Video DMA Support Design Note The video port needs to expose the following apis: 1) PUBLIC BOOLEAN VideoPortDoDma( IN PVOID HwDeviceExtension, IN PVIDEO_REQUEST_PACKET pVrp ); This function: a) allocates the MDL associated with the InputBuffer contained in the pVrp. b) maps the buffers if required by the hardware c) flushes the system buffers for cache coherency d)computes the number of map registers requested and checks that this number satisfies system requirements e) saves some parameters needed for subsequent Io calls such as the associated virtual MDL address, the number of map registers f) calls IoAllocateAdapterChannel, providiong a callback which builds the scatter gather list. Requirements: A mechanism to save the arguments to IoMapTransfer and a mechanism to indicate that a DPC is to be scheduled. The argments to IoMapTransfer are: PADAPTER_OBJECT pAO Returned from a call to HalGetAdapter and stored in the DEVICE_EXTENSION. If the actual transfer is desired, this is non NULL. If only the physical address is desired, this parameter can be NULL. PMDL pMdl Extracted from irp returned from IoBuildDeviceIoControlRequest. (also possible to get irp from IoBuildAsynchronousFsdRequest). PVOID pMapRegisterBase Allocated via ExAllocatePool from nonpaged pool of length dependent on bus type. Filled by Io subsystem via a call to HalGetBusData and held in the video ports DEVICE_EXTENSION. PVOID pCurrentVirtualAddress Constructed from LogicalAddress and MmGetMdlVirtualAddress(Irp->MdlAddress). PULONG pLength Pointer to amount to be transferred. Value saved in PUBLIC_VIDEO_REQUEST_BLOCK. BOOLEAN WriteToDevice Always set for video. 2) PVOID VideoPortGetCommonBuffer( IN PVOID HwDeviceExtension, IN PVIDEO_REQUEST_PACKET pVrp, IN ULONG Length, OUT PPHYSICAL_ADDRESS pLogicalAddress, IN BOOLEAN CacheEnabled ); This routine allows the miniport to allocate a common buffer in which to store miniport specific data. 3) PVOID VideoPortGetCommonBuffer( IN PVOID HwDeviceExtension, IN PVIDEO_REQUEST_PACKET pVrp, IN ULONG Length, OUT PPHYSICAL_ADDRESS pLogicalAddress, IN BOOLEAN CacheEnabled ); This routine allows the miniport to allocate a common buffer in which to store miniport specific data. This buffer is visible both to the system and the device and appears contiguous to the device. In support of each of these functions, the following can be added to the DEVICE_EXTENSION video port data structure: PVOID MapRegisterBase PADAPTER_OBJECT pDmaAdapterObject DMA_PARAMETERS FlushDmaParameters DMA_PARAMETERS MapTransferParameters PHW_DMA_STARTED HwDmaStarted BOOLEAN bMapBuffers where MapRegisterBase is as specified above. PADAPTER_OBJECT is defined by Io subsystem DMA_PARAMETERS, is of the form typedef struct __DMA_PARAMETERS { PPUBLIC_VIDEO_REQUEST_BLOCK pVideoRequestBlock; PIRP pIrp; ULONG DataOffset; ULONG VRBFlags; PVOID pMapRegisterBase; ULONG NumberOfMapRegisters; PVOID pLogicalAddress; ULONG Length; PVOID MdlAddress; PVRB_SG pScatterGather; VRB_SG SGList[17]; } DMA_PARAMETERS, *PDMA_PARAMETERS; which needs to be a field of the Parameters field of the IrpStack as well as a field in the interrupt data owned by the miniport and where PPUBLIC_VIDEO_REQUEST_BLOCK may be defined by typedef struct __PUBLIC_VIDEO_REQUEST_BLOCK { // Private stuff. PIRP pIrp; ULONG VRBFlags; ULONG Qindex; // Public stuff. VIDEO_REQUEST_PACKET vrp; BOOLEAN bUnlock; } PUBLIC_VIDEO_REQUEST_BLOCK, *PPUBLIC_VIDEO_REQUEST_BLOCK; with VRB_SG defined by typedef struct __VRB_SG { int64 PhysicalAddress; ULONG Length; } VRB_SG, *PVRB_SG; Useful flags for VRBFlags in DMA_PARAMETERS: DMA_FLUSH_ADAPTER MAP_DMA_TRANSFER FREE_SG NOTIFY_REQUIRED. Also in PORT_CONFIG_INFO, the following are required: ULONG DmaChannel ULONG DmaPort DMA_WIDTH DmaWidth DMA_SPEED DmaSpeed BOOLEAN DMA32bitAddresses BOOLEAN DMADemandMode One of the dependencies that supporting DMA transfers has in NT is calling IoAllocateAdapterChannel. This routine is of the form: NTSTATUS IoAllocateAdapterChannel( PADAPTER_OBJECT pAO, PDEVICE_OBJECT pDO, ULONG NumberOfRegisters, PDRIVER_CONTROL pBuildScatterGather, PVOID pContext ); where pAO is returned by HalGetAdapter, pDO is returned by IoCreateDevice NumberOfRegisters comes from a calculation involving the DataBuffer to be transferred and it's length. pBuildScatterGather builds the scatter/gather list and is a callback from the Io subsystem. pContext is the context pointer passed into pBuildScatterGather by Io subsystem (PDMA_PARAMETERS). If the miniport has indicated that DMA support is desired, then the following sequence of system calls are made: MmGetMdlVirtualAddress (to save IoMapTransfer params) MmGetSystemAddressForMdl (if MapBuffers set) KeFlushIoBuffers IoAllocateAdapterChannel (request a DPC if this fails) KeSynchronizeExecution IoMapTransfer (note PADAPTER_OBJECT) IoFlushAdapterBuffers IoFreeMapRegisters The Io subsystem calls back to a routine to build scatter gather lists of the form: IO_PRIVATE IO_ALLOCATION_ACTION pVideoPortBuildScatterGather( PDEVICE_OBJECT pDO, PIRP pIrp, PVOID pMapRegisterBase, PVOID pDmaParameters ); As mentioned, it builds and saves the scatter gather lists, and calls KeSynchronizeExecution, passing in pVideoPortStartDmaSynchronized as the synchronizing function. pVideoPortStartDmaSynchronized in turn calls HwStartDma, which is not to return until the device has finished draining the current request data. IOCTL interface IOCTL_VIDEO_DMA_INIT - set by DispDrvr Causes VideoPortGetCommonBuffer() to be called by miniport. IOCTL_VIDEO_DMA_TRANSFER - set by DispDrvr Causes VideoPortDoDma() to be called by miniport. VideoPortGetScatterGatherList is called from miniport. IOCTL_VIDEO_DMA_UNLOCK_PAGES - set by DispDrvr Causes pVideoPortUnlock to be called from videoport. Note that this IOCTL is private to the videoport.