217 lines
8.5 KiB
Plaintext
217 lines
8.5 KiB
Plaintext
|
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.
|