2.11.WD_DMALock()

Purpose

Enables contiguous-buffer or Scatter/Gather DMA.

For contiguous-buffer DMA, the function allocates a DMA buffer and returns mappings of the allocated buffer to physical address space and to user-mode and kernel virtual address spaces.

For Scatter/Gather DMA, the function receives the address of a data buffer allocated in the user-mode, locks it for DMA, and returns the corresponding physical mappings of the locked DMA pages. On Windows the function also returns a kernel-mode mapping of the buffer.

Prototype
DWORD WD_DMALock(
    HANDLE hWD,
    WD_DMA *pDma);
Parameters
NameTypeInput/Output
hWDHANDLEInput
pDmaWD_DMA*
hDmaDWORDOutput
pUserAddrPVOIDInput/Output
pKernelAddrKPTROutput
dwBytesDWORDInput
dwOptionsDWORDInput
dwPagesDWORDInput/Output
hCardDWORDInput
PageWD_DMA_PAGE[WD_DMA_PAGES]
*pPhysicalAddrDMA_ADDROutput
*dwBytesDWORDOutput
Description
NameDescription
hWDHandle to WinDriver's kernel-mode driver as received from WD_Open()[5.2]
pDmaPointer to a DMA information structure:
hDma DMA buffer handle, which should be passed to WD_DMAUnlock()[2.12] when unlocking the DMA buffer, or 0 if the DMA lock failed
pUserAddr Virtual user-mode mapped DMA buffer address. Input in the case of Scatter/Gather and output in the case of contiguous buffer DMA.
pKernelAddr Kernel-mode mapped DMA buffer address. Relevant only for contiguous-buffer DMA (dwOptions | DMA_KERNEL_BUFFER_ALLOC) and for Scatter/Gather DMA on Windows.
dwBytes The size of the DMA buffer, in bytes
dwOptions DMA options bit-mask, which can consist of a combination of any of the following flags:
DMA_FROM_DEVICE: Synchronize the DMA buffer for transfers from the device to memory.
DMA_TO_DEVICE: Synchronize the DMA buffer for transfers from memory to the device.
DMA_TO_FROM_DEVICE: Synchronize the DMA buffer for transfers in both directions — i.e., from the device to memory and from memory to the device (<=> DMA_FROM_DEVICE | DMA_TO_DEVICE).
DMA_KERNEL_BUFFER_ALLOC: Allocate a contiguous DMA buffer in the physical memory.
The default behavior (when this flag is not set) is to allocate a Scatter/Gather DMA buffer.
DMA_KBUF_BELOW_16M: Allocate the physical DMA buffer within the first 16MB of the main memory.
This flag is applicable only to contiguous-buffer DMA, i.e., only when the DMA_KERNEL_BUFFER_ALLOC flag is also set.
DMA_LARGE_BUFFER: Enable locking of a large DMA buffer — dwBytes > 1MB.
This flag is applicable only to Scatter/Gather DMA (i.e., when the DMA_KERNEL_BUFFER_ALLOC flag is not set).
DMA_ALLOW_CACHE: Allow caching of the DMA buffer.
DMA_KERNEL_ONLY_MAP: Do not map the allocated DMA buffer to the user mode (i.e., map it to kernel-mode only).
This flag is applicable only in cases where the DMA_KERNEL_BUFFER_ALLOC flag is applicable — see above.
DMA_ALLOW_64BIT_ADDRESS: Allow allocation of 64-bit DMA addresses. This flag is supported on Windows and and Linux.
dwPages The number of pages allocated for the DMA buffer.
For contiguous-buffer DMA this field is always set to 1.
For a large (> 1MB) Scatter/Gather DMA buffer (dwOptions | DMA_LARGE_BUFFER) this field is used both as an input and an output parameter (otherwise only output) — see remark below for details.
hCard Handle to a card for which the DMA buffer is locked, as received from WD_CardRegister()[2.6].
PageArray of DMA page structures:
*pPhysicalAddrPointer to the physical address of the beginning of the page
*dwBytesPage size, in bytes
Return Value

Returns WD_STATUS_SUCCESS (0) on success, or an appropriate error code otherwise[A].

Remarks
Example

The following code demonstrates Scatter/Gather DMA allocation:

WD_DMA dma;
DWORD dwStatus;
PVOID pBuffer = malloc(20000);

BZERO(dma);
dma.dwBytes = 20000;
dma.pUserAddr = pBuffer;
dma.dwOptions = fIsRead ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
/* Initialization of dma.hCard, value obtained from WD_CardRegister call: */
dma.hCard = cardReg.hCard;
dwStatus = WD_DMALock(hWD, &dma);
if (dwStatus)
{
    printf("Could not lock down buffer\n");
}
else
{
    /* On successful return dma.Page has the list of
       physical addresses.
       To access the memory from your user mode
       application, use dma.pUserAddr. */
}

The following code demonstrates contiguous kernel buffer DMA allocation:

WD_DMA dma;
DWORD dwStatus;

BZERO(dma);
dma.dwBytes = 20 * 4096; /* 20 pages */
dma.dwOptions = DMA_KERNEL_BUFFER_ALLOC |
    ( fIsRead ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
/* Initialization of dma.hCard, value obtained from WD_CardRegister call: */
dma.hCard = cardReg.hCard;
dwStatus = WD_DMALock(hWD, &dma);
if (dwStatus)
{
   printf("Failed allocating kernel buffer for DMA\n");
}
else
{
    /* On return dma.pUserAddr holds the user mode virtual
       mapping of the allocated memory and dma.pKernelAddr
       holds the kernel mapping of the physical memory.
       dma.Page[0].pPhysicalAddr points to the allocated
       physical address. */
}