⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
{
   if (AdapterObject->ChannelNumber == 0xFF)
   {
      KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
                            FALSE, NULL);
      RemoveEntryList(&AdapterObject->AdapterList);
      KeSetEvent(&HalpDmaLock, 0, 0);
   }

   ObfDereferenceObject(AdapterObject);
}

/**
 * @name HalAllocateCommonBuffer
 *
 * Allocates memory that is visible to both the processor(s) and the DMA
 * device.
 *
 * @param AdapterObject
 *        Adapter object representing the bus master or system dma controller.
 * @param Length
 *        Number of bytes to allocate.
 * @param LogicalAddress
 *        Logical address the driver can use to access the buffer.
 * @param CacheEnabled
 *        Specifies if the memory can be cached.
 *
 * @return The base virtual address of the memory allocated or NULL on failure.
 *
 * @remarks
 *    On real NT x86 systems the CacheEnabled parameter is ignored, we honour
 *    it. If it proves to cause problems change it.
 *
 * @see HalFreeCommonBuffer
 *
 * @implemented
 */

PVOID STDCALL
HalAllocateCommonBuffer(
   PADAPTER_OBJECT AdapterObject,
   ULONG Length,
   PPHYSICAL_ADDRESS LogicalAddress,
   BOOLEAN CacheEnabled)
{
   PHYSICAL_ADDRESS LowestAcceptableAddress;
   PHYSICAL_ADDRESS HighestAcceptableAddress;
   PHYSICAL_ADDRESS BoundryAddressMultiple;
   PVOID VirtualAddress;

   LowestAcceptableAddress.QuadPart = 0;
   HighestAcceptableAddress =
      HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
   BoundryAddressMultiple.QuadPart = 0;

   /*
    * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
    * slave DMA devices the 64Kb boundary mustn't be crossed since the
    * controller wouldn't be able to handle it.
    */

   if (AdapterObject->MasterDevice)
      BoundryAddressMultiple.HighPart = 1;
   else
      BoundryAddressMultiple.LowPart = 0x10000;

   VirtualAddress = MmAllocateContiguousMemorySpecifyCache(
      Length, LowestAcceptableAddress, HighestAcceptableAddress,
      BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached);
   if (VirtualAddress == NULL)
      return NULL;

   *LogicalAddress = MmGetPhysicalAddress(VirtualAddress);

   return VirtualAddress;
}

/**
 * @name HalFreeCommonBuffer
 *
 * Free common buffer allocated with HalAllocateCommonBuffer.
 *
 * @see HalAllocateCommonBuffer
 *
 * @implemented
 */

VOID STDCALL
HalFreeCommonBuffer(
   PADAPTER_OBJECT AdapterObject,
   ULONG Length,
   PHYSICAL_ADDRESS LogicalAddress,
   PVOID VirtualAddress,
   BOOLEAN CacheEnabled)
{
   MmFreeContiguousMemory(VirtualAddress);
}

/**
 * @name HalpDmaGetDmaAlignment
 *
 * Internal routine to return the DMA alignment requirement. It's exported
 * using the DMA_OPERATIONS interface by HalGetAdapter.
 *
 * @see HalGetAdapter
 */

ULONG STDCALL
HalpDmaGetDmaAlignment(
   PADAPTER_OBJECT AdapterObject)
{
   return 1;
}

/*
 * @name HalReadDmaCounter
 *
 * Read DMA operation progress counter.
 *
 * @implemented
 */

ULONG STDCALL
HalReadDmaCounter(
   PADAPTER_OBJECT AdapterObject)
{
   KIRQL OldIrql;
   ULONG Count, OldCount;

   ASSERT(!AdapterObject->MasterDevice);

   /*
    * Acquire the master adapter lock since we're going to mess with the
    * system DMA controller registers and we really don't want anyone
    * to do the same at the same time.
    */

   KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
  
   /* Send the request to the specific controller. */
   if (AdapterObject->AdapterNumber == 1)
   {
      PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;

      Count = 0xffff00;
      do
      {
         OldCount = Count;
         /* Send Reset */
         WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
         /* Read Count */
         Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
                                 [AdapterObject->ChannelNumber].DmaBaseCount);
         Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
                                  [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
      }
      while (0xffff00 & (OldCount ^ Count));
   }
   else
   {
      PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;

      Count = 0xffff00;
      do
      {
         OldCount = Count;
         /* 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);
   }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -