欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

dma.c

一个类似windows
C
第 1 页 / 共 4 页
字号:
         /* 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 + -