dma.c
字号:
/* Send Reset */
WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
/* Read Count */
Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount);
Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount) << 8;
}
while (0xffff00 & (OldCount ^ Count));
}
KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
Count++;
Count &= 0xffff;
if (AdapterObject->Width16Bits)
Count *= 2;
return Count;
}
/**
* @name HalpGrowMapBufferWorker
*
* Helper routine of HalAllocateAdapterChannel for allocating map registers
* at PASSIVE_LEVEL in work item.
*/
VOID STDCALL
HalpGrowMapBufferWorker(PVOID DeferredContext)
{
PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext;
KIRQL OldIrql;
BOOLEAN Succeeded;
/*
* Try to allocate new map registers for the adapter.
*
* NOTE: The NT implementation actually tries to allocate more map
* registers than needed as an optimization.
*/
KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
FALSE, NULL);
Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter,
WorkItem->NumberOfMapRegisters);
KeSetEvent(&HalpDmaLock, 0, 0);
if (Succeeded)
{
/*
* Flush the adapter queue now that new map registers are ready. The
* easiest way to do that is to call IoFreeMapRegisters to not free
* any registers. Note that we use the magic (PVOID)2 map register
* base to bypass the parameter checking.
*/
OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0);
KfLowerIrql(OldIrql);
}
ExFreePool(WorkItem);
}
/**
* @name HalAllocateAdapterChannel
*
* Setup map registers for an adapter object.
*
* @param AdapterObject
* Pointer to an ADAPTER_OBJECT to set up.
* @param WaitContextBlock
* Context block to be used with ExecutionRoutine.
* @param NumberOfMapRegisters
* Number of map registers requested.
* @param ExecutionRoutine
* Callback to call when map registers are allocated.
*
* @return
* If not enough map registers can be allocated then
* STATUS_INSUFFICIENT_RESOURCES is returned. If the function
* succeeds or the callback is queued for later delivering then
* STATUS_SUCCESS is returned.
*
* @see IoFreeAdapterChannel
*
* @implemented
*/
NTSTATUS STDCALL
HalAllocateAdapterChannel(
PADAPTER_OBJECT AdapterObject,
PWAIT_CONTEXT_BLOCK WaitContextBlock,
ULONG NumberOfMapRegisters,
PDRIVER_CONTROL ExecutionRoutine)
{
PADAPTER_OBJECT MasterAdapter;
PGROW_WORK_ITEM WorkItem;
ULONG Index = ~0;
ULONG Result;
KIRQL OldIrql;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Set up the wait context block in case we can't run right away. */
WaitContextBlock->DeviceRoutine = ExecutionRoutine;
WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
/* Returns true if queued, else returns false and sets the queue to busy */
if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry))
return STATUS_SUCCESS;
MasterAdapter = AdapterObject->MasterAdapter;
AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
AdapterObject->CurrentWcb = WaitContextBlock;
if (NumberOfMapRegisters && AdapterObject->NeedsMapRegisters)
{
if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)
{
AdapterObject->NumberOfMapRegisters = 0;
IoFreeAdapterChannel(AdapterObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
/*
* Get the map registers. This is partly complicated by the fact
* that new map registers can only be allocated at PASSIVE_LEVEL
* and we're currently at DISPATCH_LEVEL. The following code has
* two code paths:
*
* - If there is no adapter queued for map register allocation,
* try to see if enough contiguous map registers are present.
* In case they're we can just get them and proceed further.
*
* - If some adapter is already present in the queue we must
* respect the order of adapters asking for map registers and
* so the fast case described above can't take place.
* This case is also entered if not enough coniguous map
* registers are present.
*
* A work queue item is allocated and queued, the adapter is
* also queued into the master adapter queue. The worker
* routine does the job of allocating the map registers at
* PASSIVE_LEVEL and calling the ExecutionRoutine.
*/
OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
if (IsListEmpty(&MasterAdapter->AdapterQueue))
{
Index = RtlFindClearBitsAndSet(
MasterAdapter->MapRegisters, 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)
{
WorkItem = ExAllocatePoolWithTag(
NonPagedPool, sizeof(GROW_WORK_ITEM), TAG_DMA);
if (WorkItem == NULL)
{
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
AdapterObject->NumberOfMapRegisters = 0;
IoFreeAdapterChannel(AdapterObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
ExInitializeWorkItem(
&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem);
WorkItem->AdapterObject = AdapterObject;
WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
return STATUS_SUCCESS;
}
KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
}
else
{
AdapterObject->MapRegisterBase = NULL;
AdapterObject->NumberOfMapRegisters = 0;
}
AdapterObject->CurrentWcb = WaitContextBlock;
Result = ExecutionRoutine(
WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
/*
* Possible return values:
*
* - KeepObject
* Don't free any resources, the ADAPTER_OBJECT is still in use and
* the caller will call IoFreeAdapterChannel later.
*
* - DeallocateObject
* Deallocate the map registers and release the ADAPTER_OBJECT, so
* someone else can use it.
*
* - DeallocateObjectKeepRegisters
* Release the ADAPTER_OBJECT, but hang on to the map registers. The
* client will later call IoFreeMapRegisters.
*
* NOTE:
* IoFreeAdapterChannel runs the queue, so it must be called unless
* the adapter object is not to be freed.
*/
if (Result == DeallocateObject)
{
IoFreeAdapterChannel(AdapterObject);
}
else if (Result == DeallocateObjectKeepRegisters)
{
AdapterObject->NumberOfMapRegisters = 0;
IoFreeAdapterChannel(AdapterObject);
}
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.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -