ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dma.c
Go to the documentation of this file.
00001 /* $Id: dma.c 24759 2006-11-14 20:59:48Z ion $
00002  *
00003  * COPYRIGHT:       See COPYING in the top level directory
00004  * PROJECT:         ReactOS kernel
00005  * FILE:            ntoskrnl/hal/x86/dma.c
00006  * PURPOSE:         DMA functions
00007  * PROGRAMMERS:     David Welch (welch@mcmail.com)
00008  *                  Filip Navara (navaraf@reactos.com)
00009  * UPDATE HISTORY:
00010  *                  Created 22/05/98
00011  */
00012 
00072 /* INCLUDES *****************************************************************/
00073 
00074 #include <hal.h>
00075 #define NDEBUG
00076 #include <debug.h>
00077 
00078 static KEVENT HalpDmaLock;
00079 static LIST_ENTRY HalpDmaAdapterList;
00080 static PADAPTER_OBJECT HalpEisaAdapter[8];
00081 static BOOLEAN HalpEisaDma;
00082 static PADAPTER_OBJECT HalpMasterAdapter;
00083 
00084 static const ULONG_PTR HalpEisaPortPage[8] = {
00085    FIELD_OFFSET(DMA_PAGE, Channel0),
00086    FIELD_OFFSET(DMA_PAGE, Channel1),
00087    FIELD_OFFSET(DMA_PAGE, Channel2),
00088    FIELD_OFFSET(DMA_PAGE, Channel3),
00089    0,
00090    FIELD_OFFSET(DMA_PAGE, Channel5),
00091    FIELD_OFFSET(DMA_PAGE, Channel6),
00092    FIELD_OFFSET(DMA_PAGE, Channel7)
00093 };
00094 
00095 static DMA_OPERATIONS HalpDmaOperations = {
00096    sizeof(DMA_OPERATIONS),
00097    (PPUT_DMA_ADAPTER)HalPutDmaAdapter,
00098    (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer,
00099    (PFREE_COMMON_BUFFER)HalFreeCommonBuffer,
00100    NULL, /* Initialized in HalpInitDma() */
00101    NULL, /* Initialized in HalpInitDma() */
00102    NULL, /* Initialized in HalpInitDma() */
00103    NULL, /* Initialized in HalpInitDma() */
00104    NULL, /* Initialized in HalpInitDma() */
00105    (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment,
00106    (PREAD_DMA_COUNTER)HalReadDmaCounter,
00107    /* FIXME: Implement the S/G funtions. */
00108    NULL /*(PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList*/,
00109    NULL /*(PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList*/,
00110    NULL /*(PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize*/,
00111    NULL /*(PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList*/,
00112    NULL /*(PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList*/
00113 };
00114 
00115 #define MAX_MAP_REGISTERS 64
00116 
00117 #define TAG_DMA ' AMD'
00118 
00119 /* FUNCTIONS *****************************************************************/
00120 
00121 VOID
00122 HalpInitDma(VOID)
00123 {
00124    /*
00125     * Initialize the DMA Operation table
00126     */
00127    HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel;
00128    HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers;
00129    HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel;
00130    HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters;
00131    HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer;
00132 
00133    /*
00134     * Check if Extended DMA is available. We're just going to do a random
00135     * read and write.
00136     */
00137 
00138    WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2), 0x2A);
00139    if (READ_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)) == 0x2A)
00140       HalpEisaDma = TRUE;
00141 
00142    /*
00143     * Intialize all the global variables and allocate master adapter with
00144     * first map buffers.
00145     */
00146 
00147    InitializeListHead(&HalpDmaAdapterList);
00148    KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE);
00149 
00150    HalpMasterAdapter = HalpDmaAllocateMasterAdapter();
00151 
00152    /*
00153     * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's
00154     * used by IoGetDmaAdapter in the kernel.
00155     */
00156 
00157    HalGetDmaAdapter = HalpGetDmaAdapter;
00158 }
00159 
00167 PHYSICAL_ADDRESS NTAPI
00168 HalpGetAdapterMaximumPhysicalAddress(
00169    IN PADAPTER_OBJECT AdapterObject)
00170 {
00171    PHYSICAL_ADDRESS HighestAddress;
00172 
00173    if (AdapterObject->MasterDevice)
00174    {
00175       if (AdapterObject->Dma64BitAddresses)
00176       {
00177          HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
00178          return HighestAddress;
00179       }
00180       else if (AdapterObject->Dma32BitAddresses)
00181       {
00182          HighestAddress.QuadPart = 0xFFFFFFFF;
00183          return HighestAddress;
00184       }
00185    }
00186 
00187    HighestAddress.QuadPart = 0xFFFFFF;
00188    return HighestAddress;
00189 }
00190 
00203 BOOLEAN NTAPI
00204 HalpGrowMapBuffers(
00205    IN PADAPTER_OBJECT AdapterObject,
00206    IN ULONG SizeOfMapBuffers)
00207 {
00208    PVOID VirtualAddress;
00209    PHYSICAL_ADDRESS PhysicalAddress;
00210    PHYSICAL_ADDRESS HighestAcceptableAddress;
00211    PHYSICAL_ADDRESS LowestAcceptableAddress;
00212    PHYSICAL_ADDRESS BoundryAddressMultiple;
00213    KIRQL OldIrql;
00214    ULONG MapRegisterCount;
00215 
00216    /* FIXME: Check if enough map register slots are available. */
00217 
00218    MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers);
00219 
00220    /*
00221     * Allocate memory for the new map registers. For 32-bit adapters we use
00222     * two passes in order not to waste scare resource (low memory).
00223     */
00224 
00225    HighestAcceptableAddress =
00226       HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
00227    LowestAcceptableAddress.HighPart = 0;
00228    LowestAcceptableAddress.LowPart =
00229       HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0;
00230    BoundryAddressMultiple.QuadPart = 0;
00231 
00232    VirtualAddress = MmAllocateContiguousMemorySpecifyCache(
00233       MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress,
00234       HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached);
00235 
00236    if (VirtualAddress == NULL && LowestAcceptableAddress.LowPart != 0)
00237    {
00238       LowestAcceptableAddress.LowPart = 0;
00239       VirtualAddress = MmAllocateContiguousMemorySpecifyCache(
00240          MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress,
00241          HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached);
00242    }
00243 
00244    if (VirtualAddress == NULL)
00245       return FALSE;
00246 
00247    PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
00248 
00249    /*
00250     * All the following must be done with the master adapter lock held
00251     * to prevent corruption.
00252     */
00253 
00254    OldIrql = KfAcquireSpinLock(&AdapterObject->SpinLock);
00255 
00256    /*
00257     * Setup map register entries for the buffer allocated. Each entry has
00258     * a virtual and physical address and corresponds to PAGE_SIZE large
00259     * buffer.
00260     */
00261 
00262    if (MapRegisterCount > 0)
00263    {
00264       PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry;
00265 
00266       CurrentEntry = AdapterObject->MapRegisterBase +
00267                      AdapterObject->NumberOfMapRegisters;
00268       do
00269       {
00270          /*
00271           * Leave one entry free for every non-contiguous memory region
00272           * in the map register bitmap. This ensures that we can search
00273           * using RtlFindClearBits for contiguous map register regions.
00274           *
00275           * Also for non-EISA DMA leave one free entry for every 64Kb
00276           * break, because the DMA controller can handle only coniguous
00277           * 64Kb regions.
00278           */
00279 
00280          if (CurrentEntry != AdapterObject->MapRegisterBase)
00281          {
00282             PreviousEntry = CurrentEntry - 1;
00283             if (PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE ==
00284                 PhysicalAddress.LowPart)
00285             {
00286                if (!HalpEisaDma)
00287                {
00288                   if ((PreviousEntry->PhysicalAddress.LowPart ^
00289                        PhysicalAddress.LowPart) & 0xFFFF0000)
00290                   {
00291                      CurrentEntry++;
00292                      AdapterObject->NumberOfMapRegisters++;
00293                   }
00294                }
00295             }
00296             else
00297             {
00298                CurrentEntry++;
00299                AdapterObject->NumberOfMapRegisters++;
00300             }
00301          }
00302 
00303          RtlClearBit(AdapterObject->MapRegisters,
00304                      CurrentEntry - AdapterObject->MapRegisterBase);
00305          CurrentEntry->VirtualAddress = VirtualAddress;
00306          CurrentEntry->PhysicalAddress = PhysicalAddress;
00307 
00308          PhysicalAddress.LowPart += PAGE_SIZE;
00309          VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
00310 
00311          CurrentEntry++;
00312          AdapterObject->NumberOfMapRegisters++;
00313          MapRegisterCount--;
00314       }
00315       while (MapRegisterCount != 0);
00316    }
00317 
00318    KfReleaseSpinLock(&AdapterObject->SpinLock, OldIrql);
00319 
00320    return TRUE;
00321 }
00322 
00332 PADAPTER_OBJECT NTAPI
00333 HalpDmaAllocateMasterAdapter(VOID)
00334 {
00335    PADAPTER_OBJECT MasterAdapter;
00336    ULONG Size, SizeOfBitmap;
00337 
00338    SizeOfBitmap = MAX_MAP_REGISTERS;
00339    Size = sizeof(ADAPTER_OBJECT);
00340    Size += sizeof(RTL_BITMAP);
00341    Size += (SizeOfBitmap + 7) >> 3;
00342 
00343    MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA);
00344    if (MasterAdapter == NULL)
00345       return NULL;
00346 
00347    RtlZeroMemory(MasterAdapter, Size);
00348 
00349    KeInitializeSpinLock(&MasterAdapter->SpinLock);
00350    InitializeListHead(&MasterAdapter->AdapterQueue);
00351 
00352    MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1);
00353    RtlInitializeBitMap(
00354       MasterAdapter->MapRegisters,
00355       (PULONG)(MasterAdapter->MapRegisters + 1),
00356       SizeOfBitmap);
00357    RtlSetAllBits(MasterAdapter->MapRegisters);
00358    MasterAdapter->NumberOfMapRegisters = 0;
00359    MasterAdapter->CommittedMapRegisters = 0;
00360 
00361    MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag(
00362       NonPagedPool,
00363       SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY),
00364       TAG_DMA);
00365    if (MasterAdapter->MapRegisterBase == NULL)
00366    {
00367       ExFreePool(MasterAdapter);
00368       return NULL;
00369    }
00370 
00371    RtlZeroMemory(MasterAdapter->MapRegisterBase,
00372                  SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY));
00373    if (!HalpGrowMapBuffers(MasterAdapter, 0x10000))
00374    {
00375       ExFreePool(MasterAdapter);
00376       return NULL;
00377    }
00378 
00379    return MasterAdapter;
00380 }
00381 
00391 PADAPTER_OBJECT NTAPI
00392 HalpDmaAllocateChildAdapter(
00393    ULONG NumberOfMapRegisters,
00394    PDEVICE_DESCRIPTION DeviceDescription)
00395 {
00396    PADAPTER_OBJECT AdapterObject;
00397    OBJECT_ATTRIBUTES ObjectAttributes;
00398    NTSTATUS Status;
00399    HANDLE Handle;
00400 
00401    InitializeObjectAttributes(
00402       &ObjectAttributes,
00403       NULL,
00404       OBJ_KERNEL_HANDLE | OBJ_PERMANENT,
00405       NULL,
00406       NULL);
00407 
00408    Status = ObCreateObject(
00409       KernelMode,
00410       IoAdapterObjectType,
00411       &ObjectAttributes,
00412       KernelMode,
00413       NULL,
00414       sizeof(ADAPTER_OBJECT),
00415       0,
00416       0,
00417       (PVOID)&AdapterObject);
00418    if (!NT_SUCCESS(Status))
00419       return NULL;
00420 
00421    Status = ObReferenceObjectByPointer(
00422       AdapterObject,
00423       FILE_READ_DATA | FILE_WRITE_DATA,
00424       IoAdapterObjectType,
00425       KernelMode);
00426    if (!NT_SUCCESS(Status))
00427       return NULL;
00428 
00429    RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
00430 
00431    Status = ObInsertObject(
00432       AdapterObject,
00433       NULL,
00434       FILE_READ_DATA | FILE_WRITE_DATA,
00435       0,
00436       NULL,
00437       &Handle);
00438    if (!NT_SUCCESS(Status))
00439       return NULL;
00440 
00441    ZwClose(Handle);
00442 
00443    AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version;
00444    AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT);
00445    AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations;
00446    AdapterObject->MapRegistersPerChannel = 1;
00447    AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
00448    AdapterObject->ChannelNumber = 0xFF;
00449    AdapterObject->MasterAdapter = HalpMasterAdapter;
00450    KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
00451 
00452    return AdapterObject;
00453 }
00454 
00461 BOOLEAN NTAPI
00462 HalpDmaInitializeEisaAdapter(
00463    PADAPTER_OBJECT AdapterObject,
00464    PDEVICE_DESCRIPTION DeviceDescription)
00465 {
00466    UCHAR Controller;
00467    DMA_MODE DmaMode = {{0 }};
00468    DMA_EXTENDED_MODE ExtendedMode = {{ 0 }};
00469    PVOID AdapterBaseVa;
00470 
00471    Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1;
00472 
00473    if (Controller == 1)
00474       AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1);
00475    else
00476       AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2);
00477 
00478    AdapterObject->AdapterNumber = Controller;
00479    AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3);
00480    AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel];
00481    AdapterObject->Width16Bits = FALSE;
00482    AdapterObject->AdapterBaseVa = AdapterBaseVa;
00483 
00484    if (HalpEisaDma)
00485    {
00486       ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber;
00487 
00488       switch (DeviceDescription->DmaSpeed)
00489       {
00490          case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break;
00491          case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break;
00492          case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break;
00493          case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break;
00494          default:
00495             return FALSE;
00496       }
00497 
00498       switch (DeviceDescription->DmaWidth)
00499       {
00500          case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break;
00501          case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break;
00502          case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break;
00503          default:
00504             return FALSE;
00505       }
00506 
00507       if (Controller == 1)
00508          WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1),
00509                           ExtendedMode.Byte);
00510       else
00511          WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2),
00512                           ExtendedMode.Byte);
00513    }
00514    else
00515    {
00516       /*
00517        * Validate setup for non-busmaster DMA adapter. Secondary controller
00518        * supports only 16-bit transfers and main controller supports only
00519        * 8-bit transfers. Anything else is invalid.
00520        */
00521 
00522       if (!DeviceDescription->Master)
00523       {
00524          if (Controller == 2 && DeviceDescription->DmaWidth == Width16Bits)
00525             AdapterObject->Width16Bits = TRUE;
00526          else if (Controller != 1 || DeviceDescription->DmaWidth != Width8Bits)
00527             return FALSE;
00528       }
00529    }
00530 
00531    DmaMode.Channel = AdapterObject->ChannelNumber;
00532    DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
00533 
00534    /*
00535     * Set the DMA request mode.
00536     *
00537     * For (E)ISA bus master devices just unmask (enable) the DMA channel
00538     * and set it to cascade mode. Otherwise just select the right one
00539     * bases on the passed device description.
00540     */
00541 
00542    if (DeviceDescription->Master)
00543    {
00544       DmaMode.RequestMode = CASCADE_REQUEST_MODE;
00545       if (Controller == 1)
00546       {
00547          /* Set the Request Data */
00548          WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode,
00549                           DmaMode.Byte);
00550          /* Unmask DMA Channel */
00551          WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask,
00552                           AdapterObject->ChannelNumber | DMA_CLEARMASK);
00553       } else {
00554          /* Set the Request Data */
00555          WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode,
00556                           DmaMode.Byte);
00557          /* Unmask DMA Channel */
00558          WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask,
00559                           AdapterObject->ChannelNumber | DMA_CLEARMASK);
00560       }
00561    }
00562    else
00563    {
00564       if (DeviceDescription->DemandMode)
00565          DmaMode.RequestMode = DEMAND_REQUEST_MODE;
00566       else
00567          DmaMode.RequestMode = SINGLE_REQUEST_MODE;
00568    }
00569 
00570    AdapterObject->AdapterMode = DmaMode;
00571 
00572    return TRUE;
00573 }
00574 
00591 PADAPTER_OBJECT NTAPI
00592 HalGetAdapter(
00593    PDEVICE_DESCRIPTION DeviceDescription,
00594    PULONG NumberOfMapRegisters)
00595 {
00596    PADAPTER_OBJECT AdapterObject = NULL;
00597    PADAPTER_OBJECT MasterAdapter;
00598    BOOLEAN EisaAdapter;
00599    ULONG MapRegisters;
00600    ULONG MaximumLength;
00601 
00602    /* Validate parameters in device description */
00603    if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2)
00604       return NULL;
00605 
00606    /*
00607     * See if we're going to use ISA/EISA DMA adapter. These adapters are
00608     * special since they're reused.
00609     *
00610     * Also note that we check for channel number since there are only 8 DMA
00611     * channels on ISA, so any request above this requires new adapter.
00612     */
00613 
00614    if (DeviceDescription->InterfaceType == Isa || !DeviceDescription->Master)
00615    {
00616       if (DeviceDescription->InterfaceType == Isa &&
00617           DeviceDescription->DmaChannel >= 8)
00618          EisaAdapter = FALSE;
00619       else
00620          EisaAdapter = TRUE;
00621    }
00622    else
00623    {
00624       EisaAdapter = FALSE;
00625    }
00626 
00627    /*
00628     * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
00629     * for cascading the controllers and it's not available for software use.
00630     */
00631 
00632    if (EisaAdapter && DeviceDescription->DmaChannel == 4)
00633       return NULL;
00634 
00635    /*
00636     * Calculate the number of map registers.
00637     *
00638     * - For EISA and PCI scatter/gather no map registers are needed.
00639     * - For ISA slave scatter/gather one map register is needed.
00640     * - For all other cases the number of map registers depends on
00641     *   DeviceDescription->MaximumLength.
00642     */
00643 
00644    MaximumLength = DeviceDescription->MaximumLength & MAXLONG;
00645    if (DeviceDescription->ScatterGather &&
00646        (DeviceDescription->InterfaceType == Eisa ||
00647         DeviceDescription->InterfaceType == PCIBus))
00648    {
00649       MapRegisters = 0;
00650    }
00651    else if (DeviceDescription->ScatterGather &&
00652             !DeviceDescription->Master)
00653    {
00654       MapRegisters = 1;
00655    }
00656    else
00657    {
00658       /*
00659        * In the equation below the additional map register added by
00660        * the "+1" accounts for the case when a transfer does not start
00661        * at a page-aligned address.
00662        */
00663       MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1;
00664       if (MapRegisters > 16)
00665          MapRegisters = 16;
00666    }
00667 
00668    /*
00669     * Acquire the DMA lock that is used to protect adapter lists and
00670     * EISA adapter array.
00671     */
00672 
00673    KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
00674                          FALSE, NULL);
00675 
00676    /*
00677     * Now we must get ahold of the adapter object. For first eight ISA/EISA
00678     * channels there are static adapter objects that are reused and updated
00679     * on succesive HalGetAdapter calls. In other cases a new adapter object
00680     * is always created and it's to the DMA adapter list (HalpDmaAdapterList).
00681     */
00682 
00683    if (EisaAdapter)
00684    {
00685       AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
00686       if (AdapterObject != NULL)
00687       {
00688          if (AdapterObject->NeedsMapRegisters &&
00689              MapRegisters > AdapterObject->MapRegistersPerChannel)
00690             AdapterObject->MapRegistersPerChannel = MapRegisters;
00691       }
00692    }
00693 
00694    if (AdapterObject == NULL)
00695    {
00696       AdapterObject = HalpDmaAllocateChildAdapter(
00697          MapRegisters, DeviceDescription);
00698       if (AdapterObject == NULL)
00699       {
00700          KeSetEvent(&HalpDmaLock, 0, 0);
00701          return NULL;
00702       }
00703 
00704       if (EisaAdapter)
00705       {
00706          HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
00707       }
00708 
00709       if (MapRegisters > 0)
00710       {
00711          AdapterObject->NeedsMapRegisters = TRUE;
00712          MasterAdapter = HalpMasterAdapter;
00713          AdapterObject->MapRegistersPerChannel = MapRegisters;
00714 
00715          /*
00716           * FIXME: Verify that the following makes sense. Actually
00717           * MasterAdapter->NumberOfMapRegisters contains even the number
00718           * of gaps, so this will not work correctly all the time. It
00719           * doesn't matter much since it's only optimization to avoid
00720           * queuing work items in HalAllocateAdapterChannel.
00721           */
00722 
00723          MasterAdapter->CommittedMapRegisters += MapRegisters;
00724          if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters)
00725             HalpGrowMapBuffers(MasterAdapter, 0x10000);
00726       }
00727       else
00728       {
00729          AdapterObject->NeedsMapRegisters = FALSE;
00730          if (DeviceDescription->Master)
00731             AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1;
00732          else
00733             AdapterObject->MapRegistersPerChannel = 1;
00734       }
00735    }
00736 
00737    if (!EisaAdapter)
00738       InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList);
00739 
00740    /*
00741     * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
00742     * no longer be touched, so we don't need it.
00743     */
00744 
00745    KeSetEvent(&HalpDmaLock, 0, 0);
00746 
00747    /*
00748     * Setup the values in the adapter object that are common for all
00749     * types of buses.
00750     */
00751 
00752    if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1)
00753       AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount;
00754    else
00755       AdapterObject->IgnoreCount = 0;
00756 
00757    AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
00758    AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses;
00759    AdapterObject->ScatterGather = DeviceDescription->ScatterGather;
00760    AdapterObject->MasterDevice = DeviceDescription->Master;
00761    *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel;
00762 
00763    /*
00764     * For non-(E)ISA adapters we have already done all the work. On the
00765     * other hand for (E)ISA adapters we must still setup the DMA modes
00766     * and prepare the controller.
00767     */
00768 
00769    if (EisaAdapter)
00770    {
00771       if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription))
00772       {
00773          ObDereferenceObject(AdapterObject);
00774          return NULL;
00775       }
00776    }
00777 
00778    return AdapterObject;
00779 }
00780 
00790 PDMA_ADAPTER NTAPI
00791 HalpGetDmaAdapter(
00792    IN PVOID Context,
00793    IN PDEVICE_DESCRIPTION DeviceDescription,
00794    OUT PULONG NumberOfMapRegisters)
00795 {
00796    return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader;
00797 }
00798 
00808 VOID NTAPI
00809 HalPutDmaAdapter(
00810    PADAPTER_OBJECT AdapterObject)
00811 {
00812    if (AdapterObject->ChannelNumber == 0xFF)
00813    {
00814       KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
00815                             FALSE, NULL);
00816       RemoveEntryList(&AdapterObject->AdapterList);
00817       KeSetEvent(&HalpDmaLock, 0, 0);
00818    }
00819 
00820    ObDereferenceObject(AdapterObject);
00821 }
00822 
00849 PVOID NTAPI
00850 HalAllocateCommonBuffer(
00851    PADAPTER_OBJECT AdapterObject,
00852    ULONG Length,
00853    PPHYSICAL_ADDRESS LogicalAddress,
00854    BOOLEAN CacheEnabled)
00855 {
00856    PHYSICAL_ADDRESS LowestAcceptableAddress;
00857    PHYSICAL_ADDRESS HighestAcceptableAddress;
00858    PHYSICAL_ADDRESS BoundryAddressMultiple;
00859    PVOID VirtualAddress;
00860 
00861    LowestAcceptableAddress.QuadPart = 0;
00862    HighestAcceptableAddress =
00863       HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
00864    BoundryAddressMultiple.QuadPart = 0;
00865 
00866    /*
00867     * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
00868     * slave DMA devices the 64Kb boundary mustn't be crossed since the
00869     * controller wouldn't be able to handle it.
00870     */
00871 
00872    if (AdapterObject->MasterDevice)
00873       BoundryAddressMultiple.HighPart = 1;
00874    else
00875       BoundryAddressMultiple.LowPart = 0x10000;
00876 
00877    VirtualAddress = MmAllocateContiguousMemorySpecifyCache(
00878       Length, LowestAcceptableAddress, HighestAcceptableAddress,
00879       BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached);
00880    if (VirtualAddress == NULL)
00881       return NULL;
00882 
00883    *LogicalAddress = MmGetPhysicalAddress(VirtualAddress);
00884 
00885    return VirtualAddress;
00886 }
00887 
00898 VOID NTAPI
00899 HalFreeCommonBuffer(
00900    PADAPTER_OBJECT AdapterObject,
00901    ULONG Length,
00902    PHYSICAL_ADDRESS LogicalAddress,
00903    PVOID VirtualAddress,
00904    BOOLEAN CacheEnabled)
00905 {
00906    MmFreeContiguousMemory(VirtualAddress);
00907 }
00908 
00918 ULONG NTAPI
00919 HalpDmaGetDmaAlignment(
00920    PADAPTER_OBJECT AdapterObject)
00921 {
00922    return 1;
00923 }
00924 
00925 /*
00926  * @name HalReadDmaCounter
00927  *
00928  * Read DMA operation progress counter.
00929  *
00930  * @implemented
00931  */
00932 
00933 ULONG NTAPI
00934 HalReadDmaCounter(
00935    PADAPTER_OBJECT AdapterObject)
00936 {
00937    KIRQL OldIrql;
00938    ULONG Count, OldCount;
00939 
00940    ASSERT(!AdapterObject->MasterDevice);
00941 
00942    /*
00943     * Acquire the master adapter lock since we're going to mess with the
00944     * system DMA controller registers and we really don't want anyone
00945     * to do the same at the same time.
00946     */
00947 
00948    KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
00949 
00950    /* Send the request to the specific controller. */
00951    if (AdapterObject->AdapterNumber == 1)
00952    {
00953       PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
00954 
00955       Count = 0xffff00;
00956       do
00957       {
00958          OldCount = Count;
00959          /* Send Reset */
00960          WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
00961          /* Read Count */
00962          Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
00963                                  [AdapterObject->ChannelNumber].DmaBaseCount);
00964          Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
00965                                   [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
00966       }
00967       while (0xffff00 & (OldCount ^ Count));
00968    }
00969    else
00970    {
00971       PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
00972 
00973       Count = 0xffff00;
00974       do
00975       {
00976          OldCount = Count;
00977          /* Send Reset */
00978          WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
00979          /* Read Count */
00980          Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
00981                                  [AdapterObject->ChannelNumber].DmaBaseCount);
00982          Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
00983                                   [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
00984       }
00985       while (0xffff00 & (OldCount ^ Count));
00986    }
00987 
00988    KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
00989 
00990    Count++;
00991    Count &= 0xffff;
00992    if (AdapterObject->Width16Bits)
00993       Count *= 2;
00994 
00995    return Count;
00996 }
00997 
01005 VOID NTAPI
01006 HalpGrowMapBufferWorker(PVOID DeferredContext)
01007 {
01008    PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext;
01009    KIRQL OldIrql;
01010    BOOLEAN Succeeded;
01011 
01012    /*
01013     * Try to allocate new map registers for the adapter.
01014     *
01015     * NOTE: The NT implementation actually tries to allocate more map
01016     * registers than needed as an optimization.
01017     */
01018 
01019    KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
01020                          FALSE, NULL);
01021    Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter,
01022                                   WorkItem->NumberOfMapRegisters);
01023    KeSetEvent(&HalpDmaLock, 0, 0);
01024 
01025    if (Succeeded)
01026    {
01027       /*
01028        * Flush the adapter queue now that new map registers are ready. The
01029        * easiest way to do that is to call IoFreeMapRegisters to not free
01030        * any registers. Note that we use the magic (PVOID)2 map register
01031        * base to bypass the parameter checking.
01032        */
01033 
01034       KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
01035       IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0);
01036       KeLowerIrql(OldIrql);
01037    }
01038 
01039    ExFreePool(WorkItem);
01040 }
01041 
01067 NTSTATUS NTAPI
01068 HalAllocateAdapterChannel(
01069    PADAPTER_OBJECT AdapterObject,
01070    PWAIT_CONTEXT_BLOCK WaitContextBlock,
01071    ULONG NumberOfMapRegisters,
01072    PDRIVER_CONTROL ExecutionRoutine)
01073 {
01074    PADAPTER_OBJECT MasterAdapter;
01075    PGROW_WORK_ITEM WorkItem;
01076    ULONG Index = MAXULONG;
01077    ULONG Result;
01078    KIRQL OldIrql;
01079 
01080    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01081 
01082    /* Set up the wait context block in case we can't run right away. */
01083    WaitContextBlock->DeviceRoutine = ExecutionRoutine;
01084    WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
01085 
01086    /* Returns true if queued, else returns false and sets the queue to busy */
01087    if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry))
01088       return STATUS_SUCCESS;
01089 
01090    MasterAdapter = AdapterObject->MasterAdapter;
01091 
01092    AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
01093    AdapterObject->CurrentWcb = WaitContextBlock;
01094 
01095    if (NumberOfMapRegisters && AdapterObject->NeedsMapRegisters)
01096    {
01097       if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)
01098       {
01099          AdapterObject->NumberOfMapRegisters = 0;
01100          IoFreeAdapterChannel(AdapterObject);
01101          return STATUS_INSUFFICIENT_RESOURCES;
01102       }
01103 
01104       /*
01105        * Get the map registers. This is partly complicated by the fact
01106        * that new map registers can only be allocated at PASSIVE_LEVEL
01107        * and we're currently at DISPATCH_LEVEL. The following code has
01108        * two code paths:
01109        *
01110        * - If there is no adapter queued for map register allocation,
01111        *   try to see if enough contiguous map registers are present.
01112        *   In case they're we can just get them and proceed further.
01113        *
01114        * - If some adapter is already present in the queue we must
01115        *   respect the order of adapters asking for map registers and
01116        *   so the fast case described above can't take place.
01117        *   This case is also entered if not enough coniguous map
01118        *   registers are present.
01119        *
01120        *   A work queue item is allocated and queued, the adapter is
01121        *   also queued into the master adapter queue. The worker
01122        *   routine does the job of allocating the map registers at
01123        *   PASSIVE_LEVEL and calling the ExecutionRoutine.
01124        */
01125 
01126       OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
01127 
01128       if (IsListEmpty(&MasterAdapter->AdapterQueue))
01129       {
01130          Index = RtlFindClearBitsAndSet(
01131             MasterAdapter->MapRegisters, NumberOfMapRegisters, 0);
01132          if (Index != MAXULONG)
01133          {
01134             AdapterObject->MapRegisterBase =
01135                MasterAdapter->MapRegisterBase + Index;
01136             if (!AdapterObject->ScatterGather)
01137             {
01138                AdapterObject->MapRegisterBase =
01139                   (PROS_MAP_REGISTER_ENTRY)(
01140                      (ULONG_PTR)AdapterObject->MapRegisterBase |
01141                      MAP_BASE_SW_SG);
01142             }
01143          }
01144       }
01145 
01146       if (Index == MAXULONG)
01147       {
01148          WorkItem = ExAllocatePoolWithTag(
01149             NonPagedPool, sizeof(GROW_WORK_ITEM), TAG_DMA);
01150          if (WorkItem == NULL)
01151          {
01152             KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01153             AdapterObject->NumberOfMapRegisters = 0;
01154             IoFreeAdapterChannel(AdapterObject);
01155             return STATUS_INSUFFICIENT_RESOURCES;
01156          }
01157 
01158          InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
01159 
01160          ExInitializeWorkItem(
01161             &WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem);
01162          WorkItem->AdapterObject = AdapterObject;
01163          WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
01164 
01165          ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
01166 
01167          KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01168 
01169          return STATUS_SUCCESS;
01170       }
01171 
01172       KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01173    }
01174    else
01175    {
01176       AdapterObject->MapRegisterBase = NULL;
01177       AdapterObject->NumberOfMapRegisters = 0;
01178    }
01179 
01180    AdapterObject->CurrentWcb = WaitContextBlock;
01181 
01182    Result = ExecutionRoutine(
01183       WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
01184       AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
01185 
01186    /*
01187     * Possible return values:
01188     *
01189     * - KeepObject
01190     *   Don't free any resources, the ADAPTER_OBJECT is still in use and
01191     *   the caller will call IoFreeAdapterChannel later.
01192     *
01193     * - DeallocateObject
01194     *   Deallocate the map registers and release the ADAPTER_OBJECT, so
01195     *   someone else can use it.
01196     *
01197     * - DeallocateObjectKeepRegisters
01198     *   Release the ADAPTER_OBJECT, but hang on to the map registers. The
01199     *   client will later call IoFreeMapRegisters.
01200     *
01201     * NOTE:
01202     * IoFreeAdapterChannel runs the queue, so it must be called unless
01203     * the adapter object is not to be freed.
01204     */
01205 
01206    if (Result == DeallocateObject)
01207    {
01208       IoFreeAdapterChannel(AdapterObject);
01209    }
01210    else if (Result == DeallocateObjectKeepRegisters)
01211    {
01212       AdapterObject->NumberOfMapRegisters = 0;
01213       IoFreeAdapterChannel(AdapterObject);
01214    }
01215 
01216    return STATUS_SUCCESS;
01217 }
01218 
01238 VOID NTAPI
01239 IoFreeAdapterChannel(
01240    PADAPTER_OBJECT AdapterObject)
01241 {
01242    PADAPTER_OBJECT MasterAdapter;
01243    PKDEVICE_QUEUE_ENTRY DeviceQueueEntry;
01244    PWAIT_CONTEXT_BLOCK WaitContextBlock;
01245    ULONG Index = MAXULONG;
01246    ULONG Result;
01247    KIRQL OldIrql;
01248 
01249    MasterAdapter = AdapterObject->MasterAdapter;
01250 
01251    for (;;)
01252    {
01253       /*
01254        * To keep map registers, call here with AdapterObject->
01255        * NumberOfMapRegisters set to zero. This trick is used in
01256        * HalAllocateAdapterChannel for example.
01257        */
01258       if (AdapterObject->NumberOfMapRegisters)
01259       {
01260          IoFreeMapRegisters(
01261             AdapterObject,
01262             AdapterObject->MapRegisterBase,
01263             AdapterObject->NumberOfMapRegisters);
01264       }
01265 
01266       DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue);
01267       if (DeviceQueueEntry == NULL)
01268       {
01269          break;
01270       }
01271 
01272       WaitContextBlock = CONTAINING_RECORD(
01273          DeviceQueueEntry,
01274          WAIT_CONTEXT_BLOCK,
01275          WaitQueueEntry);
01276 
01277       AdapterObject->CurrentWcb = WaitContextBlock;
01278       AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters;
01279 
01280       if (WaitContextBlock->NumberOfMapRegisters &&
01281           AdapterObject->MasterAdapter)
01282       {
01283          OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
01284 
01285          if (IsListEmpty(&MasterAdapter->AdapterQueue))
01286          {
01287             Index = RtlFindClearBitsAndSet(
01288                MasterAdapter->MapRegisters,
01289                WaitContextBlock->NumberOfMapRegisters, 0);
01290             if (Index != MAXULONG)
01291             {
01292                AdapterObject->MapRegisterBase =
01293                   MasterAdapter->MapRegisterBase + Index;
01294                if (!AdapterObject->ScatterGather)
01295                {
01296                   AdapterObject->MapRegisterBase =
01297                      (PROS_MAP_REGISTER_ENTRY)(
01298                         (ULONG_PTR)AdapterObject->MapRegisterBase |
01299                         MAP_BASE_SW_SG);
01300                }
01301             }
01302          }
01303 
01304          if (Index == MAXULONG)
01305          {
01306             InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
01307             KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01308             break;
01309          }
01310 
01311          KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01312       }
01313       else
01314       {
01315          AdapterObject->MapRegisterBase = NULL;
01316          AdapterObject->NumberOfMapRegisters = 0;
01317       }
01318 
01319       /* Call the adapter control routine. */
01320       Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(
01321           WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
01322           AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
01323 
01324       switch (Result)
01325       {
01326          case KeepObject:
01327             /*
01328              * We're done until the caller manually calls IoFreeAdapterChannel
01329              * or IoFreeMapRegisters.
01330              */
01331             return;
01332 
01333          case DeallocateObjectKeepRegisters:
01334             /*
01335              * Hide the map registers so they aren't deallocated next time
01336              * around.
01337              */
01338             AdapterObject->NumberOfMapRegisters = 0;
01339             break;
01340 
01341          default:
01342             break;
01343       }
01344    }
01345 }
01346 
01362 VOID NTAPI
01363 IoFreeMapRegisters(
01364    IN PADAPTER_OBJECT AdapterObject,
01365    IN PVOID MapRegisterBase,
01366    IN ULONG NumberOfMapRegisters)
01367 {
01368    PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter;
01369    PLIST_ENTRY ListEntry;
01370    KIRQL OldIrql;
01371    ULONG Index;
01372    ULONG Result;
01373 
01374    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01375 
01376    if (MasterAdapter == NULL || MapRegisterBase == NULL)
01377       return;
01378 
01379    OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
01380 
01381    if (NumberOfMapRegisters != 0)
01382    {
01383       PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
01384 
01385       RealMapRegisterBase =
01386          (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
01387       RtlClearBits(MasterAdapter->MapRegisters,
01388                    RealMapRegisterBase - MasterAdapter->MapRegisterBase,
01389                    NumberOfMapRegisters);
01390    }
01391 
01392    /*
01393     * Now that we freed few map registers it's time to look at the master
01394     * adapter queue and see if there is someone waiting for map registers.
01395     */
01396 
01397    while (!IsListEmpty(&MasterAdapter->AdapterQueue))
01398    {
01399       ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue);
01400       AdapterObject = CONTAINING_RECORD(
01401          ListEntry, struct _ADAPTER_OBJECT, AdapterQueue);
01402 
01403       Index = RtlFindClearBitsAndSet(
01404          MasterAdapter->MapRegisters,
01405          AdapterObject->NumberOfMapRegisters,
01406          MasterAdapter->NumberOfMapRegisters);
01407       if (Index == MAXULONG)
01408       {
01409          InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry);
01410          break;
01411       }
01412 
01413       KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01414 
01415       AdapterObject->MapRegisterBase =
01416          MasterAdapter->MapRegisterBase + Index;
01417       if (!AdapterObject->ScatterGather)
01418       {
01419          AdapterObject->MapRegisterBase =
01420             (PROS_MAP_REGISTER_ENTRY)(
01421                (ULONG_PTR)AdapterObject->MapRegisterBase |
01422                MAP_BASE_SW_SG);
01423       }
01424 
01425       Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(
01426          AdapterObject->CurrentWcb->DeviceObject,
01427          AdapterObject->CurrentWcb->CurrentIrp,
01428          AdapterObject->MapRegisterBase,
01429          AdapterObject->CurrentWcb->DeviceContext);
01430 
01431       switch (Result)
01432       {
01433          case DeallocateObjectKeepRegisters:
01434             AdapterObject->NumberOfMapRegisters = 0;
01435             /* fall through */
01436 
01437          case DeallocateObject:
01438             if (AdapterObject->NumberOfMapRegisters)
01439             {
01440                OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
01441                RtlClearBits(MasterAdapter->MapRegisters,
01442                             AdapterObject->MapRegisterBase -
01443                             MasterAdapter->MapRegisterBase,
01444                             AdapterObject->NumberOfMapRegisters);
01445                KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01446             }
01447             IoFreeAdapterChannel(AdapterObject);
01448             break;
01449 
01450          default:
01451             break;
01452       }
01453 
01454       OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock);
01455    }
01456 
01457    KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
01458 }
01459 
01468 VOID NTAPI
01469 HalpCopyBufferMap(
01470    PMDL Mdl,
01471    PROS_MAP_REGISTER_ENTRY MapRegisterBase,
01472    PVOID CurrentVa,
01473    ULONG Length,
01474    BOOLEAN WriteToDevice)
01475 {
01476    ULONG CurrentLength;
01477    ULONG_PTR CurrentAddress;
01478    ULONG ByteOffset;
01479    PVOID VirtualAddress;
01480 
01481    VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority);
01482    if (VirtualAddress == NULL)
01483    {
01484       /*
01485        * NOTE: On real NT a mechanism with reserved pages is implemented
01486        * to handle this case in a slow, but graceful non-fatal way.
01487        */
01488       KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0);
01489    }
01490 
01491    CurrentAddress = (ULONG_PTR)VirtualAddress +
01492                     (ULONG_PTR)CurrentVa -
01493                     (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
01494 
01495    while (Length > 0)
01496    {
01497       ByteOffset = BYTE_OFFSET(CurrentAddress);
01498       CurrentLength = PAGE_SIZE - ByteOffset;
01499       if (CurrentLength > Length)
01500          CurrentLength = Length;
01501 
01502       if (WriteToDevice)
01503       {
01504          RtlCopyMemory(
01505             (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
01506             (PVOID)CurrentAddress,
01507             CurrentLength);
01508       }
01509       else
01510       {
01511          RtlCopyMemory(
01512             (PVOID)CurrentAddress,
01513             (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
01514             CurrentLength);
01515       }
01516 
01517       Length -= CurrentLength;
01518       CurrentAddress += CurrentLength;
01519       MapRegisterBase++;
01520    }
01521 }
01522 
01555 BOOLEAN NTAPI
01556 IoFlushAdapterBuffers(
01557    PADAPTER_OBJECT AdapterObject,
01558    PMDL Mdl,
01559    PVOID MapRegisterBase,
01560    PVOID CurrentVa,
01561    ULONG Length,
01562    BOOLEAN WriteToDevice)
01563 {
01564    BOOLEAN SlaveDma = FALSE;
01565    PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
01566    PHYSICAL_ADDRESS HighestAcceptableAddress;
01567    PHYSICAL_ADDRESS PhysicalAddress;
01568    PPFN_NUMBER MdlPagesPtr;
01569 
01570    ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
01571 
01572    if (AdapterObject != NULL && !AdapterObject->MasterDevice)
01573    {
01574       /* Mask out (disable) the DMA channel. */
01575       if (AdapterObject->AdapterNumber == 1)
01576       {
01577          PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
01578          WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
01579                           AdapterObject->ChannelNumber | DMA_SETMASK);
01580       }
01581       else
01582       {
01583          PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
01584          WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
01585                           AdapterObject->ChannelNumber | DMA_SETMASK);
01586       }
01587       SlaveDma = TRUE;
01588    }
01589 
01590    /* This can happen if the device supports hardware scatter/gather. */
01591    if (MapRegisterBase == NULL)
01592       return TRUE;
01593 
01594    RealMapRegisterBase =
01595       (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
01596 
01597    if (!WriteToDevice)
01598    {
01599       if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG)
01600       {
01601          if (RealMapRegisterBase->Counter != MAXULONG)
01602          {
01603             if (SlaveDma && !AdapterObject->IgnoreCount)
01604                Length -= HalReadDmaCounter(AdapterObject);
01605          HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE);
01606       }
01607       }
01608       else
01609       {
01610          MdlPagesPtr = MmGetMdlPfnArray(Mdl);
01611          MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
01612 
01613          PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT;
01614          PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa);
01615 
01616          HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
01617          if (PhysicalAddress.QuadPart + Length >
01618              HighestAcceptableAddress.QuadPart)
01619          {
01620             HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE);
01621       }
01622    }
01623    }
01624 
01625    RealMapRegisterBase->Counter = 0;
01626 
01627    return TRUE;
01628 }
01629 
01662 PHYSICAL_ADDRESS NTAPI
01663 IoMapTransfer(
01664    IN PADAPTER_OBJECT AdapterObject,
01665    IN PMDL Mdl,
01666    IN PVOID MapRegisterBase,
01667    IN PVOID CurrentVa,
01668    IN OUT PULONG Length,
01669    IN BOOLEAN WriteToDevice)
01670 {
01671    PPFN_NUMBER MdlPagesPtr;
01672    PFN_NUMBER MdlPage1, MdlPage2;
01673    ULONG ByteOffset;
01674    ULONG TransferOffset;
01675    ULONG TransferLength;
01676    BOOLEAN UseMapRegisters;
01677    PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
01678    PHYSICAL_ADDRESS PhysicalAddress;
01679    PHYSICAL_ADDRESS HighestAcceptableAddress;
01680    ULONG Counter;
01681    DMA_MODE AdapterMode;
01682    KIRQL OldIrql;
01683 
01684    /*
01685     * Precalculate some values that are used in all cases.
01686     *
01687     * ByteOffset is offset inside the page at which the transfer starts.
01688     * MdlPagesPtr is pointer inside the MDL page chain at the page where the
01689     *             transfer start.
01690     * PhysicalAddress is physical address corresponding to the transfer
01691     *                 start page and offset.
01692     * TransferLength is the inital length of the transfer, which is reminder
01693     *                of the first page. The actual value is calculated below.
01694     *
01695     * Note that all the variables can change during the processing which
01696     * takes place below. These are just initial values.
01697     */
01698 
01699    ByteOffset = BYTE_OFFSET(CurrentVa);
01700 
01701    MdlPagesPtr = MmGetMdlPfnArray(Mdl);
01702    MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
01703 
01704    PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT;
01705    PhysicalAddress.QuadPart += ByteOffset;
01706 
01707    TransferLength = PAGE_SIZE - ByteOffset;
01708 
01709    /*
01710     * Special case for bus master adapters with S/G support. We can directly
01711     * use the buffer specified by the MDL, so not much work has to be done.
01712     *
01713     * Just return the passed VA's corresponding physical address and update
01714     * length to the number of physically contiguous bytes found. Also
01715     * pages crossing the 4Gb boundary aren't considered physically contiguous.
01716     */
01717 
01718    if (MapRegisterBase == NULL)
01719    {
01720       while (TransferLength < *Length)
01721       {
01722          MdlPage1 = *MdlPagesPtr;
01723          MdlPage2 = *(MdlPagesPtr + 1);
01724          if (MdlPage1 + 1 != MdlPage2)
01725             break;
01726          if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF)
01727             break;
01728          TransferLength += PAGE_SIZE;
01729          MdlPagesPtr++;
01730       }
01731 
01732       if (TransferLength < *Length)
01733          *Length = TransferLength;
01734 
01735       return PhysicalAddress;
01736    }
01737 
01738    /*
01739     * The code below applies to slave DMA adapters and bus master adapters
01740     * without hardward S/G support.
01741     */
01742 
01743    RealMapRegisterBase =
01744       (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
01745 
01746    /*
01747     * Try to calculate the size of the transfer. We can only transfer
01748     * pages that are physically contiguous and that don't cross the
01749     * 64Kb boundary (this limitation applies only for ISA controllers).
01750     */
01751 
01752    while (TransferLength < *Length)
01753    {
01754       MdlPage1 = *MdlPagesPtr;
01755       MdlPage2 = *(MdlPagesPtr + 1);
01756       if (MdlPage1 + 1 != MdlPage2)
01757          break;
01758       if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF))
01759          break;
01760       TransferLength += PAGE_SIZE;
01761       MdlPagesPtr++;
01762    }
01763 
01764    if (TransferLength > *Length)
01765       TransferLength = *Length;
01766 
01767    /*
01768     * If we're about to simulate software S/G and not all the pages are
01769     * physically contiguous then we must use the map registers to store
01770     * the data and allow the whole transfer to proceed at once.
01771     */
01772 
01773    if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG &&
01774        TransferLength < *Length)
01775    {
01776       UseMapRegisters = TRUE;
01777       PhysicalAddress = RealMapRegisterBase->PhysicalAddress;
01778       PhysicalAddress.QuadPart += ByteOffset;
01779       TransferLength = *Length;
01780       RealMapRegisterBase->Counter = MAXULONG;
01781       Counter = 0;
01782    }
01783    else
01784    {
01785       /*
01786        * This is ordinary DMA transfer, so just update the progress
01787        * counters. These are used by IoFlushAdapterBuffers to track
01788        * the transfer progress.
01789        */
01790 
01791       UseMapRegisters = FALSE;
01792       Counter = RealMapRegisterBase->Counter;
01793       RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength);
01794 
01795       /*
01796        * Check if the buffer doesn't exceed the highest physical address
01797        * limit of the device. In that case we must use the map registers to
01798        * store the data.
01799        */
01800 
01801       HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
01802       if (PhysicalAddress.QuadPart + TransferLength >
01803           HighestAcceptableAddress.QuadPart)
01804       {
01805          UseMapRegisters = TRUE;
01806          PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress;
01807          PhysicalAddress.QuadPart += ByteOffset;
01808          if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG)
01809          {
01810             RealMapRegisterBase->Counter = MAXULONG;
01811             Counter = 0;
01812          }
01813       }
01814    }
01815 
01816    /*
01817     * If we decided to use the map registers (see above) and we're about
01818     * to transfer data to the device then copy the buffers into the map
01819     * register memory.
01820     */
01821 
01822    if (UseMapRegisters && WriteToDevice)
01823    {
01824       HalpCopyBufferMap(Mdl, RealMapRegisterBase + Counter,
01825                         CurrentVa, TransferLength, WriteToDevice);
01826    }
01827 
01828    /*
01829     * Return the length of transfer that actually takes place.
01830     */
01831 
01832    *Length = TransferLength;
01833 
01834    /*
01835     * If we're doing slave (system) DMA then program the (E)ISA controller
01836     * to actually start the transfer.
01837     */
01838 
01839    if (AdapterObject != NULL && !AdapterObject->MasterDevice)
01840    {
01841       AdapterMode = AdapterObject->AdapterMode;
01842 
01843       if (WriteToDevice)
01844       {
01845          AdapterMode.TransferType = WRITE_TRANSFER;
01846       }
01847       else
01848       {
01849          AdapterMode.TransferType = READ_TRANSFER;
01850          if (AdapterObject->IgnoreCount)
01851          {
01852             RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress +
01853                           ByteOffset, TransferLength);
01854          }
01855       }
01856 
01857       TransferOffset = PhysicalAddress.LowPart & 0xFFFF;
01858       if (AdapterObject->Width16Bits)
01859       {
01860          TransferLength >>= 1;
01861          TransferOffset >>= 1;
01862       }
01863 
01864       OldIrql = KfAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock);
01865 
01866       if (AdapterObject->AdapterNumber == 1)
01867       {
01868          PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
01869 
01870          /* Reset Register */
01871          WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
01872          /* Set the Mode */
01873          WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte);
01874          /* Set the Offset Register */
01875          WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
01876                           (UCHAR)(TransferOffset));
01877          WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
01878                           (UCHAR)(TransferOffset >> 8));
01879          /* Set the Page Register */
01880          WRITE_PORT_UCHAR(AdapterObject->PagePort +
01881                           FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
01882                           (UCHAR)(PhysicalAddress.LowPart >> 16));
01883          if (HalpEisaDma)
01884          {
01885             WRITE_PORT_UCHAR(AdapterObject->PagePort +
01886                              FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
01887                              0);
01888          }
01889          /* Set the Length */
01890          WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
01891                           (UCHAR)(TransferLength - 1));
01892          WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
01893                           (UCHAR)((TransferLength - 1) >> 8));
01894          /* Unmask the Channel */
01895          WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
01896                           AdapterObject->ChannelNumber | DMA_CLEARMASK);
01897       }
01898       else
01899       {
01900          PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
01901 
01902          /* Reset Register */
01903          WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
01904          /* Set the Mode */
01905          WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte);
01906          /* Set the Offset Register */
01907          WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
01908                           (UCHAR)(TransferOffset));
01909          WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
01910                           (UCHAR)(TransferOffset >> 8));
01911          /* Set the Page Register */
01912          WRITE_PORT_UCHAR(AdapterObject->PagePort +
01913                           FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
01914                           (UCHAR)(PhysicalAddress.u.LowPart >> 16));
01915          if (HalpEisaDma)
01916          {
01917             WRITE_PORT_UCHAR(AdapterObject->PagePort +
01918                              FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
01919                              0);
01920          }
01921          /* Set the Length */
01922          WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
01923                           (UCHAR)(TransferLength - 1));
01924          WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
01925                           (UCHAR)((TransferLength - 1) >> 8));
01926          /* Unmask the Channel */
01927          WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
01928                           AdapterObject->ChannelNumber | DMA_CLEARMASK);
01929       }
01930 
01931       KfReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
01932    }
01933 
01934    /*
01935     * Return physical address of the buffer with data that is used for the
01936     * transfer. It can either point inside the Mdl that was passed by the
01937     * caller or into the map registers if the Mdl buffer can't be used
01938     * directly.
01939     */
01940 
01941    return PhysicalAddress;
01942 }
01943 
01949 BOOLEAN
01950 NTAPI
01951 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject,
01952                      IN ULONG Length,
01953                      IN PHYSICAL_ADDRESS LogicalAddress,
01954                      IN PVOID VirtualAddress)
01955 {
01956     /* Function always returns true */
01957     return TRUE;
01958 }
01959 
01960 /*
01961  * @implemented
01962  */
01963 PVOID
01964 NTAPI
01965 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject,
01966                               IN OUT PULONG NumberOfMapRegisters)
01967 {
01968     PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter;
01969     ULONG MapRegisterNumber;
01970 
01971     /* Check if it needs map registers */
01972     if (AdapterObject->NeedsMapRegisters)
01973     {
01974         /* Check if we have enough */
01975         if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)
01976         {
01977             /* We don't, fail */
01978             AdapterObject->NumberOfMapRegisters = 0;
01979             return NULL;
01980         }
01981 
01982         /* Try to find free map registers */
01983         MapRegisterNumber = MAXULONG;
01984         MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters,
01985                                                    *NumberOfMapRegisters,
01986                                                    0);
01987 
01988         /* Check if nothing was found */
01989         if (MapRegisterNumber == MAXULONG)
01990         {
01991             /* No free registers found, so use the base registers */
01992             RtlSetBits(MasterAdapter->MapRegisters,
01993                        0,
01994                        *NumberOfMapRegisters);
01995             MapRegisterNumber = 0;
01996         }
01997 
01998         /* Calculate the new base */
01999         AdapterObject->MapRegisterBase =
02000             (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase +
02001                                       MapRegisterNumber);
02002 
02003         /* Check if scatter gather isn't supported */
02004         if (!AdapterObject->ScatterGather)
02005         {
02006             /* Set the flag */
02007             AdapterObject->MapRegisterBase =
02008                 (PROS_MAP_REGISTER_ENTRY)
02009                 ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG);
02010         }
02011     }
02012     else
02013     {
02014         AdapterObject->MapRegisterBase = NULL;
02015         AdapterObject->NumberOfMapRegisters = 0;
02016     }
02017 
02018     /* Return the base */
02019     return AdapterObject->MapRegisterBase;
02020 }
02021 
02022 /* EOF */

Generated on Sun May 27 2012 04:28:00 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.