📄 dma.c
字号:
return STATUS_SUCCESS;
}
/**
* @name IoFreeAdapterChannel
*
* Free DMA resources allocated by IoAllocateAdapterChannel.
*
* @param AdapterObject
* Adapter object with resources to free.
*
* @remarks
* This function releases map registers registers assigned to the DMA
* adapter. After releasing the adapter, it checks the adapter's queue
* and runs each queued device object in series until the queue is
* empty. This is the only way the device queue is emptied.
*
* @see IoAllocateAdapterChannel
*
* @implemented
*/
VOID STDCALL
IoFreeAdapterChannel(
PADAPTER_OBJECT AdapterObject)
{
PADAPTER_OBJECT MasterAdapter;
PKDEVICE_QUEUE_ENTRY DeviceQueueEntry;
PWAIT_CONTEXT_BLOCK WaitContextBlock;
ULONG Index = ~0;
ULONG Result;
KIRQL OldIrql;
MasterAdapter = AdapterObject->MasterAdapter;
for (;;)
{
/*
* To keep map registers, call here with AdapterObject->
* NumberOfMapRegisters set to zero. This trick is used in
* HalAllocateAdapterChannel for example.
*/
if (AdapterObject->NumberOfMapRegisters)
{
IoFreeMapRegisters(
AdapterObject,
AdapterObject->MapRegisterBase,
AdapterObject->NumberOfMapRegisters);
}
DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue);
if (DeviceQueueEntry == NULL)
{
break;
}
WaitContextBlock = CONTAINING_RECORD(
DeviceQueueEntry,
WAIT_CONTEXT_BLOCK,
WaitQueueEntry);
AdapterObject->CurrentWcb = WaitContextBlock;
AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters;
if (WaitContextBlock->NumberOfMapRegisters &&
AdapterObject->MasterAdapter)
{
OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
if (IsListEmpty(&MasterAdapter->AdapterQueue))
{
Index = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
WaitContextBlock->NumberOfMapRegisters, 0);
if (Index != ~0)
{
AdapterObject->MapRegisterBase =
MasterAdapter->MapRegisterBase + Index;
if (!AdapterObject->ScatterGather)
{
AdapterObject->MapRegisterBase =
(PROS_MAP_REGISTER_ENTRY)(
(ULONG_PTR)AdapterObject->MapRegisterBase |
MAP_BASE_SW_SG);
}
}
}
if (Index == ~0)
{
InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
break;
}
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
}
else
{
AdapterObject->MapRegisterBase = NULL;
AdapterObject->NumberOfMapRegisters = 0;
}
/* Call the adapter control routine. */
Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(
WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
switch (Result)
{
case KeepObject:
/*
* We're done until the caller manually calls IoFreeAdapterChannel
* or IoFreeMapRegisters.
*/
return;
case DeallocateObjectKeepRegisters:
/*
* Hide the map registers so they aren't deallocated next time
* around.
*/
AdapterObject->NumberOfMapRegisters = 0;
break;
default:
break;
}
}
}
/**
* @name IoFreeMapRegisters
*
* Free map registers reserved by the system for a DMA.
*
* @param AdapterObject
* DMA adapter to free map registers on.
* @param MapRegisterBase
* Handle to map registers to free.
* @param NumberOfRegisters
* Number of map registers to be freed.
*
* @implemented
*/
VOID STDCALL
IoFreeMapRegisters(
IN PADAPTER_OBJECT AdapterObject,
IN PVOID MapRegisterBase,
IN ULONG NumberOfMapRegisters)
{
PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter;
PLIST_ENTRY ListEntry;
KIRQL OldIrql;
ULONG Index;
ULONG Result;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
if (MasterAdapter == NULL || MapRegisterBase == NULL)
return;
OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
if (NumberOfMapRegisters != 0)
{
PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
RealMapRegisterBase =
(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
RtlClearBits(MasterAdapter->MapRegisters,
RealMapRegisterBase - MasterAdapter->MapRegisterBase,
NumberOfMapRegisters);
}
/*
* Now that we freed few map registers it's time to look at the master
* adapter queue and see if there is someone waiting for map registers.
*/
while (!IsListEmpty(&MasterAdapter->AdapterQueue))
{
ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue);
AdapterObject = CONTAINING_RECORD(
ListEntry, struct _ADAPTER_OBJECT, AdapterQueue);
Index = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters,
AdapterObject->NumberOfMapRegisters,
MasterAdapter->NumberOfMapRegisters);
if (Index == ~0)
{
InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry);
break;
}
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
AdapterObject->MapRegisterBase =
MasterAdapter->MapRegisterBase + Index;
if (!AdapterObject->ScatterGather)
{
AdapterObject->MapRegisterBase =
(PROS_MAP_REGISTER_ENTRY)(
(ULONG_PTR)AdapterObject->MapRegisterBase |
MAP_BASE_SW_SG);
}
Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(
AdapterObject->CurrentWcb->DeviceObject,
AdapterObject->CurrentWcb->CurrentIrp,
AdapterObject->MapRegisterBase,
AdapterObject->CurrentWcb->DeviceContext);
switch (Result)
{
case DeallocateObjectKeepRegisters:
AdapterObject->NumberOfMapRegisters = 0;
/* fall through */
case DeallocateObject:
if (AdapterObject->NumberOfMapRegisters)
{
OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
RtlClearBits(MasterAdapter->MapRegisters,
AdapterObject->MapRegisterBase -
MasterAdapter->MapRegisterBase,
AdapterObject->NumberOfMapRegisters);
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
}
IoFreeAdapterChannel(AdapterObject);
break;
default:
break;
}
OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
}
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
}
/**
* @name HalpCopyBufferMap
*
* Helper function for copying data from/to map register buffers.
*
* @see IoFlushAdapterBuffers, IoMapTransfer
*/
VOID STDCALL
HalpCopyBufferMap(
PMDL Mdl,
PROS_MAP_REGISTER_ENTRY MapRegisterBase,
PVOID CurrentVa,
ULONG Length,
BOOLEAN WriteToDevice)
{
ULONG CurrentLength;
ULONG_PTR CurrentAddress;
ULONG ByteOffset;
PVOID VirtualAddress;
VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority);
if (VirtualAddress == NULL)
{
/*
* NOTE: On real NT a mechanism with reserved pages is implemented
* to handle this case in a slow, but graceful non-fatal way.
*/
/* FIXME: The correct bug check code isn't defined. */
/* KEBUGCHECKEX(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); */
KEBUGCHECK(0);
}
CurrentAddress = (ULONG_PTR)VirtualAddress +
(ULONG_PTR)CurrentVa -
(ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
while (Length > 0)
{
ByteOffset = BYTE_OFFSET(CurrentAddress);
CurrentLength = PAGE_SIZE - ByteOffset;
if (CurrentLength > Length)
CurrentLength = Length;
if (WriteToDevice)
{
RtlCopyMemory(
(PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
(PVOID)CurrentAddress,
CurrentLength);
}
else
{
RtlCopyMemory(
(PVOID)CurrentAddress,
(PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
CurrentLength);
}
Length -= CurrentLength;
CurrentAddress += CurrentLength;
MapRegisterBase++;
}
}
/**
* @name IoFlushAdapterBuffers
*
* Flush any data remaining in the DMA controller's memory into the host
* memory.
*
* @param AdapterObject
* The adapter object to flush.
* @param Mdl
* Original MDL to flush data into.
* @param MapRegisterBase
* Map register base that was just used by IoMapTransfer, etc.
* @param CurrentVa
* Offset into Mdl to be flushed into, same as was passed to
* IoMapTransfer.
* @param Length
* Length of the buffer to be flushed into.
* @param WriteToDevice
* TRUE if it's a write, FALSE if it's a read.
*
* @return TRUE in all cases.
*
* @remarks
* This copies data from the map register-backed buffer to the user's
* target buffer. Data are not in the user buffer until this function
* is called.
* For slave DMA transfers the controller channel is masked effectively
* stopping the current transfer.
*
* @unimplemented.
*/
BOOLEAN STDCALL
IoFlushAdapterBuffers(
PADAPTER_OBJECT AdapterObject,
PMDL Mdl,
PVOID MapRegisterBase,
PVOID CurrentVa,
ULONG Length,
BOOLEAN WriteToDevice)
{
BOOLEAN SlaveDma = FALSE;
PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
PHYSICAL_ADDRESS HighestAcceptableAddress;
PHYSICAL_ADDRESS PhysicalAddress;
PPFN_NUMBER MdlPagesPtr;
ASSERT_IRQL(DISPATCH_LEVEL);
if (AdapterObject != NULL && !AdapterObject->MasterDevice)
{
/* Mask out (disable) the DMA channel. */
if (AdapterObject->AdapterNumber == 1)
{
PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
AdapterObject->ChannelNumber | DMA_SETMASK);
}
else
{
PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
AdapterObject->ChannelNumber | DMA_SETMASK);
}
SlaveDma = TRUE;
}
/* This can happen if the device supports hardware scatter/gather. */
if (MapRegisterBase == NULL)
return TRUE;
RealMapRegisterBase =
(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
if (!WriteToDevice)
{
if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG)
{
if (RealMapRegisterBase->Counter != ~0)
{
if (SlaveDma && !AdapterObject->IgnoreCount)
Length -= HalReadDmaCounter(AdapterObject);
HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE);
}
}
else
{
MdlPagesPtr = MmGetMdlPfnArray(Mdl);
MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT;
PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa);
HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
if (PhysicalAddress.QuadPart + Length >
HighestAcceptableAddress.QuadPart)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -