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

📄 dma.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
      NULL);

   Status = ObCreateObject(
      KernelMode,
      IoAdapterObjectType,
      &ObjectAttributes,
      KernelMode,
      NULL,
      sizeof(ADAPTER_OBJECT),
      0,
      0,
      (PVOID)&AdapterObject);
   if (!NT_SUCCESS(Status))
      return NULL;

   Status = ObReferenceObjectByPointer(
      AdapterObject,
      FILE_READ_DATA | FILE_WRITE_DATA,
      IoAdapterObjectType,
      KernelMode);
   if (!NT_SUCCESS(Status))
      return NULL;
 
   RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));

   Status = ObInsertObject(
      AdapterObject,
      NULL,
      FILE_READ_DATA | FILE_WRITE_DATA,
      0,
      NULL,
      &Handle);
   if (!NT_SUCCESS(Status))
      return NULL;

   ZwClose(Handle);

   AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version;
   AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT);
   AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations;
   AdapterObject->MapRegistersPerChannel = 1;
   AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
   AdapterObject->ChannelNumber = 0xFF;
   AdapterObject->MasterAdapter = HalpMasterAdapter;
   KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);

   return AdapterObject;
}

/**
 * @name HalpDmaInitializeEisaAdapter
 *
 * Setup DMA modes and extended modes for (E)ISA DMA adapter object.
 */

BOOLEAN STDCALL
HalpDmaInitializeEisaAdapter(
   PADAPTER_OBJECT AdapterObject,
   PDEVICE_DESCRIPTION DeviceDescription)
{
   UCHAR Controller;
   DMA_MODE DmaMode = {{0 }};
   DMA_EXTENDED_MODE ExtendedMode = {{ 0 }};
   PVOID AdapterBaseVa;

   Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1;

   if (Controller == 1)
      AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1);
   else
      AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2);

   AdapterObject->AdapterNumber = Controller;
   AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3);
   AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel];
   AdapterObject->Width16Bits = FALSE;
   AdapterObject->AdapterBaseVa = AdapterBaseVa;

   if (HalpEisaDma)
   {
      ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber;

      switch (DeviceDescription->DmaSpeed)
      {
         case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break;
         case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break;
         case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break;
         case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break;
         default:
            return FALSE;
      }

      switch (DeviceDescription->DmaWidth)
      {
         case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break;
         case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break;
         case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break;
         default:
            return FALSE;
      }

      if (Controller == 1)
         WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1),
                          ExtendedMode.Byte);
      else
         WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2),
                          ExtendedMode.Byte);
   }
   else
   {
      /*
       * Validate setup for non-busmaster DMA adapter. Secondary controller 
       * supports only 16-bit transfers and main controller supports only
       * 8-bit transfers. Anything else is invalid.
       */

      if (!DeviceDescription->Master)
      {
         if (Controller == 2 && DeviceDescription->DmaWidth == Width16Bits)
            AdapterObject->Width16Bits = TRUE;
         else if (Controller != 1 || DeviceDescription->DmaWidth != Width8Bits)
            return FALSE;
      }
   }

   DmaMode.Channel = AdapterObject->ChannelNumber;
   DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;

   /*
    * Set the DMA request mode.
    *
    * For (E)ISA bus master devices just unmask (enable) the DMA channel
    * and set it to cascade mode. Otherwise just select the right one
    * bases on the passed device description.
    */

   if (DeviceDescription->Master)
   {
      DmaMode.RequestMode = CASCADE_REQUEST_MODE;
      if (Controller == 1)
      {
         /* Set the Request Data */
         WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode,
                          DmaMode.Byte);
         /* Unmask DMA Channel */
         WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask,
                          AdapterObject->ChannelNumber | DMA_CLEARMASK);
      } else {
         /* Set the Request Data */
         WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode,
                          DmaMode.Byte);
         /* Unmask DMA Channel */
         WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask,
                          AdapterObject->ChannelNumber | DMA_CLEARMASK);
      }
   }
   else
   {
      if (DeviceDescription->DemandMode)
         DmaMode.RequestMode = DEMAND_REQUEST_MODE;
      else
         DmaMode.RequestMode = SINGLE_REQUEST_MODE;
   }

   AdapterObject->AdapterMode = DmaMode;

   return TRUE;
}

/**
 * @name HalGetAdapter
 *
 * Allocate an adapter object for DMA device.
 *
 * @param DeviceDescription
 *        Structure describing the attributes of the device.
 * @param NumberOfMapRegisters
 *        On return filled with the maximum number of map registers the
 *        device driver can allocate for DMA transfer operations.
 *
 * @return The DMA adapter on success, NULL otherwise.
 *
 * @implemented
 */

PADAPTER_OBJECT STDCALL
HalGetAdapter(
   PDEVICE_DESCRIPTION DeviceDescription,
   PULONG NumberOfMapRegisters)
{
   PADAPTER_OBJECT AdapterObject = NULL;
   PADAPTER_OBJECT MasterAdapter;
   BOOLEAN EisaAdapter;
   ULONG MapRegisters;
   ULONG MaximumLength;

   /* Validate parameters in device description */
   if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2)
      return NULL;

   /*
    * See if we're going to use ISA/EISA DMA adapter. These adapters are
    * special since they're reused.
    *
    * Also note that we check for channel number since there are only 8 DMA
    * channels on ISA, so any request above this requires new adapter.
    */

   if (DeviceDescription->InterfaceType == Isa || !DeviceDescription->Master)
   {
      if (DeviceDescription->InterfaceType == Isa &&
          DeviceDescription->DmaChannel >= 8)
         EisaAdapter = FALSE;
      else
         EisaAdapter = TRUE;
   }
   else
   {
      EisaAdapter = FALSE;
   }
	
   /*
    * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
    * for cascading the controllers and it's not available for software use.
    */

   if (EisaAdapter && DeviceDescription->DmaChannel == 4)
      return NULL;

   /*
    * Calculate the number of map registers.
    *
    * - For EISA and PCI scatter/gather no map registers are needed.
    * - For ISA slave scatter/gather one map register is needed.
    * - For all other cases the number of map registers depends on
    *   DeviceDescription->MaximumLength.
    */

   MaximumLength = DeviceDescription->MaximumLength & MAXLONG;
   if (DeviceDescription->ScatterGather &&
       (DeviceDescription->InterfaceType == Eisa ||
        DeviceDescription->InterfaceType == PCIBus))
   {
      MapRegisters = 0;
   }
   else if (DeviceDescription->ScatterGather &&
            !DeviceDescription->Master)
   {
      MapRegisters = 1;
   }
   else
   {
      /*
       * In the equation below the additional map register added by
       * the "+1" accounts for the case when a transfer does not start
       * at a page-aligned address.
       */
      MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1;
      if (MapRegisters > 16)
         MapRegisters = 16;
   }

   /*
    * Acquire the DMA lock that is used to protect adapter lists and
    * EISA adapter array.
    */

   KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
                         FALSE, NULL);

   /*
    * Now we must get ahold of the adapter object. For first eight ISA/EISA
    * channels there are static adapter objects that are reused and updated
    * on succesive HalGetAdapter calls. In other cases a new adapter object
    * is always created and it's to the DMA adapter list (HalpDmaAdapterList).
    */

   if (EisaAdapter)
   {
      AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
      if (AdapterObject != NULL)
      {
         if (AdapterObject->NeedsMapRegisters && 
             MapRegisters > AdapterObject->MapRegistersPerChannel)
            AdapterObject->MapRegistersPerChannel = MapRegisters;
      }
   }

   if (AdapterObject == NULL)
   {
      AdapterObject = HalpDmaAllocateChildAdapter(
         MapRegisters, DeviceDescription);
      if (AdapterObject == NULL)
      {
         KeSetEvent(&HalpDmaLock, 0, 0);
         return NULL;
      }

      if (EisaAdapter)
      {
         HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
      }

      if (MapRegisters > 0)
      {
         AdapterObject->NeedsMapRegisters = TRUE;
         MasterAdapter = HalpMasterAdapter;
         AdapterObject->MapRegistersPerChannel = MapRegisters;

         /*
          * FIXME: Verify that the following makes sense. Actually 
          * MasterAdapter->NumberOfMapRegisters contains even the number
          * of gaps, so this will not work correctly all the time. It
          * doesn't matter much since it's only optimization to avoid
          * queuing work items in HalAllocateAdapterChannel.
          */

         MasterAdapter->CommittedMapRegisters += MapRegisters;
         if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters)
            HalpGrowMapBuffers(MasterAdapter, 0x10000);
      }
      else
      {
         AdapterObject->NeedsMapRegisters = FALSE;
         if (DeviceDescription->Master)
            AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1;
         else
            AdapterObject->MapRegistersPerChannel = 1;
      }
   }

   if (!EisaAdapter)
      InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList);

   /*
    * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
    * no longer be touched, so we don't need it.
    */

   KeSetEvent(&HalpDmaLock, 0, 0);

   /*
    * Setup the values in the adapter object that are common for all
    * types of buses.
    */

   if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1)
      AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount;
   else
      AdapterObject->IgnoreCount = 0;

   AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
   AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses;
   AdapterObject->ScatterGather = DeviceDescription->ScatterGather;
   AdapterObject->MasterDevice = DeviceDescription->Master;
   *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel;

   /*
    * For non-(E)ISA adapters we have already done all the work. On the
    * other hand for (E)ISA adapters we must still setup the DMA modes
    * and prepare the controller.
    */

   if (EisaAdapter)
   {
      if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription))
      {
         ObfDereferenceObject(AdapterObject);
         return NULL;
      }
   }

   return AdapterObject;
}

/**
 * @name HalpGetDmaAdapter
 *
 * Internal routine to allocate PnP DMA adapter object. It's exported through
 * HalDispatchTable and used by IoGetDmaAdapter.
 *
 * @see HalGetAdapter
 */

PDMA_ADAPTER STDCALL
HalpGetDmaAdapter(
   IN PVOID Context,
   IN PDEVICE_DESCRIPTION DeviceDescription,
   OUT PULONG NumberOfMapRegisters)
{
   return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader;
}

/**
 * @name HalPutDmaAdapter
 *
 * Internal routine to free DMA adapter and resources for reuse. It's exported
 * using the DMA_OPERATIONS interface by HalGetAdapter.
 *
 * @see HalGetAdapter
 */

VOID STDCALL
HalPutDmaAdapter(
   PADAPTER_OBJECT AdapterObject)

⌨️ 快捷键说明

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