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

📄 dma.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
   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 + -