Working with Adapter Objects

< BACK  NEXT >
[oR]

Although the specific details vary with the nature of the device and the architecture of the driver, DMA drivers generally have to perform several kinds of operations on Adapter objects.

  • Locate the Adapter object associated with the specific device.

  • Acquire and release ownership of Adapter objects and their mapping registers.

  • Load the Adapter object's mapping registers at the start of a transfer.

  • Flush the Adapter object's cache after a transfer completes.

The following sections discuss these topics in general terms. Later sections of this chapter add more detail.

Finding the Right Adapter Object

All DMA drivers need to locate an Adapter object before they can perform any I/O operations. To find the right one, a driver's initialization code needs to call the IoGetDmaAdapter function described in Table 12.2.

Given a description of some DMA hardware, IoGetDmaAdapter returns a pointer to a structure of function pointers that manipulate the corresponding Adapter object. It also reports a count of the maximum number of mapping registers available for a single transfer. The driver needs to save both these items in nonpaged storage (usually the Device or Controller Extension) for later use.

Table 12.2. Function Prototype for IoGetDmaAdapter
PDMA_ADAPTER IoGetDmaAdapter IRQL == PASSIVE_LEVEL
Parameter Description
IN PDEVICE_OBJECT pdo Points to the physical device object for the device
IN PDEVICE_DESCRIPTION pDeviceDescription Points to a DEVICE_DESCRIPTION structure
IN OUT PULONG Input: number of map registers requested.
NumberOfMapRegisters Output: maximum number of map registers that the driver can allocate for any DMA transfer operation.
Return value Pointer to DMA_ADAPTER

By returning a structure of function pointers, the Adapter object is truly an encapsulated object it can only be manipulated through its interface.

The main input to IoGetDmaAdapter is the DEVICE_DESCRIPTION block listed in Table 12.3. Unused entries of this input structure must be zero. Some fields of this structure deserve comment.

ScatterGather.

For bus master devices, this field signifies that the hardware supports transfer of data to and from noncontiguous ranges of physical memory. For slave devices, this field indicates that the device can be paused between page transfers, allowing the I/O Manager to repoint the DMA channel's address register to a new page of physical memory.

DemandMode.

DMA demand mode is a transfer protocol that allows a device to hold off the (slave) DMA controller. In normal mode (DemandMode==FALSE), the DMA controller does not allow the device to delay its request to transfer another block of data.

Autoinitialization.

DMA autoinitialization mode allows system DMA channels to restart themselves after a completed transfer. Specified address and count values are automatically reset into the DMA hardware and another operation is "good to go."

IgnoreCount.

Some DMA hardware maintains an improper count of bytes transferred. This can occur because the hardware counts words instead of bytes. If this field is set to TRUE, the HAL manually maintains the transfer count on behalf of the device.

Table 12.3. The DEVICE_DESCRIPTION Structure for IoGetDmaAdapter
DEVICE_DESCRIPTION, *PDEVICE_DESCRIPTION
Field Contents
ULONG Version DEVICE_DESCRIPTION_VERSION
DEVICE_DESCRIPTION_VERSION1
BOOLEAN Master TRUE - Bus master device
FALSE - Slave device
BOOLEAN ScatterGather TRUE - Device supports scatter/gather
BOOLEAN DemandMode Slave device uses demand mode
BOOLEAN AutoInitialize Slave device uses autoinitialize mode
BOOLEAN Dma32BitAddresses DMA addressing uses 32 bits
BOOLEAN IgnoreCount TRUE - Device's transfer count not maintained accurately
BOOLEAN Reserved1 Must be FALSE
BOOLEAN Dma64BitAddresses DMA addressing uses 64 bits
ULONG BusNumber System-assigned bus number (unused by WDM drivers)
ULONG DmaChannel Slave device DMA channel number
INTERFACE_TYPE InterfaceType Internal
Isa
Eisa
MicroChannel
PCIBus
DMA_WIDTH DmaWidth Width8Bits
Width16Bits
Width32Bits
DMA_SPEED DmaSpeed Compatible
TypeA
TypeB
TypeC
ULONG MaximumLength Largest transfer size (in bytes) device can perform
ULONG DmaPort Microchannel-type bus port number (obsolete)

Acquiring and Releasing the Adapter Object

There is no guarantee that the DMA resources needed for a device transfer will be free when a driver's Start I/O routine runs. For example, a slave device DMA channel may already be in use by another device, or there may not be enough mapping registers to handle the request. Consequently, all packet-based DMA drivers and drivers for common buffer slave devices have to request ownership of the Adapter object before starting a data transfer.

Since the Start I/O routine runs at DISPATCH_LEVEL IRQL, there is no way it can stop and wait for the Adapter object. Instead, it calls the Allocate-AdapterChannel method of the Adapter object (see Table 12.4) and then returns control to the I/O Manager.

When the requested DMA resources become available, the I/O Manager notifies the driver by calling its Adapter Control routine. It's important to keep in mind that this is an asynchronous callback. It may happen as soon as Start I/O calls AllocateAdapterChannel, or it may not occur until some other driver releases the Adapter resources.

Notice that the caller of AllocateAdapterChannel must be at DISPATCH_LEVEL IRQL. Since the function is normally called from the Start I/O routine, this poses no problem. However, if it is called from another driver routine from PASSIVE_LEVEL, make sure to use KeRaiseIrql and KeLower-Irql before and after the call to AllocateAdapterChannel.

Table 12.4. Function Prototype for AllocateAdapterChannel
NTSTATUS AllocateAdapterChannel IRQL == DISPATCH_LEVEL
Parameter Description
IN PDMA_ADAPTER pDmaAdapter Points to the DMA_ADAPTER structure returned by IoGetDmaAdapter
IN PDEVICE_OBJECT pDeviceObject Points to the target DMA device object
IN ULONG NumberOfMapRegisters Specifies the number of map registers to be used in the transfer
IN PDRIVER_CONTROL ExecutionRoutine Points to a driver-supplied AdapterControl routine to be called as soon the system DMA controller or bus master adapter is available
IN PVOID pContext Points to the driver-determined context to be passed to the AdapterControl routine
Return value STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES

The Adapter Control routine in a DMA driver is responsible for calling MapTransfer to set up the DMA hardware and starting the actual device operation. Table 12.5 contains a prototype of the Adapter Control callback.

Table 12.5. Function Prototype for an Adapter Control Routine
IO_ALLOCATION_ACTION AdapterControl IRQL == DISPATCH_LEVEL
Parameter Description
IN_PDEVICE_OBJECT pDeviceObject Target device for DMA operation
IN PIRP pIrp IRP describing this operation
IN PVOID MapRegisterBase Handle to a group of mapping registers
IN PVOID pContext Driver-determined context
Return value
  • l DeallocateObjectKeepRegisters

  • l KeepObject

The MapRegisterBase argument is an opaque value that identifies the mapping registers assigned to the I/O request. It is really a kind of handle to a specific group of registers. This handle is used to set up the DMA hardware for the transfer. Normally, this handle value is saved in the Device or Controller extension because it is needed in later parts of the DMA operation.

The pIrp argument passed to the Adapter Control callback is valid only when AllocateAdapterChannel is called from the Start I/O routine. If it is called from some other context, the pIrp pointer will be NULL. In such a case, another mechanism must be used to pass the IRP (and its associated MDL address) to the Adapter Control routine. The context pointer argument can possibly be used for this purpose.

After it programs the DMA controller and starts the data transfer, the Adapter Control routine gives control back to the I/O Manager. Drivers of slave devices should return a value of KeepObject from this function so that the Adapter object remains the exclusive property of this request. Bus master drivers return DeallocateObjectKeepRegisters.

When the DpcForIsr routine in a DMA driver completes an I/O request, it needs to release any Adapter resources it owns. Drivers of DMA devices do this by calling FreeAdapterChannel.

Setting Up the DMA Hardware

All packet-based drivers, as well as common buffer drivers for slave devices, have to program the DMA hardware at the beginning of each data transfer. Using the abstract DMA model of Windows 2000, this means loading the Adapter object's mapping registers with physical page addresses taken from the MDL. This setup work is done by the MapTransfer method of the Adapter object, described in Table 12.6.

MapTransfer uses the CurrentVa and Length arguments to figure out what physical page addresses to put into the mapping registers. These values must fall somewhere within the range of addresses described by the MDL.

Keep in mind that MapTransfer may actually move the contents of the DMA output buffer from one place to another in memory. For example, on an ISA machine, if the pages in the MDL are outside the 16-megabyte DMA limit, calling this function results in data being copied to a buffer in low physical memory. Similarly, if the DMA input buffer is out of range, MapTransfer allocates a buffer in low memory for the transfer. On buses that support 32-bit DMA addresses, no copying or duplicate buffers are required.

Drivers of bus master devices also need to call MapTransfer. In this case, however, the function behaves differently, since it doesn't know how to program the bus master's control registers. Instead, MapTransfer simply returns address and length values that the driver again loads into the device's registers. For bus masters with built-in scatter/gather support, this same mechanism allows the driver to create a scatter/gather list for the device. Later sections of this chapter explain how this works.

Flushing the Adapter Object Cache

At the end of a data transfer, all packet-based DMA drivers and drivers for common buffer slave devices have to call FlushAdapterBuffers, a method of the Adapter object (see Table 12.7). For devices using the system DMA controller, this function flushes any hardware caches associated with the Adapter object.

Table 12.6. Function Prototype for MapTransfer
PHYSICAL_ADDRESS MapTransfer IRQL <= DISPATCH_LEVEL
Parameter Description
IN PDMA_ADAPTER pDmaAdapter Points to the DMA adapter object returned by IoGetDmaAdapter
IN PMDL pMdl Memory Descriptor List for DMA buffer
IN PVOID MapRegisterBase Handle to a group of mapping registers
IN PVOID CurrentVA Virtual address of buffer within the MDL
IN OUT PULONG Length IN - count of bytes to be mapped
OUT - actual count of bytes mapped
IN BOOLEAN bWriteToDevice TRUE - send data to device
FALSE - read data from device
Return value DMA logical address of the mapped region

Table 12.7. Function Prototype for FlushAdapterBuffers
BOOLEAN FlushAdapterBuffers IRQL <= DISPATCH_LEVEL
Parameter Description
IN PDMA_ADAPTER pDmaAdapter Points to the DMA adapter object returned by IoGetDmaAdapter
IN PMDL pMdl MDL describing the buffer
IN PVOID MapRegisterBase Handle passed to AdapterControl
IN PVOID CurrentVA Starting virtual address of buffer
IN ULONG Length Length of the buffer
IN BOOLEAN WriteToDevice TRUE - operation was an output
FALSE - operation was an input
Return value TRUE - Adapter buffers flushed
FALSE - an error occurred

In the case of ISA devices doing packet-based DMA, this call releases any low memory used for auxiliary buffers. For input operations, it also copies data back to the physical pages of the caller's input buffer. Refer back to the section on cache coherency for a discussion of this process.

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net