阅读:1850回复:10
如何的到slave dma
如题,奇怪,pnp根本就没给出CmResourceTypeDma资源啊,如何才能得到slave dma 控制器呢?
请高人们指点,谢谢! |
|
|
沙发#
发布于:2005-06-09 12:26
我也在捉摸
|
|
板凳#
发布于:2005-06-10 11:28
猜测:主机dma是由桥芯片提供的吗?还是cpu?
现在的主板是不是由于板卡及设备功能的强大(一般都自带dma个功能)而不支持主机dma了??? |
|
|
地板#
发布于:2005-06-10 15:55
看到一篇文章:在有isa的主板,即bx主板才用到8237的dma,也就是slave dma,在pci的时代就不用slave dma了,全用master dma了!??
是吗?待确认!!! |
|
|
地下室#
发布于:2005-06-12 18:55
看到一篇文章:在有isa的主板,即bx主板才用到8237的dma,也就是slave dma,在pci的时代就不用slave dma了,全用master dma了!?? slave dma得你自己去向OS申请dma channle pci的好像就是不用slave dma了,全是master |
|
5楼#
发布于:2005-06-13 19:44
谢谢,但是怎么去向os申请呢?
我在响应IRP_MN_START_DEVICE时调用 NTSTATUS GetDmaInfo( IN PDEVICE_OBJECT fdo ) { PDMAS_DEVICE_EXTENSION pDevExt = (PDMAS_DEVICE_EXTENSION)fdo->DeviceExtension; DEVICE_DESCRIPTION dd; // Zero out the entire structure RtlZeroMemory( &dd, sizeof(dd) ); dd.Version = DEVICE_DESCRIPTION_VERSION1; dd.Master = FALSE; dd.ScatterGather = FALSE; dd.DemandMode = FALSE; dd.AutoInitialize = FALSE; dd.Dma32BitAddresses = TRUE; dd.InterfaceType = PCIBus;//Internal; dd.DmaChannel = 0; dd.MaximumLength = MAX_DMA_LENGTH; dd.DmaWidth = Width8Bits; dd.DmaSpeed = Compatible; pDevExt->mapRegisterCount =(MAX_DMA_LENGTH / PAGE_SIZE) + 1; pDevExt->pDmaAdapter =IoGetDmaAdapter( fdo, &dd, &pDevExt->mapRegisterCount); if (pDevExt->pDmaAdapter == NULL) DbgPrint(\"The dma adapter is null!\\n\"); else return STATUS_SUCCESS; } 在我调用IoGetDmaAdapter时系统就崩掉了,我用softice看了,根本就返回了,直接咔嚓了 :o 是我哪个参数没设对? :( |
|
|
6楼#
发布于:2005-06-15 13:34
你的是PCI设备?
pci不能用slave dma |
|
7楼#
发布于:2005-06-15 16:01
我的是pci设备!请问有什么官方文件说明pci设备就不能使用slave dma了吗。
我现在不和设备直接挂接,做了一个虚拟设备的驱动,那不就无所谓是不是pci设备了吗,也不行啊!? |
|
|
8楼#
发布于:2005-06-17 10:18
哈哈,我得到dmaadapter了!
关键是在fdo错了! 好,现在开始传传数据看!不知道为什么得到的MapRegisterCount这么小,我想要385,而得到的就只有8?那我传一次需要分多少次啊!!! 还有,slave dma传完后中断怎么产生了,纳闷? |
|
|
9楼#
发布于:2005-07-05 09:25
中断难道一定要由isa设备产生吗?
|
|
|
10楼#
发布于:2005-07-07 14:43
---------------------------------------------------------------------
The information in this article applies to: - Microsoft Win32 Device Development Kit (DDK) for Windows NT, versions 3.1, 3.5, 3.51, 4.0 --------------------------------------------------------------------- SUMMARY ======= The Slavedma.exe file contains code that demonstrates how to handle slave Direct Memory Access (DMA) in a Windows NT Driver. /*++ Copyright (c) 1989 Microsoft Corporation Module Name: slavedma.txt Abstract: This file contains a driver skeleton that demonstrates how to handle slave DMA. This is probably the type of DMA most commonly dealt with. Author: Keith Jin, March 15, 1994 Environment: Kernel mode Revision History: --*/ #include <ntddk.h> #define IRQ_NUMBER 5 #define DMA_CHANNEL 2 typedef struct _XYZ_DEVICE_EXTENSION { PADAPTER_OBJECT AdapterObject ; PKINTERRUPT InterruptObject ; ULONG MaximumMapRegisters ; PVOID MapRegisterBase ; PVOID CurrentVirtualAddress ; ULONG CurrentTransferLength ; ULONG BytesTransfered ; BOOLEAN WriteToDevice ; } XYZ_EXTENSION, * PXYZ_EXTENSION ; typedef struct _CONFIG_DATA { INTERFACE_TYPE InterfaceType ; ULONG BusNumber ; ULONG BusInterruptLevel ; ULONG BusInterruptVector ; KINTERRUPT_MODE InterruptMode; ULONG DmaChannel ; DMA_SPEED DmaSpeed ; DMA_WIDTH DmaWidth ; ULONG MaximumTransferLength ; } CONFIG_DATA, *PCONFIG_DATA ; NTSTATUS XyzOpenClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS XyzReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); VOID XyzStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); IO_ALLOCATION_ACTION XyzAdapterControl ( IN PDEVICE_OBJECT DeviceObejct, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context ) ; BOOLEAN XyzInterruptRoutine( IN PKINTERRUPT InterruptObject, IN PVOID ServiceContext ) ; VOID XyzDpcRoutine ( IN PKDPC Dpc , IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp , IN PVOID Context ) ; VOID XyzUnload( IN PDRIVER_OBJECT DriverObject ); NTSTATUS XyzFindAndReportResources( IN PDRIVER_OBJECT DriverObject, OUT PCONFIG_DATA ConfigData, OUT BOOLEAN * Conflict ); NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { PDEVICE_OBJECT deviceObject = NULL; NTSTATUS status; UNICODE_STRING uniDeviceName; PXYZ_EXTENSION deviceExtension ; DEVICE_DESCRIPTION deviceDescription ; BOOLEAN resourceConflict = FALSE ; PCONFIG_DATA configData ; KAFFINITY processorAffinity ; ULONG systemInterruptVector ; KIRQL interruptIrql ; // // Get the config information and report resource usage. // If resource conflict was detected, fail the driver loading. // configData = ExAllocatePool (NonPagedPool, sizeof (CONFIG_DATA)) ; if (!configData) { return STATUS_INSUFFICIENT_RESOURCES ; } status = XyzFindAndReportResources (DriverObject, configData, &resourceConflict) ; if (!NT_SUCCESS(status) || resourceConflict) { if (resourceConflict) { status = STATUS_DEVICE_CONFIGURATION_ERROR ; } KdPrint (("Xyz: Report resource problem. Status: %X.\n", status)) ; goto DriverEntryExit ; } // // Create a device object. // RtlInitUnicodeString( &uniDeviceName, L"\\Device\\XyzDevice"); status = IoCreateDevice( DriverObject, sizeof (XYZ_EXTENSION), &uniDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject ); if (!NT_SUCCESS(status)) { KdPrint(("Xyz: Failed creating device object! Status: %X\n", status)); goto DriverEntryExit ; } deviceObject->Flags |= DO_DIRECT_IO ; deviceExtension = deviceObject->DeviceExtension ; // // // Get the adapter object. // deviceDescription.Version = 0 ; deviceDescription.Master = FALSE ; // Slave DMA, not a bus master. deviceDescription.ScatterGather = FALSE ; // no scatter/gather for slave deviceDescription.DemandMode = FALSE ; deviceDescription.AutoInitialize = FALSE ; // We don't use autoinitialize deviceDescription.Dma32BitAddresses = FALSE ; deviceDescription.BusNumber = configData->BusNumber ; deviceDescription.DmaChannel = configData->DmaChannel ; deviceDescription.InterfaceType = configData->InterfaceType ; deviceDescription.DmaWidth = configData->DmaWidth ; deviceDescription.DmaSpeed = configData->DmaSpeed ; deviceDescription.MaximumLength = configData->MaximumTransferLength ; deviceDescription.DmaPort = 0 ; // For MCA only deviceExtension->AdapterObject = HalGetAdapter (&deviceDescription, &deviceExtension->MaximumMapRegisters) ; // // If HalGetAdapter fails, it is mostly likely that one of the parameters // supplied in the DEVICE_DESCRIPTION structure is not valid. For example, // using DMA channel 4 is not valid. It can also fail because of insufficient // resource, but not very likely. // if (deviceExtension->AdapterObject == NULL) { KdPrint (("Xyz: HalGetAdapter failed.\n")) ; status = STATUS_DEVICE_CONFIGURATION_ERROR ; goto DriverEntryExit ; } // // If there are I/O ports or device memory to handle, Call // HalTranslateBusAddress and MmMapIoSpace. See other sample drivers in // the DDK for examples. PORTIO is one of them. // /* <Code to be implemented by vendor.> */ // // Usually a device would use an interrupt to notify the driver that a // transfer is comleted. We will connect interrupt. // systemInterruptVector = HalGetInterruptVector ( configData->InterfaceType, configData->BusNumber, configData->BusInterruptLevel, configData->BusInterruptVector, &interruptIrql, &processorAffinity) ; if (systemInterruptVector == 0) { KdPrint (("Xyz: HalGetInterruptVector failed.\n")) ; status = STATUS_DEVICE_CONFIGURATION_ERROR ; goto DriverEntryExit ; } status = IoConnectInterrupt ( &deviceExtension->InterruptObject, XyzInterruptRoutine, // interrupt routine deviceObject, // interrupt context NULL, // no spinlock systemInterruptVector, interruptIrql, interruptIrql, configData->InterruptMode, FALSE, // not sharable processorAffinity, FALSE) ; // no need to save FP status if (!NT_SUCCESS(status)) { KdPrint (("Xyz: Can not connect interrupt.\n")) ; goto DriverEntryExit ; } // // Initialize an DPC for the device object, so that we can queue the DPC // from the interrupt service routine. // IoInitializeDpcRequest (deviceObject, XyzDpcRoutine) ; // // Setup dispatch points for create/open, close, read, write and unload. // DriverObject->MajorFunction[IRP_MJ_CREATE] = XyzOpenClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = XyzOpenClose; DriverObject->MajorFunction[IRP_MJ_READ] = XyzReadWrite; DriverObject->MajorFunction[IRP_MJ_WRITE] = XyzReadWrite; DriverObject->DriverStartIo = XyzStartIo; DriverObject->DriverUnload = XyzUnload; // // Setup a symbolic link if necessary // /* < Code to be implemented by vendor> */ DriverEntryExit: // // Free the allocated buffer for config data. // if (configData) { ExFreePool (configData) ; } // // If an error has occurred, un-report the resource // usage and delete the device object if necessary. // if (!NT_SUCCESS (status)) { if (!resourceConflict) { // // If resource usage has been reported, un-report the resource using // IoReporteResourceUsage. See the Unload routine for example. // /* <Code to be implemented by vendor.> */ } if (deviceObject) { IoDeleteDevice (deviceObject) ; } } return status ; } NTSTATUS XyzFindAndReportResources ( IN PDRIVER_OBJECT DriverObject, IN PCONFIG_DATA ConfigData, OUT BOOLEAN * Conflict ) /*++ Routine Description: This routine finds the configuration info and reports the resource usage to the system. Resources includes DMA channel, IO ports and interrupt (IRQ). Configuration information can be obtained by detecting the card, or retrieve from the registry. Arguments: Return Value: Returns what IoReportResourceUsage returns. Conflict = TRUE if conflict is detected. Otherwise, it is set to FALSE ; --*/ { // // Hardware detecting can be implemented here. Or the configuration can // come from the registry. There are sample drivers in the DDK that show // how to get information from registry. PORTIO, for example, is one of // of them. // // Here, for the sake of the simplicity of the sample, we will just // fill in the CONFIG_DATA structure with default values. This is not // the best choice for dealing with a real device. // ConfigData->InterfaceType = Isa ; ConfigData->BusNumber = 0 ; ConfigData->BusInterruptLevel = IRQ_NUMBER ; ConfigData->BusInterruptVector = IRQ_NUMBER ; ConfigData->InterruptMode = Latched ; ConfigData->DmaChannel = DMA_CHANNEL ; ConfigData->DmaSpeed = Compatible ; ConfigData->DmaWidth = Width8Bits ; ConfigData->MaximumTransferLength = 0x10000 ; // // Report resource usage: IO ports, DMA channel, interrupt, memory. Use // IoReportResourceUsage(). // /* <Code to be implemented by vendor> */ // // The true result should come from IoReportResourceUsage(). We set it to // FALSE for now. // *Conflict = FALSE ; return STATUS_SUCCESS ; } NTSTATUS XyzOpenClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { // // There is not much we need to do here. Just complet the request. // Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS XyzReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the dispatch routine for read or write requests. We just start the packet. Arguments: Return Value: return STATUS_PENDING --*/ { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp) ; // // If the request has a buffer of length 0, we will complete it right here. // if (irpSp->Parameters.Read.Length == 0) { Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH ; Irp->IoStatus.Information = 0 ; IoCompleteRequest (Irp, IO_NO_INCREMENT) ; return STATUS_INFO_LENGTH_MISMATCH ; } // // This is a valid request, mark the Irp pending and start the packet. // IoMarkIrpPending (Irp) ; IoStartPacket (DeviceObject, Irp, NULL, NULL) ; return STATUS_PENDING ; } VOID XyzStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the starting point of a new transfer. Arguments: Return Value: return STATUS_PENDING --*/ { PXYZ_EXTENSION deviceExtension = DeviceObject->DeviceExtension ; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp) ; ULONG numberOfMapRegisters ; PMDL mdlAddress = Irp->MdlAddress ; NTSTATUS status ; // // Calculate the number of map registers needed for this transfer. // Use ADDRESS_AND_SIZE_TO_SPAN_PAGES, since we need to consider // partial pages (which can exist at the beginning and end of the // linear region). A partial page will use one map register. // deviceExtension->CurrentVirtualAddress = MmGetMdlVirtualAddress (mdlAddress) ; deviceExtension->CurrentTransferLength = MmGetMdlByteCount (mdlAddress) ; deviceExtension->BytesTransfered = 0 ; numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES ( deviceExtension->CurrentVirtualAddress, deviceExtension->CurrentTransferLength) ; // // If the number of map registers needed for the buffer is greater than // the maximum number of map registers we can use, we will do a partial // transfer. The length of the partial transfer is calculated. Again, // put into consideration the partial page at the beginning. // if (numberOfMapRegisters > deviceExtension->MaximumMapRegisters) { numberOfMapRegisters = deviceExtension->MaximumMapRegisters ; deviceExtension->CurrentTransferLength = numberOfMapRegisters * PAGE_SIZE - mdlAddress->ByteOffset ; } deviceExtension->WriteToDevice = (irpSp->MajorFunction == IRP_MJ_WRITE) ; // // IoAllocateAdapterChannel needs to be called at DISPATCH_LEVEL. Since // StartIo is called at DISPATCH_LEVEL, we don't need to raise the Irql. // This call would be needed if we were at a different place. // // KeRaiseIrql (DISPATCH_LEVEL, &OldIrql) ; // status = IoAllocateAdapterChannel (deviceExtension->AdapterObject, DeviceObject, numberOfMapRegisters, XyzAdapterControl, NULL) ; // // This call should not fail. If it does, it means we are requesting too many // map registers than we should. // ASSERT (NT_SUCCESS(status)) ; // // If KeRaiseIrql is called previously, we need to lower the Irql. // // KeLowerIrql (OldIrql) ; // } IO_ALLOCATION_ACTION XyzAdapterControl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context ) /*++ Routine Description: The adapter channel control routine is called when the adapter object is given to our device and enough map registers are available for us to do the transfer. This routine is responsible for calling IoMapTransfer and notify the device to start the DMA transfer. Note: The Irp pointer passed to this routine comes from the CurrentIrp field of the device object. Because the CurrentIrp field only gets set when the StartIo routine is called, it is only meaningful to use this passed Irp pointer if IoAllocateAdapterChannel is called from the StartIo routine. A driver does not implement StartIo will find this Irp pointer to be NULL. In that case, the Mdl address must be passed in some other way. Arguments: Return Value: return KeepObject. --*/ { PXYZ_EXTENSION deviceExtension = DeviceObject->DeviceExtension ; PMDL mdlAddress ; mdlAddress = Irp->MdlAddress ; deviceExtension->MapRegisterBase = MapRegisterBase ; KeFlushIoBuffers (mdlAddress, !deviceExtension->WriteToDevice, TRUE) ; IoMapTransfer (deviceExtension->AdapterObject, mdlAddress, MapRegisterBase, deviceExtension->CurrentVirtualAddress, &deviceExtension->CurrentTransferLength, deviceExtension->WriteToDevice) ; // // By now, the DMA controller on the system is programmed and the DMA // channel is unmasked. We are ready to go, the driver usually needs to // tell the device that a transfer should be started. // /* <Code to be implemented by vendor> */ // // Three values can be returned from the adapter control routine. // // DeallocateObject -- The adapter object is freed. // // DeallocateObjectKeepRegsters -- keep map registers // // KeepObject -- Keep the adapter object and the map registers. // // Since we need the adapter object as well as the map registers until we // are done transferiing, we will return KeepObject. // return KeepObject ; } BOOLEAN XyzInterruptRoutine( IN PKINTERRUPT InterruptObject, IN PVOID ServiceContext ) /* -- Routine Description: Service the interrupt. Queue the DPC. We should be in this routine as short as possible. Return: return TRUE. This means we handled the interrupt. -- */ { PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) ServiceContext ; // // Service the interrupt. The driver should do whatever necessary to the device // for servicing the interrupt. This is device specific. // /* <Code to be implemented by vendor.> */ // // Queue DPC for further processing the interrupt if necessary. // IoRequestDpc (deviceObject, deviceObject->CurrentIrp, NULL) ; // // Return TRUE if this interrupt was handled. If this is an unexpected // interrupt, return FALSE to tell kernel that we didn't handle it. // return TRUE ; } VOID XyzDpcRoutine ( IN PKDPC Dpc, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /* -- Routine Description: The DPC routine does the most of the job of servicing an interrupt. If the transfer is partial, further transfer will be programmed. If the transfer is completed, the routine will release the adapter object and map registers, complete the Irp and start the next packet. -- */ { PXYZ_EXTENSION deviceExtension = DeviceObject->DeviceExtension ; PMDL mdlAddress = Irp->MdlAddress ; ULONG numberOfMapRegisters ; // // Check the device to see if the transfer was successful. // If not successful, process accordingly. Depending on the error, // the driver can retry the operation, or complete the current // request with a unsuccessful status. If the packet is completed // here because of an error, remember to start the next packet. // /* <Code to be implemented by vendor.> */ // // If the transfer was successful, the following needs to be done. // // // Call IoFlushAdapterBuffers. This will mask off the DMA channel (on x86 // platforms at least) and, if necessary, copy data from the map buffer // to the original buffer. // IoFlushAdapterBuffers (deviceExtension->AdapterObject, mdlAddress, deviceExtension->MapRegisterBase, deviceExtension->CurrentVirtualAddress, deviceExtension->CurrentTransferLength, deviceExtension->WriteToDevice) ; deviceExtension->BytesTransfered += deviceExtension->CurrentTransferLength ; if (deviceExtension->BytesTransfered < mdlAddress->ByteCount) { // // That was a partial transfer. More transfer(s) need to be programmed. // (PCHAR)deviceExtension->CurrentVirtualAddress += deviceExtension->CurrentTransferLength ; deviceExtension->CurrentTransferLength = mdlAddress->ByteCount - deviceExtension->BytesTransfered ; numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES ( deviceExtension->CurrentVirtualAddress, deviceExtension->CurrentTransferLength) ; if (numberOfMapRegisters > deviceExtension->MaximumMapRegisters) { numberOfMapRegisters = deviceExtension->MaximumMapRegisters ; deviceExtension->CurrentTransferLength = numberOfMapRegisters * PAGE_SIZE - BYTE_OFFSET (deviceExtension->CurrentVirtualAddress) ; } IoMapTransfer (deviceExtension->AdapterObject, mdlAddress, deviceExtension->MapRegisterBase, deviceExtension->CurrentVirtualAddress, &deviceExtension->CurrentTransferLength, deviceExtension->WriteToDevice) ; } else { // // The transfer has completed the whole packet. We will release the // the adapter channel, complet the current packet and start the next // packet. // IoFreeAdapterChannel (deviceExtension->AdapterObject) ; Irp->IoStatus.Status = STATUS_SUCCESS ; Irp->IoStatus.Information = deviceExtension->BytesTransfered ; // // Choose an appropriate priority increment. We use the one for // disk drivers. See NTDDK.H for other values. // IoCompleteRequest (Irp, IO_DISK_INCREMENT) ; IoStartNextPacket (DeviceObject, TRUE) ; } } VOID XyzUnload( IN PDRIVER_OBJECT DriverObject ) /* -- Description: The driver is being unloaded from the system. This routine should: . un-report resource usage. . unmap io address space in any mapped during init. . disconnect interrupt. . free any alocated memory and resource. . delete the device object(s). . delete symbolic link if one created during init. -- */ { PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject ; PXYZ_EXTENSION deviceExtension = deviceObject->DeviceExtension ; CM_RESOURCE_LIST nullResourceList; BOOLEAN resourceConflict; PDEVICE_OBJECT nextDevice ; // // Tell the system that we don't use the resources we claimed // any more. // RtlZeroMemory((PVOID)&nullResourceList, sizeof(nullResourceList)); IoReportResourceUsage( NULL, DriverObject, &nullResourceList, sizeof(ULONG), NULL, NULL, 0, FALSE, &resourceConflict ); // // Disconnect interrupt. // IoDisconnectInterrupt (deviceExtension->InterruptObject) ; // // Unmap Io space, if any mapped during initialization. // /* <Code to be implemented by vendor.> */ // // Delete the device object(s) that we created. // while (deviceObject) { nextDevice = deviceObject->NextDevice ; IoDeleteDevice (deviceObject) ; deviceObject = nextDevice ; } // // Delete symbolic link if any created during init. // /* <Code to be implemented by vendor.> */ } |
|
|