2.13  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 7/Vista/Server 2008/Server 2003/XP/2000 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.14] 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 7/Vista/Server 2008/Server 2003/XP/2000.
• 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.
• dwOptions (continued)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, if supported by the target platform. This flag is supported on Windows% 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.8].
This field can also be set to 0 in order to lock a kernel memory buffer without association to a specific device.
• 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. */
}