xref: /reactos/hal/halx86/generic/dma.c (revision 3f976713)
1 /*
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            hal/halx86/generic/dma.c
6  * PURPOSE:         DMA functions
7  * PROGRAMMERS:     David Welch (welch@mcmail.com)
8  *                  Filip Navara (navaraf@reactos.com)
9  * UPDATE HISTORY:
10  *                  Created 22/05/98
11  */
12 
13 /**
14  * @page DMA Implementation Notes
15  *
16  * Concepts:
17  *
18  * - Map register
19  *
20  *   Abstract encapsulation of physically contiguous buffer that resides
21  *   in memory accessible by both the DMA device / controller and the system.
22  *   The map registers are allocated and distributed on demand and are
23  *   scarce resource.
24  *
25  *   The actual use of map registers is to allow transfers from/to buffer
26  *   located in physical memory at address inaccessible by the DMA device /
27  *   controller directly. For such transfers the map register buffers
28  *   are used as intermediate data storage.
29  *
30  * - Master adapter
31  *
32  *   A container for map registers (typically corresponding to one physical
33  *   bus connection type). There can be master adapters for 24-bit address
34  *   ranges, 32-bit address ranges, etc. Every time a new DMA adapter is
35  *   created it's associated with a corresponding master adapter that
36  *   is used for any map register allocation requests.
37  *
38  * - Bus-master / Slave DMA
39  *
40  *   Slave DMA is term used for DMA transfers done by the system (E)ISA
41  *   controller as opposed to transfers mastered by the device itself
42  *   (hence the name).
43  *
44  *   For slave DMA special care is taken to actually access the system
45  *   controller and handle the transfers. The relevant code is in
46  *   HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers
47  *   and IoMapTransfer.
48  *
49  * Implementation:
50  *
51  * - Allocation of map registers
52  *
53  *   Initial set of map registers is allocated on the system start to
54  *   ensure that low memory won't get filled up later. Additional map
55  *   registers are allocated as needed by HalpGrowMapBuffers. This
56  *   routine is called on two places:
57  *
58  *   - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that
59  *     more map registers will probably be needed.
60  *   - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker
61  *     since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly)
62  *     when no more map registers are free.
63  *
64  *   Note that even if no more map registers can be allocated it's not
65  *   the end of the world. The adapters waiting for free map registers
66  *   are queued in the master adapter's queue and once one driver hands
67  *   back it's map registers (using IoFreeMapRegisters or indirectly using
68  *   the execution routine callback in IoAllocateAdapterChannel) the
69  *   queue gets processed and the map registers are reassigned.
70  */
71 
72 /* INCLUDES *****************************************************************/
73 
74 #include <hal.h>
75 #include <suppress.h>
76 
77 #define NDEBUG
78 #include <debug.h>
79 
80 #define MAX_SG_ELEMENTS 0x10
81 
82 #ifndef _MINIHAL_
83 static KEVENT HalpDmaLock;
84 static KSPIN_LOCK HalpDmaAdapterListLock;
85 static LIST_ENTRY HalpDmaAdapterList;
86 static PADAPTER_OBJECT HalpEisaAdapter[8];
87 #endif
88 static BOOLEAN HalpEisaDma;
89 #ifndef _MINIHAL_
90 static PADAPTER_OBJECT HalpMasterAdapter;
91 #endif
92 
93 static const ULONG_PTR HalpEisaPortPage[8] = {
94    FIELD_OFFSET(DMA_PAGE, Channel0),
95    FIELD_OFFSET(DMA_PAGE, Channel1),
96    FIELD_OFFSET(DMA_PAGE, Channel2),
97    FIELD_OFFSET(DMA_PAGE, Channel3),
98    0,
99    FIELD_OFFSET(DMA_PAGE, Channel5),
100    FIELD_OFFSET(DMA_PAGE, Channel6),
101    FIELD_OFFSET(DMA_PAGE, Channel7)
102 };
103 
104 #ifndef _MINIHAL_
105 NTSTATUS
106 NTAPI
107 HalCalculateScatterGatherListSize(
108     IN PADAPTER_OBJECT AdapterObject,
109     IN PMDL Mdl OPTIONAL,
110     IN PVOID CurrentVa,
111     IN ULONG Length,
112     OUT PULONG ScatterGatherListSize,
113     OUT PULONG pNumberOfMapRegisters);
114 
115 NTSTATUS
116 NTAPI
117 HalBuildScatterGatherList(
118     IN PADAPTER_OBJECT AdapterObject,
119     IN PDEVICE_OBJECT DeviceObject,
120     IN PMDL Mdl,
121     IN PVOID CurrentVa,
122     IN ULONG Length,
123     IN PDRIVER_LIST_CONTROL ExecutionRoutine,
124     IN PVOID Context,
125     IN BOOLEAN WriteToDevice,
126     IN PVOID ScatterGatherBuffer,
127     IN ULONG ScatterGatherLength);
128 
129 NTSTATUS
130 NTAPI
131 HalBuildMdlFromScatterGatherList(
132     IN PDMA_ADAPTER DmaAdapter,
133     IN PSCATTER_GATHER_LIST ScatterGather,
134     IN PMDL OriginalMdl,
135     OUT PMDL *TargetMdl);
136 
137 
138 static DMA_OPERATIONS HalpDmaOperations = {
139    sizeof(DMA_OPERATIONS),
140    (PPUT_DMA_ADAPTER)HalPutDmaAdapter,
141    (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer,
142    (PFREE_COMMON_BUFFER)HalFreeCommonBuffer,
143    NULL, /* Initialized in HalpInitDma() */
144    NULL, /* Initialized in HalpInitDma() */
145    NULL, /* Initialized in HalpInitDma() */
146    NULL, /* Initialized in HalpInitDma() */
147    NULL, /* Initialized in HalpInitDma() */
148    (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment,
149    (PREAD_DMA_COUNTER)HalReadDmaCounter,
150    (PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList,
151    (PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList,
152    (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize,
153    (PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList,
154    (PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList
155 };
156 #endif
157 
158 #define MAX_MAP_REGISTERS 64
159 
160 #define TAG_DMA ' AMD'
161 
162 /* FUNCTIONS *****************************************************************/
163 
164 #if defined(SARCH_PC98)
165 /*
166  * Disable I/O for safety.
167  * FIXME: Add support for PC-98 DMA controllers.
168  */
169 #undef WRITE_PORT_UCHAR
170 #undef READ_PORT_UCHAR
171 
172 #define WRITE_PORT_UCHAR(Port, Data) \
173     do { \
174         UNIMPLEMENTED; \
175         (Port); \
176         (Data); \
177     } while (0)
178 
179 #define READ_PORT_UCHAR(Port) 0x00
180 #endif
181 
182 #ifndef _MINIHAL_
183 CODE_SEG("INIT")
184 VOID
185 HalpInitDma(VOID)
186 {
187     /*
188      * Initialize the DMA Operation table
189      */
190     HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel;
191     HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers;
192     HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel;
193     HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters;
194     HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer;
195 
196     if (HalpBusType == MACHINE_TYPE_EISA)
197     {
198         /*
199         * Check if Extended DMA is available. We're just going to do a random
200         * read and write.
201         */
202         WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)), 0x2A);
203         if (READ_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2))) == 0x2A)
204         {
205             DPRINT1("Machine supports EISA DMA. Bus type: %lu\n", HalpBusType);
206             HalpEisaDma = TRUE;
207         }
208     }
209 
210     /*
211      * Intialize all the global variables and allocate master adapter with
212      * first map buffers.
213      */
214     InitializeListHead(&HalpDmaAdapterList);
215     KeInitializeSpinLock(&HalpDmaAdapterListLock);
216     KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE);
217     HalpMasterAdapter = HalpDmaAllocateMasterAdapter();
218 
219     /*
220      * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's
221      * used by IoGetDmaAdapter in the kernel.
222      */
223     HalGetDmaAdapter = HalpGetDmaAdapter;
224 }
225 #endif
226 
227 /**
228  * @name HalpGetAdapterMaximumPhysicalAddress
229  *
230  * Get the maximum physical address acceptable by the device represented
231  * by the passed DMA adapter.
232  */
233 PHYSICAL_ADDRESS
234 NTAPI
235 HalpGetAdapterMaximumPhysicalAddress(IN PADAPTER_OBJECT AdapterObject)
236 {
237     PHYSICAL_ADDRESS HighestAddress;
238 
239     if (AdapterObject->MasterDevice)
240     {
241         if (AdapterObject->Dma64BitAddresses)
242         {
243             HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
244             return HighestAddress;
245         }
246         else if (AdapterObject->Dma32BitAddresses)
247         {
248             HighestAddress.QuadPart = 0xFFFFFFFF;
249             return HighestAddress;
250         }
251     }
252 
253     HighestAddress.QuadPart = 0xFFFFFF;
254     return HighestAddress;
255 }
256 
257 #ifndef _MINIHAL_
258 /**
259  * @name HalpGrowMapBuffers
260  *
261  * Allocate initial, or additional, map buffers for DMA master adapter.
262  *
263  * @param MasterAdapter
264  *        DMA master adapter to allocate buffers for.
265  * @param SizeOfMapBuffers
266  *        Size of the map buffers to allocate (not including the size
267  *        already allocated).
268  */
269 BOOLEAN
270 NTAPI
271 HalpGrowMapBuffers(IN PADAPTER_OBJECT AdapterObject,
272                   IN ULONG SizeOfMapBuffers)
273 {
274     PVOID VirtualAddress;
275     PHYSICAL_ADDRESS PhysicalAddress;
276     PHYSICAL_ADDRESS HighestAcceptableAddress;
277     PHYSICAL_ADDRESS LowestAcceptableAddress;
278     PHYSICAL_ADDRESS BoundryAddressMultiple;
279     KIRQL OldIrql;
280     ULONG MapRegisterCount;
281 
282     /* Check if enough map register slots are available. */
283     MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers);
284     if (MapRegisterCount + AdapterObject->NumberOfMapRegisters > MAX_MAP_REGISTERS)
285     {
286         DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n",
287                AdapterObject->NumberOfMapRegisters,
288                MapRegisterCount,
289                MAX_MAP_REGISTERS);
290         return FALSE;
291     }
292 
293     /*
294      * Allocate memory for the new map registers. For 32-bit adapters we use
295      * two passes in order not to waste scare resource (low memory).
296      */
297     HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
298     LowestAcceptableAddress.HighPart = 0;
299     LowestAcceptableAddress.LowPart = HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0;
300     BoundryAddressMultiple.QuadPart = 0;
301 
302     VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT,
303                                                             LowestAcceptableAddress,
304                                                             HighestAcceptableAddress,
305                                                             BoundryAddressMultiple,
306                                                             MmNonCached);
307     if (!(VirtualAddress) && (LowestAcceptableAddress.LowPart))
308     {
309         LowestAcceptableAddress.LowPart = 0;
310         VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT,
311                                                                 LowestAcceptableAddress,
312                                                                 HighestAcceptableAddress,
313                                                                 BoundryAddressMultiple,
314                                                                 MmNonCached);
315     }
316 
317     if (!VirtualAddress) return FALSE;
318 
319     PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
320 
321     /*
322      * All the following must be done with the master adapter lock held
323      * to prevent corruption.
324      */
325     KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql);
326 
327     /*
328      * Setup map register entries for the buffer allocated. Each entry has
329      * a virtual and physical address and corresponds to PAGE_SIZE large
330      * buffer.
331      */
332     if (MapRegisterCount > 0)
333     {
334         PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry;
335 
336         CurrentEntry = AdapterObject->MapRegisterBase + AdapterObject->NumberOfMapRegisters;
337         do
338         {
339             /*
340              * Leave one entry free for every non-contiguous memory region
341              * in the map register bitmap. This ensures that we can search
342              * using RtlFindClearBits for contiguous map register regions.
343              *
344              * Also for non-EISA DMA leave one free entry for every 64Kb
345              * break, because the DMA controller can handle only coniguous
346              * 64Kb regions.
347              */
348             if (CurrentEntry != AdapterObject->MapRegisterBase)
349             {
350                 PreviousEntry = CurrentEntry - 1;
351                 if ((PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE) == PhysicalAddress.LowPart)
352                 {
353                     if (!HalpEisaDma)
354                     {
355                         if ((PreviousEntry->PhysicalAddress.LowPart ^ PhysicalAddress.LowPart) & 0xFFFF0000)
356                         {
357                             CurrentEntry++;
358                             AdapterObject->NumberOfMapRegisters++;
359                         }
360                     }
361                 }
362                 else
363                 {
364                     CurrentEntry++;
365                     AdapterObject->NumberOfMapRegisters++;
366                 }
367             }
368 
369             RtlClearBit(AdapterObject->MapRegisters,
370                         (ULONG)(CurrentEntry - AdapterObject->MapRegisterBase));
371             CurrentEntry->VirtualAddress = VirtualAddress;
372             CurrentEntry->PhysicalAddress = PhysicalAddress;
373 
374             PhysicalAddress.LowPart += PAGE_SIZE;
375             VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
376 
377             CurrentEntry++;
378             AdapterObject->NumberOfMapRegisters++;
379             MapRegisterCount--;
380         } while (MapRegisterCount);
381     }
382 
383     KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql);
384 
385     return TRUE;
386 }
387 
388 /**
389  * @name HalpDmaAllocateMasterAdapter
390  *
391  * Helper routine to allocate and initialize master adapter object and it's
392  * associated map register buffers.
393  *
394  * @see HalpInitDma
395  */
396 PADAPTER_OBJECT
397 NTAPI
398 HalpDmaAllocateMasterAdapter(VOID)
399 {
400     PADAPTER_OBJECT MasterAdapter;
401     ULONG Size, SizeOfBitmap;
402 
403     SizeOfBitmap = MAX_MAP_REGISTERS;
404     Size = sizeof(ADAPTER_OBJECT);
405     Size += sizeof(RTL_BITMAP);
406     Size += (SizeOfBitmap + 7) >> 3;
407 
408     MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA);
409     if (!MasterAdapter) return NULL;
410 
411     RtlZeroMemory(MasterAdapter, Size);
412 
413     KeInitializeSpinLock(&MasterAdapter->SpinLock);
414     InitializeListHead(&MasterAdapter->AdapterQueue);
415 
416     MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1);
417     RtlInitializeBitMap(MasterAdapter->MapRegisters,
418                         (PULONG)(MasterAdapter->MapRegisters + 1),
419                         SizeOfBitmap);
420     RtlSetAllBits(MasterAdapter->MapRegisters);
421     MasterAdapter->NumberOfMapRegisters = 0;
422     MasterAdapter->CommittedMapRegisters = 0;
423 
424     MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag(NonPagedPool,
425                                                            SizeOfBitmap *
426                                                            sizeof(ROS_MAP_REGISTER_ENTRY),
427                                                            TAG_DMA);
428     if (!MasterAdapter->MapRegisterBase)
429     {
430         ExFreePool(MasterAdapter);
431         return NULL;
432     }
433 
434     RtlZeroMemory(MasterAdapter->MapRegisterBase,
435                   SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY));
436     if (!HalpGrowMapBuffers(MasterAdapter, 0x10000))
437     {
438         ExFreePool(MasterAdapter);
439         return NULL;
440     }
441 
442     return MasterAdapter;
443 }
444 
445 /**
446  * @name HalpDmaAllocateChildAdapter
447  *
448  * Helper routine of HalGetAdapter. Allocate child adapter object and
449  * fill out some basic fields.
450  *
451  * @see HalGetAdapter
452  */
453 PADAPTER_OBJECT
454 NTAPI
455 HalpDmaAllocateChildAdapter(IN ULONG NumberOfMapRegisters,
456                             IN PDEVICE_DESCRIPTION DeviceDescription)
457 {
458     PADAPTER_OBJECT AdapterObject;
459     OBJECT_ATTRIBUTES ObjectAttributes;
460     NTSTATUS Status;
461     HANDLE Handle;
462 
463     InitializeObjectAttributes(&ObjectAttributes,
464                                NULL,
465                                OBJ_KERNEL_HANDLE | OBJ_PERMANENT,
466                                NULL,
467                                NULL);
468 
469     Status = ObCreateObject(KernelMode,
470                             IoAdapterObjectType,
471                             &ObjectAttributes,
472                             KernelMode,
473                             NULL,
474                             sizeof(ADAPTER_OBJECT),
475                             0,
476                             0,
477                             (PVOID)&AdapterObject);
478     if (!NT_SUCCESS(Status)) return NULL;
479 
480     Status = ObReferenceObjectByPointer(AdapterObject,
481                                         FILE_READ_DATA | FILE_WRITE_DATA,
482                                         IoAdapterObjectType,
483                                         KernelMode);
484     if (!NT_SUCCESS(Status)) return NULL;
485 
486     RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
487 
488     Status = ObInsertObject(AdapterObject,
489                             NULL,
490                             FILE_READ_DATA | FILE_WRITE_DATA,
491                             0,
492                             NULL,
493                             &Handle);
494     if (!NT_SUCCESS(Status)) return NULL;
495 
496     ZwClose(Handle);
497 
498     AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version;
499     AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT);
500     AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations;
501     AdapterObject->MapRegistersPerChannel = 1;
502     AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
503     AdapterObject->ChannelNumber = 0xFF;
504     AdapterObject->MasterAdapter = HalpMasterAdapter;
505     KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
506 
507     return AdapterObject;
508 }
509 #endif
510 
511 /**
512  * @name HalpDmaInitializeEisaAdapter
513  *
514  * Setup DMA modes and extended modes for (E)ISA DMA adapter object.
515  */
516 BOOLEAN
517 NTAPI
518 HalpDmaInitializeEisaAdapter(IN PADAPTER_OBJECT AdapterObject,
519                              IN PDEVICE_DESCRIPTION DeviceDescription)
520 {
521     UCHAR Controller;
522     DMA_MODE DmaMode = {{0 }};
523     DMA_EXTENDED_MODE ExtendedMode = {{ 0 }};
524     PVOID AdapterBaseVa;
525 
526     Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1;
527 
528     if (Controller == 1)
529     {
530         AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController1));
531     }
532     else
533     {
534         AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2));
535     }
536 
537     AdapterObject->AdapterNumber = Controller;
538     AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3);
539     AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel];
540     AdapterObject->Width16Bits = FALSE;
541     AdapterObject->AdapterBaseVa = AdapterBaseVa;
542 
543     if (HalpEisaDma)
544     {
545         ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber;
546 
547         switch (DeviceDescription->DmaSpeed)
548         {
549             case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break;
550             case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break;
551             case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break;
552             case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break;
553             default:
554                 return FALSE;
555         }
556 
557         switch (DeviceDescription->DmaWidth)
558         {
559             case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break;
560             case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break;
561             case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break;
562             default:
563                 return FALSE;
564         }
565 
566         if (Controller == 1)
567         {
568             WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1)),
569                             ExtendedMode.Byte);
570         }
571         else
572         {
573             WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2)),
574                             ExtendedMode.Byte);
575         }
576     }
577     else
578     {
579         /*
580          * Validate setup for non-busmaster DMA adapter. Secondary controller
581          * supports only 16-bit transfers and main controller supports only
582          * 8-bit transfers. Anything else is invalid.
583          */
584         if (!DeviceDescription->Master)
585         {
586             if ((Controller == 2) && (DeviceDescription->DmaWidth == Width16Bits))
587             {
588                 AdapterObject->Width16Bits = TRUE;
589             }
590             else if ((Controller != 1) || (DeviceDescription->DmaWidth != Width8Bits))
591             {
592                 return FALSE;
593             }
594         }
595     }
596 
597     DmaMode.Channel = AdapterObject->ChannelNumber;
598     DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
599 
600     /*
601      * Set the DMA request mode.
602      *
603      * For (E)ISA bus master devices just unmask (enable) the DMA channel
604      * and set it to cascade mode. Otherwise just select the right one
605      * bases on the passed device description.
606      */
607     if (DeviceDescription->Master)
608     {
609         DmaMode.RequestMode = CASCADE_REQUEST_MODE;
610         if (Controller == 1)
611         {
612             /* Set the Request Data */
613             _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR)
614             WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
615 
616             /* Unmask DMA Channel */
617             WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask,
618                              AdapterObject->ChannelNumber | DMA_CLEARMASK);
619         }
620         else
621         {
622             /* Set the Request Data */
623             WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
624 
625             /* Unmask DMA Channel */
626             WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask,
627                              AdapterObject->ChannelNumber | DMA_CLEARMASK);
628         }
629     }
630     else
631     {
632         if (DeviceDescription->DemandMode)
633         {
634             DmaMode.RequestMode = DEMAND_REQUEST_MODE;
635         }
636         else
637         {
638             DmaMode.RequestMode = SINGLE_REQUEST_MODE;
639         }
640     }
641 
642     AdapterObject->AdapterMode = DmaMode;
643 
644     return TRUE;
645 }
646 
647 #ifndef _MINIHAL_
648 /**
649  * @name HalGetAdapter
650  *
651  * Allocate an adapter object for DMA device.
652  *
653  * @param DeviceDescription
654  *        Structure describing the attributes of the device.
655  * @param NumberOfMapRegisters
656  *        On return filled with the maximum number of map registers the
657  *        device driver can allocate for DMA transfer operations.
658  *
659  * @return The DMA adapter on success, NULL otherwise.
660  *
661  * @implemented
662  */
663 PADAPTER_OBJECT
664 NTAPI
665 HalGetAdapter(IN PDEVICE_DESCRIPTION DeviceDescription,
666               OUT PULONG NumberOfMapRegisters)
667 {
668     PADAPTER_OBJECT AdapterObject = NULL;
669     BOOLEAN EisaAdapter;
670     ULONG MapRegisters;
671     ULONG MaximumLength;
672     KIRQL OldIrql;
673 
674     /* Validate parameters in device description */
675     if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) return NULL;
676 
677     /*
678      * See if we're going to use ISA/EISA DMA adapter. These adapters are
679      * special since they're reused.
680      *
681      * Also note that we check for channel number since there are only 8 DMA
682      * channels on ISA, so any request above this requires new adapter.
683      */
684     if (((DeviceDescription->InterfaceType == Eisa) ||
685          (DeviceDescription->InterfaceType == Isa)) || !(DeviceDescription->Master))
686     {
687         if (((DeviceDescription->InterfaceType == Isa) ||
688              (DeviceDescription->InterfaceType == Eisa)) &&
689             (DeviceDescription->DmaChannel >= 8))
690         {
691             EisaAdapter = FALSE;
692         }
693         else
694         {
695             EisaAdapter = TRUE;
696         }
697     }
698     else
699     {
700         EisaAdapter = FALSE;
701     }
702 
703     /*
704      * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
705      * for cascading the controllers and it's not available for software use.
706      */
707     if ((EisaAdapter) && (DeviceDescription->DmaChannel == 4)) return NULL;
708 
709     /*
710      * Calculate the number of map registers.
711      *
712      * - For EISA and PCI scatter/gather no map registers are needed.
713      * - For ISA slave scatter/gather one map register is needed.
714      * - For all other cases the number of map registers depends on
715      *   DeviceDescription->MaximumLength.
716      */
717     MaximumLength = DeviceDescription->MaximumLength & MAXLONG;
718     if ((DeviceDescription->ScatterGather) &&
719         ((DeviceDescription->InterfaceType == Eisa) ||
720          (DeviceDescription->InterfaceType == PCIBus)))
721     {
722         MapRegisters = 0;
723     }
724     else if ((DeviceDescription->ScatterGather) && !(DeviceDescription->Master))
725     {
726         MapRegisters = 1;
727     }
728     else
729     {
730         /*
731          * In the equation below the additional map register added by
732          * the "+1" accounts for the case when a transfer does not start
733          * at a page-aligned address.
734          */
735         MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1;
736         if (MapRegisters > 16) MapRegisters = 16;
737     }
738 
739     /*
740      * Acquire the DMA lock that is used to protect the EISA adapter array.
741      */
742     KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL);
743 
744     /*
745      * Now we must get ahold of the adapter object. For first eight ISA/EISA
746      * channels there are static adapter objects that are reused and updated
747      * on succesive HalGetAdapter calls. In other cases a new adapter object
748      * is always created and it's to the DMA adapter list (HalpDmaAdapterList).
749      */
750     if (EisaAdapter)
751     {
752         AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
753         if (AdapterObject)
754         {
755             if ((AdapterObject->NeedsMapRegisters) &&
756                 (MapRegisters > AdapterObject->MapRegistersPerChannel))
757             {
758                 AdapterObject->MapRegistersPerChannel = MapRegisters;
759             }
760         }
761     }
762 
763     if (AdapterObject == NULL)
764     {
765         AdapterObject = HalpDmaAllocateChildAdapter(MapRegisters, DeviceDescription);
766         if (AdapterObject == NULL)
767         {
768             KeSetEvent(&HalpDmaLock, 0, 0);
769             return NULL;
770         }
771 
772         if (EisaAdapter)
773         {
774             HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
775         }
776 
777         if (MapRegisters > 0)
778         {
779             AdapterObject->NeedsMapRegisters = TRUE;
780             AdapterObject->MapRegistersPerChannel = MapRegisters;
781         }
782         else
783         {
784             AdapterObject->NeedsMapRegisters = FALSE;
785             if (DeviceDescription->Master)
786             {
787                 AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1;
788             }
789             else
790             {
791                 AdapterObject->MapRegistersPerChannel = 1;
792             }
793         }
794     }
795 
796     /*
797      * Release the DMA lock. HalpEisaAdapter will no longer be touched,
798      * so we don't need it.
799      */
800     KeSetEvent(&HalpDmaLock, 0, 0);
801 
802     if (!EisaAdapter)
803     {
804         /* If it's not one of the static adapters, add it to the list */
805         KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql);
806         InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList);
807         KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql);
808     }
809 
810     /*
811      * Setup the values in the adapter object that are common for all
812      * types of buses.
813      */
814     if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1)
815     {
816         AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount;
817     }
818     else
819     {
820         AdapterObject->IgnoreCount = 0;
821     }
822 
823     AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
824     AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses;
825     AdapterObject->ScatterGather = DeviceDescription->ScatterGather;
826     AdapterObject->MasterDevice = DeviceDescription->Master;
827     *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel;
828 
829     /*
830      * For non-(E)ISA adapters we have already done all the work. On the
831      * other hand for (E)ISA adapters we must still setup the DMA modes
832      * and prepare the controller.
833      */
834     if (EisaAdapter)
835     {
836         if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription))
837         {
838             ObDereferenceObject(AdapterObject);
839             return NULL;
840         }
841     }
842 
843     return AdapterObject;
844 }
845 
846 /**
847  * @name HalpGetDmaAdapter
848  *
849  * Internal routine to allocate PnP DMA adapter object. It's exported through
850  * HalDispatchTable and used by IoGetDmaAdapter.
851  *
852  * @see HalGetAdapter
853  */
854 PDMA_ADAPTER
855 NTAPI
856 HalpGetDmaAdapter(IN PVOID Context,
857                   IN PDEVICE_DESCRIPTION DeviceDescription,
858                   OUT PULONG NumberOfMapRegisters)
859 {
860     return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader;
861 }
862 
863 /**
864  * @name HalPutDmaAdapter
865  *
866  * Internal routine to free DMA adapter and resources for reuse. It's exported
867  * using the DMA_OPERATIONS interface by HalGetAdapter.
868  *
869  * @see HalGetAdapter
870  */
871 VOID
872 NTAPI
873 HalPutDmaAdapter(IN PADAPTER_OBJECT AdapterObject)
874 {
875     KIRQL OldIrql;
876     if (AdapterObject->ChannelNumber == 0xFF)
877     {
878         KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql);
879         RemoveEntryList(&AdapterObject->AdapterList);
880         KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql);
881     }
882 
883     ObDereferenceObject(AdapterObject);
884 }
885 
886 /**
887  * @name HalAllocateCommonBuffer
888  *
889  * Allocates memory that is visible to both the processor(s) and the DMA
890  * device.
891  *
892  * @param AdapterObject
893  *        Adapter object representing the bus master or system dma controller.
894  * @param Length
895  *        Number of bytes to allocate.
896  * @param LogicalAddress
897  *        Logical address the driver can use to access the buffer.
898  * @param CacheEnabled
899  *        Specifies if the memory can be cached.
900  *
901  * @return The base virtual address of the memory allocated or NULL on failure.
902  *
903  * @remarks
904  *    On real NT x86 systems the CacheEnabled parameter is ignored, we honour
905  *    it. If it proves to cause problems change it.
906  *
907  * @see HalFreeCommonBuffer
908  *
909  * @implemented
910  */
911 PVOID
912 NTAPI
913 HalAllocateCommonBuffer(IN PADAPTER_OBJECT AdapterObject,
914                         IN ULONG Length,
915                         IN PPHYSICAL_ADDRESS LogicalAddress,
916                         IN BOOLEAN CacheEnabled)
917 {
918     PHYSICAL_ADDRESS LowestAcceptableAddress;
919     PHYSICAL_ADDRESS HighestAcceptableAddress;
920     PHYSICAL_ADDRESS BoundryAddressMultiple;
921     PVOID VirtualAddress;
922 
923     LowestAcceptableAddress.QuadPart = 0;
924     HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
925     BoundryAddressMultiple.QuadPart = 0;
926 
927     /*
928      * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
929      * slave DMA devices the 64Kb boundary mustn't be crossed since the
930      * controller wouldn't be able to handle it.
931      */
932     if (AdapterObject->MasterDevice)
933     {
934         BoundryAddressMultiple.HighPart = 1;
935     }
936     else
937     {
938         BoundryAddressMultiple.LowPart = 0x10000;
939     }
940 
941     VirtualAddress = MmAllocateContiguousMemorySpecifyCache(Length,
942                                                             LowestAcceptableAddress,
943                                                             HighestAcceptableAddress,
944                                                             BoundryAddressMultiple,
945                                                             CacheEnabled ? MmCached :
946                                                             MmNonCached);
947     if (VirtualAddress == NULL) return NULL;
948 
949     *LogicalAddress = MmGetPhysicalAddress(VirtualAddress);
950 
951     return VirtualAddress;
952 }
953 
954 /**
955  * @name HalFreeCommonBuffer
956  *
957  * Free common buffer allocated with HalAllocateCommonBuffer.
958  *
959  * @see HalAllocateCommonBuffer
960  *
961  * @implemented
962  */
963 VOID
964 NTAPI
965 HalFreeCommonBuffer(IN PADAPTER_OBJECT AdapterObject,
966                     IN ULONG Length,
967                     IN PHYSICAL_ADDRESS LogicalAddress,
968                     IN PVOID VirtualAddress,
969                     IN BOOLEAN CacheEnabled)
970 {
971     MmFreeContiguousMemorySpecifyCache(VirtualAddress,
972                                        Length,
973                                        CacheEnabled ? MmCached : MmNonCached);
974 }
975 
976 typedef struct _SCATTER_GATHER_CONTEXT {
977     BOOLEAN UsingUserBuffer;
978 	PADAPTER_OBJECT AdapterObject;
979 	PMDL Mdl;
980 	PUCHAR CurrentVa;
981 	ULONG Length;
982 	PDRIVER_LIST_CONTROL AdapterListControlRoutine;
983 	PVOID AdapterListControlContext, MapRegisterBase;
984 	ULONG MapRegisterCount;
985 	BOOLEAN WriteToDevice;
986 	WAIT_CONTEXT_BLOCK Wcb;
987 } SCATTER_GATHER_CONTEXT, *PSCATTER_GATHER_CONTEXT;
988 
989 
990 IO_ALLOCATION_ACTION
991 NTAPI
992 HalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject,
993                                 IN PIRP Irp,
994 								IN PVOID MapRegisterBase,
995 								IN PVOID Context)
996 {
997 	PSCATTER_GATHER_CONTEXT AdapterControlContext = Context;
998 	PADAPTER_OBJECT AdapterObject = AdapterControlContext->AdapterObject;
999 	PSCATTER_GATHER_LIST ScatterGatherList;
1000 	SCATTER_GATHER_ELEMENT TempElements[MAX_SG_ELEMENTS];
1001 	ULONG ElementCount = 0, RemainingLength = AdapterControlContext->Length;
1002 	PUCHAR CurrentVa = AdapterControlContext->CurrentVa;
1003 
1004 	/* Store the map register base for later in HalPutScatterGatherList */
1005 	AdapterControlContext->MapRegisterBase = MapRegisterBase;
1006 
1007 	while (RemainingLength > 0 && ElementCount < MAX_SG_ELEMENTS)
1008 	{
1009 	    TempElements[ElementCount].Length = RemainingLength;
1010 		TempElements[ElementCount].Reserved = 0;
1011 	    TempElements[ElementCount].Address = IoMapTransfer(AdapterObject,
1012 		                                                   AdapterControlContext->Mdl,
1013 														   MapRegisterBase,
1014 														   CurrentVa + (AdapterControlContext->Length - RemainingLength),
1015 														   &TempElements[ElementCount].Length,
1016 														   AdapterControlContext->WriteToDevice);
1017 		if (TempElements[ElementCount].Length == 0)
1018 			break;
1019 
1020 		DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n",
1021 		        TempElements[ElementCount].Address.QuadPart,
1022 				TempElements[ElementCount].Length);
1023 
1024 		ASSERT(TempElements[ElementCount].Length <= RemainingLength);
1025 		RemainingLength -= TempElements[ElementCount].Length;
1026 		ElementCount++;
1027 	}
1028 
1029 	if (RemainingLength > 0)
1030 	{
1031 		DPRINT1("Scatter/gather list construction failed!\n");
1032 		return DeallocateObject;
1033 	}
1034 
1035 	ScatterGatherList = ExAllocatePoolWithTag(NonPagedPool,
1036 	                                          sizeof(SCATTER_GATHER_LIST) + sizeof(SCATTER_GATHER_ELEMENT) * ElementCount,
1037 											  TAG_DMA);
1038 	ASSERT(ScatterGatherList);
1039 
1040 	ScatterGatherList->NumberOfElements = ElementCount;
1041 	ScatterGatherList->Reserved = (ULONG_PTR)AdapterControlContext;
1042 	RtlCopyMemory(ScatterGatherList->Elements,
1043 	              TempElements,
1044 				  sizeof(SCATTER_GATHER_ELEMENT) * ElementCount);
1045 
1046 	DPRINT("Initiating S/G DMA with %d element(s)\n", ElementCount);
1047 
1048 	AdapterControlContext->AdapterListControlRoutine(DeviceObject,
1049 	                                                 Irp,
1050 													 ScatterGatherList,
1051 													 AdapterControlContext->AdapterListControlContext);
1052 
1053 	return DeallocateObjectKeepRegisters;
1054 }
1055 
1056 /**
1057  * @name HalGetScatterGatherList
1058  *
1059  * Creates a scatter-gather list to be using in scatter/gather DMA
1060  *
1061  * @param AdapterObject
1062  *        Adapter object representing the bus master or system dma controller.
1063  * @param DeviceObject
1064  *        The device target for DMA.
1065  * @param Mdl
1066  *        The MDL that describes the buffer to be mapped.
1067  * @param CurrentVa
1068  *        The current VA in the buffer to be mapped for transfer.
1069  * @param Length
1070  *        Specifies the length of data in bytes to be mapped.
1071  * @param ExecutionRoutine
1072  *        A caller supplied AdapterListControl routine to be called when DMA is available.
1073  * @param Context
1074  *        Context passed to the AdapterListControl routine.
1075  * @param WriteToDevice
1076  *        Indicates direction of DMA operation.
1077  *
1078  * @return The status of the operation.
1079  *
1080  * @see HalBuildScatterGatherList
1081  *
1082  * @implemented
1083  */
1084  NTSTATUS
1085  NTAPI
1086  HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject,
1087                          IN PDEVICE_OBJECT DeviceObject,
1088                          IN PMDL Mdl,
1089                          IN PVOID CurrentVa,
1090                          IN ULONG Length,
1091                          IN PDRIVER_LIST_CONTROL ExecutionRoutine,
1092                          IN PVOID Context,
1093                          IN BOOLEAN WriteToDevice)
1094 {
1095     return HalBuildScatterGatherList(AdapterObject,
1096                                      DeviceObject,
1097                                      Mdl,
1098                                      CurrentVa,
1099                                      Length,
1100                                      ExecutionRoutine,
1101                                      Context,
1102                                      WriteToDevice,
1103                                      NULL,
1104                                      0);
1105 }
1106 
1107 /**
1108  * @name HalPutScatterGatherList
1109  *
1110  * Frees a scatter-gather list allocated from HalBuildScatterGatherList
1111  *
1112  * @param AdapterObject
1113  *        Adapter object representing the bus master or system dma controller.
1114  * @param ScatterGather
1115  *        The scatter/gather list to be freed.
1116  * @param WriteToDevice
1117  *        Indicates direction of DMA operation.
1118  *
1119  * @return None
1120  *
1121  * @see HalBuildScatterGatherList
1122  *
1123  * @implemented
1124  */
1125  VOID
1126  NTAPI
1127  HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject,
1128                          IN PSCATTER_GATHER_LIST ScatterGather,
1129 						 IN BOOLEAN WriteToDevice)
1130 {
1131     PSCATTER_GATHER_CONTEXT AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved;
1132 	ULONG i;
1133 
1134 	for (i = 0; i < ScatterGather->NumberOfElements; i++)
1135 	{
1136 	     IoFlushAdapterBuffers(AdapterObject,
1137 		                       AdapterControlContext->Mdl,
1138 							   AdapterControlContext->MapRegisterBase,
1139 							   AdapterControlContext->CurrentVa,
1140 							   ScatterGather->Elements[i].Length,
1141 							   AdapterControlContext->WriteToDevice);
1142 		 AdapterControlContext->CurrentVa += ScatterGather->Elements[i].Length;
1143 	}
1144 
1145 	IoFreeMapRegisters(AdapterObject,
1146 	                   AdapterControlContext->MapRegisterBase,
1147 					   AdapterControlContext->MapRegisterCount);
1148 
1149 
1150 	ExFreePoolWithTag(ScatterGather, TAG_DMA);
1151 
1152     /* If this is our buffer, release it */
1153     if (!AdapterControlContext->UsingUserBuffer)
1154         ExFreePoolWithTag(AdapterControlContext, TAG_DMA);
1155 
1156     DPRINT("S/G DMA has finished!\n");
1157 }
1158 
1159 NTSTATUS
1160 NTAPI
1161 HalCalculateScatterGatherListSize(
1162     IN PADAPTER_OBJECT AdapterObject,
1163     IN PMDL Mdl OPTIONAL,
1164     IN PVOID CurrentVa,
1165     IN ULONG Length,
1166     OUT PULONG ScatterGatherListSize,
1167     OUT PULONG pNumberOfMapRegisters)
1168 {
1169     ULONG NumberOfMapRegisters;
1170     ULONG SgSize;
1171 
1172     UNIMPLEMENTED_ONCE;
1173 
1174     NumberOfMapRegisters = PAGE_ROUND_UP(Length) >> PAGE_SHIFT;
1175     SgSize = sizeof(SCATTER_GATHER_CONTEXT);
1176 
1177     *ScatterGatherListSize = SgSize;
1178     if (pNumberOfMapRegisters) *pNumberOfMapRegisters = NumberOfMapRegisters;
1179 
1180     return STATUS_SUCCESS;
1181 }
1182 
1183 /**
1184  * @name HalBuildScatterGatherList
1185  *
1186  * Creates a scatter-gather list to be using in scatter/gather DMA
1187  *
1188  * @param AdapterObject
1189  *        Adapter object representing the bus master or system dma controller.
1190  * @param DeviceObject
1191  *        The device target for DMA.
1192  * @param Mdl
1193  *        The MDL that describes the buffer to be mapped.
1194  * @param CurrentVa
1195  *        The current VA in the buffer to be mapped for transfer.
1196  * @param Length
1197  *        Specifies the length of data in bytes to be mapped.
1198  * @param ExecutionRoutine
1199  *        A caller supplied AdapterListControl routine to be called when DMA is available.
1200  * @param Context
1201  *        Context passed to the AdapterListControl routine.
1202  * @param WriteToDevice
1203  *        Indicates direction of DMA operation.
1204  *
1205  * @param ScatterGatherBuffer
1206  *        User buffer for the scatter-gather list
1207  *
1208  * @param ScatterGatherBufferLength
1209  *        Buffer length
1210  *
1211  * @return The status of the operation.
1212  *
1213  * @see HalPutScatterGatherList
1214  *
1215  * @implemented
1216  */
1217 NTSTATUS
1218 NTAPI
1219 HalBuildScatterGatherList(
1220     IN PADAPTER_OBJECT AdapterObject,
1221     IN PDEVICE_OBJECT DeviceObject,
1222     IN PMDL Mdl,
1223     IN PVOID CurrentVa,
1224     IN ULONG Length,
1225     IN PDRIVER_LIST_CONTROL ExecutionRoutine,
1226     IN PVOID Context,
1227     IN BOOLEAN WriteToDevice,
1228     IN PVOID ScatterGatherBuffer,
1229     IN ULONG ScatterGatherBufferLength)
1230 {
1231     NTSTATUS Status;
1232     ULONG SgSize, NumberOfMapRegisters;
1233     PSCATTER_GATHER_CONTEXT ScatterGatherContext;
1234     BOOLEAN UsingUserBuffer;
1235 
1236     Status = HalCalculateScatterGatherListSize(AdapterObject,
1237                                                Mdl,
1238                                                CurrentVa,
1239                                                Length,
1240                                                &SgSize,
1241                                                &NumberOfMapRegisters);
1242     if (!NT_SUCCESS(Status)) return Status;
1243 
1244     if (ScatterGatherBuffer)
1245     {
1246         /* Checking if user buffer is enough */
1247         if (ScatterGatherBufferLength < SgSize)
1248         {
1249             return STATUS_BUFFER_TOO_SMALL;
1250         }
1251         UsingUserBuffer = TRUE;
1252     }
1253     else
1254     {
1255         ScatterGatherBuffer = ExAllocatePoolWithTag(NonPagedPool, SgSize, TAG_DMA);
1256         if (!ScatterGatherBuffer)
1257         {
1258             return STATUS_INSUFFICIENT_RESOURCES;
1259         }
1260         UsingUserBuffer = FALSE;
1261     }
1262 
1263     {
1264         ScatterGatherContext = (PSCATTER_GATHER_CONTEXT)ScatterGatherBuffer;
1265 
1266         /* Fill the scatter-gather context */
1267         ScatterGatherContext->UsingUserBuffer = UsingUserBuffer;
1268         ScatterGatherContext->AdapterObject = AdapterObject;
1269         ScatterGatherContext->Mdl = Mdl;
1270         ScatterGatherContext->CurrentVa = CurrentVa;
1271         ScatterGatherContext->Length = Length;
1272         ScatterGatherContext->MapRegisterCount = NumberOfMapRegisters;
1273         ScatterGatherContext->AdapterListControlRoutine = ExecutionRoutine;
1274         ScatterGatherContext->AdapterListControlContext = Context;
1275         ScatterGatherContext->WriteToDevice = WriteToDevice;
1276 
1277         ScatterGatherContext->Wcb.DeviceObject = DeviceObject;
1278         ScatterGatherContext->Wcb.DeviceContext = (PVOID)ScatterGatherContext;
1279         ScatterGatherContext->Wcb.CurrentIrp = DeviceObject->CurrentIrp;
1280 
1281         Status = HalAllocateAdapterChannel(AdapterObject,
1282                                            &ScatterGatherContext->Wcb,
1283                                            NumberOfMapRegisters,
1284                                            HalpScatterGatherAdapterControl);
1285 
1286         if (!NT_SUCCESS(Status))
1287         {
1288             if (!UsingUserBuffer)
1289                 ExFreePoolWithTag(ScatterGatherBuffer, TAG_DMA);
1290             return Status;
1291         }
1292     }
1293 
1294     return STATUS_SUCCESS;
1295 }
1296 
1297 NTSTATUS
1298 NTAPI
1299 HalBuildMdlFromScatterGatherList(
1300     IN PDMA_ADAPTER DmaAdapter,
1301     IN PSCATTER_GATHER_LIST ScatterGather,
1302     IN PMDL OriginalMdl,
1303     OUT PMDL *TargetMdl)
1304 {
1305     UNIMPLEMENTED;
1306     return STATUS_NOT_IMPLEMENTED;
1307 }
1308 #endif
1309 
1310 /**
1311  * @name HalpDmaGetDmaAlignment
1312  *
1313  * Internal routine to return the DMA alignment requirement. It's exported
1314  * using the DMA_OPERATIONS interface by HalGetAdapter.
1315  *
1316  * @see HalGetAdapter
1317  */
1318 ULONG
1319 NTAPI
1320 HalpDmaGetDmaAlignment(IN PADAPTER_OBJECT AdapterObject)
1321 {
1322     return 1;
1323 }
1324 
1325 /*
1326  * @name HalReadDmaCounter
1327  *
1328  * Read DMA operation progress counter.
1329  *
1330  * @implemented
1331  */
1332 ULONG
1333 NTAPI
1334 HalReadDmaCounter(IN PADAPTER_OBJECT AdapterObject)
1335 {
1336     KIRQL OldIrql;
1337     ULONG Count, OldCount;
1338 
1339     ASSERT(!AdapterObject->MasterDevice);
1340 
1341     /*
1342      * Acquire the master adapter lock since we're going to mess with the
1343      * system DMA controller registers and we really don't want anyone
1344      * to do the same at the same time.
1345      */
1346     KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
1347 
1348     /* Send the request to the specific controller. */
1349     if (AdapterObject->AdapterNumber == 1)
1350     {
1351         PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
1352 
1353         Count = 0xffff00;
1354         do
1355         {
1356             OldCount = Count;
1357 
1358             /* Send Reset */
1359             WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
1360 
1361             /* Read Count */
1362             Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
1363                                     [AdapterObject->ChannelNumber].DmaBaseCount);
1364             Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
1365                                      [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
1366         } while (0xffff00 & (OldCount ^ Count));
1367     }
1368     else
1369     {
1370         PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
1371 
1372         Count = 0xffff00;
1373         do
1374         {
1375             OldCount = Count;
1376 
1377             /* Send Reset */
1378             WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
1379 
1380             /* Read Count */
1381             Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
1382                                     [AdapterObject->ChannelNumber].DmaBaseCount);
1383             Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
1384                                      [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
1385         } while (0xffff00 & (OldCount ^ Count));
1386     }
1387 
1388     KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
1389 
1390     Count++;
1391     Count &= 0xffff;
1392     if (AdapterObject->Width16Bits) Count *= 2;
1393 
1394     return Count;
1395 }
1396 
1397 #ifndef _MINIHAL_
1398 /**
1399  * @name HalpGrowMapBufferWorker
1400  *
1401  * Helper routine of HalAllocateAdapterChannel for allocating map registers
1402  * at PASSIVE_LEVEL in work item.
1403  */
1404 VOID
1405 NTAPI
1406 HalpGrowMapBufferWorker(IN PVOID DeferredContext)
1407 {
1408     PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext;
1409     KIRQL OldIrql;
1410     BOOLEAN Succeeded;
1411 
1412     /*
1413      * Try to allocate new map registers for the adapter.
1414      *
1415      * NOTE: The NT implementation actually tries to allocate more map
1416      * registers than needed as an optimization.
1417      */
1418     KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL);
1419     Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter,
1420                                    WorkItem->NumberOfMapRegisters << PAGE_SHIFT);
1421     KeSetEvent(&HalpDmaLock, 0, 0);
1422 
1423     if (Succeeded)
1424     {
1425         /*
1426          * Flush the adapter queue now that new map registers are ready. The
1427          * easiest way to do that is to call IoFreeMapRegisters to not free
1428          * any registers. Note that we use the magic (PVOID)2 map register
1429          * base to bypass the parameter checking.
1430          */
1431         OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
1432         IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0);
1433         KfLowerIrql(OldIrql);
1434     }
1435 
1436     ExFreePool(WorkItem);
1437 }
1438 
1439 /**
1440  * @name HalAllocateAdapterChannel
1441  *
1442  * Setup map registers for an adapter object.
1443  *
1444  * @param AdapterObject
1445  *        Pointer to an ADAPTER_OBJECT to set up.
1446  * @param WaitContextBlock
1447  *        Context block to be used with ExecutionRoutine.
1448  * @param NumberOfMapRegisters
1449  *        Number of map registers requested.
1450  * @param ExecutionRoutine
1451  *        Callback to call when map registers are allocated.
1452  *
1453  * @return
1454  *    If not enough map registers can be allocated then
1455  *    STATUS_INSUFFICIENT_RESOURCES is returned. If the function
1456  *    succeeds or the callback is queued for later delivering then
1457  *    STATUS_SUCCESS is returned.
1458  *
1459  * @see IoFreeAdapterChannel
1460  *
1461  * @implemented
1462  */
1463 NTSTATUS
1464 NTAPI
1465 HalAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject,
1466                           IN PWAIT_CONTEXT_BLOCK WaitContextBlock,
1467                           IN ULONG NumberOfMapRegisters,
1468                           IN PDRIVER_CONTROL ExecutionRoutine)
1469 {
1470     PADAPTER_OBJECT MasterAdapter;
1471     PGROW_WORK_ITEM WorkItem;
1472     ULONG Index = MAXULONG;
1473     ULONG Result;
1474     KIRQL OldIrql;
1475 
1476     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1477 
1478     /* Set up the wait context block in case we can't run right away. */
1479     WaitContextBlock->DeviceRoutine = ExecutionRoutine;
1480     WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
1481 
1482     /* Returns true if queued, else returns false and sets the queue to busy */
1483     if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue,
1484                             &WaitContextBlock->WaitQueueEntry))
1485     {
1486         return STATUS_SUCCESS;
1487     }
1488 
1489     MasterAdapter = AdapterObject->MasterAdapter;
1490 
1491     AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters;
1492     AdapterObject->CurrentWcb = WaitContextBlock;
1493 
1494     if ((NumberOfMapRegisters) && (AdapterObject->NeedsMapRegisters))
1495     {
1496         if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)
1497         {
1498             AdapterObject->NumberOfMapRegisters = 0;
1499             IoFreeAdapterChannel(AdapterObject);
1500             return STATUS_INSUFFICIENT_RESOURCES;
1501         }
1502 
1503         /*
1504          * Get the map registers. This is partly complicated by the fact
1505          * that new map registers can only be allocated at PASSIVE_LEVEL
1506          * and we're currently at DISPATCH_LEVEL. The following code has
1507          * two code paths:
1508          *
1509          * - If there is no adapter queued for map register allocation,
1510          *   try to see if enough contiguous map registers are present.
1511          *   In case they're we can just get them and proceed further.
1512          *
1513          * - If some adapter is already present in the queue we must
1514          *   respect the order of adapters asking for map registers and
1515          *   so the fast case described above can't take place.
1516          *   This case is also entered if not enough coniguous map
1517          *   registers are present.
1518          *
1519          *   A work queue item is allocated and queued, the adapter is
1520          *   also queued into the master adapter queue. The worker
1521          *   routine does the job of allocating the map registers at
1522          *   PASSIVE_LEVEL and calling the ExecutionRoutine.
1523          */
1524 
1525         KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
1526 
1527         if (IsListEmpty(&MasterAdapter->AdapterQueue))
1528         {
1529             Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, NumberOfMapRegisters, 0);
1530             if (Index != MAXULONG)
1531             {
1532                 AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index;
1533                 if (!AdapterObject->ScatterGather)
1534                 {
1535                     AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG);
1536                 }
1537             }
1538         }
1539 
1540         if (Index == MAXULONG)
1541         {
1542             InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
1543 
1544             WorkItem = ExAllocatePoolWithTag(NonPagedPool,
1545                                              sizeof(GROW_WORK_ITEM),
1546                                              TAG_DMA);
1547             if (WorkItem)
1548             {
1549                 ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem);
1550                 WorkItem->AdapterObject = AdapterObject;
1551                 WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
1552 
1553                 ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
1554             }
1555 
1556             KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1557 
1558             return STATUS_SUCCESS;
1559         }
1560 
1561         KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1562     }
1563     else
1564     {
1565         AdapterObject->MapRegisterBase = NULL;
1566         AdapterObject->NumberOfMapRegisters = 0;
1567     }
1568 
1569     AdapterObject->CurrentWcb = WaitContextBlock;
1570 
1571     Result = ExecutionRoutine(WaitContextBlock->DeviceObject,
1572                               WaitContextBlock->CurrentIrp,
1573                               AdapterObject->MapRegisterBase,
1574                               WaitContextBlock->DeviceContext);
1575 
1576     /*
1577      * Possible return values:
1578      *
1579      * - KeepObject
1580      *   Don't free any resources, the ADAPTER_OBJECT is still in use and
1581      *   the caller will call IoFreeAdapterChannel later.
1582      *
1583      * - DeallocateObject
1584      *   Deallocate the map registers and release the ADAPTER_OBJECT, so
1585      *   someone else can use it.
1586      *
1587      * - DeallocateObjectKeepRegisters
1588      *   Release the ADAPTER_OBJECT, but hang on to the map registers. The
1589      *   client will later call IoFreeMapRegisters.
1590      *
1591      * NOTE:
1592      * IoFreeAdapterChannel runs the queue, so it must be called unless
1593      * the adapter object is not to be freed.
1594      */
1595     if (Result == DeallocateObject)
1596     {
1597         IoFreeAdapterChannel(AdapterObject);
1598     }
1599     else if (Result == DeallocateObjectKeepRegisters)
1600     {
1601         AdapterObject->NumberOfMapRegisters = 0;
1602         IoFreeAdapterChannel(AdapterObject);
1603     }
1604 
1605     return STATUS_SUCCESS;
1606 }
1607 
1608 /**
1609  * @name IoFreeAdapterChannel
1610  *
1611  * Free DMA resources allocated by IoAllocateAdapterChannel.
1612  *
1613  * @param AdapterObject
1614  *        Adapter object with resources to free.
1615  *
1616  * @remarks
1617  *    This function releases map registers registers assigned to the DMA
1618  *    adapter. After releasing the adapter, it checks the adapter's queue
1619  *    and runs each queued device object in series until the queue is
1620  *    empty. This is the only way the device queue is emptied.
1621  *
1622  * @see IoAllocateAdapterChannel
1623  *
1624  * @implemented
1625  */
1626 VOID
1627 NTAPI
1628 IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject)
1629 {
1630     PADAPTER_OBJECT MasterAdapter;
1631     PKDEVICE_QUEUE_ENTRY DeviceQueueEntry;
1632     PWAIT_CONTEXT_BLOCK WaitContextBlock;
1633     ULONG Index = MAXULONG;
1634     ULONG Result;
1635     KIRQL OldIrql;
1636 
1637     MasterAdapter = AdapterObject->MasterAdapter;
1638 
1639     for (;;)
1640     {
1641         /*
1642          * To keep map registers, call here with AdapterObject->
1643          * NumberOfMapRegisters set to zero. This trick is used in
1644          * HalAllocateAdapterChannel for example.
1645          */
1646         if (AdapterObject->NumberOfMapRegisters)
1647         {
1648             IoFreeMapRegisters(AdapterObject,
1649                                AdapterObject->MapRegisterBase,
1650                                AdapterObject->NumberOfMapRegisters);
1651         }
1652 
1653         DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue);
1654         if (!DeviceQueueEntry) break;
1655 
1656         WaitContextBlock = CONTAINING_RECORD(DeviceQueueEntry,
1657                                              WAIT_CONTEXT_BLOCK,
1658                                              WaitQueueEntry);
1659 
1660         AdapterObject->CurrentWcb = WaitContextBlock;
1661         AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters;
1662 
1663         if ((WaitContextBlock->NumberOfMapRegisters) && (AdapterObject->MasterAdapter))
1664         {
1665             KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
1666 
1667             if (IsListEmpty(&MasterAdapter->AdapterQueue))
1668             {
1669                 Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters,
1670                                                WaitContextBlock->NumberOfMapRegisters,
1671                                                0);
1672                 if (Index != MAXULONG)
1673                 {
1674                     AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index;
1675                     if (!AdapterObject->ScatterGather)
1676                     {
1677                         AdapterObject->MapRegisterBase =(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG);
1678                     }
1679                 }
1680             }
1681 
1682             if (Index == MAXULONG)
1683             {
1684                 InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
1685                 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1686                 break;
1687             }
1688 
1689             KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1690         }
1691         else
1692         {
1693             AdapterObject->MapRegisterBase = NULL;
1694             AdapterObject->NumberOfMapRegisters = 0;
1695         }
1696 
1697         /* Call the adapter control routine. */
1698         Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject,
1699                                                                     WaitContextBlock->CurrentIrp,
1700                                                                     AdapterObject->MapRegisterBase,
1701                                                                     WaitContextBlock->DeviceContext);
1702         switch (Result)
1703         {
1704             case KeepObject:
1705                 /*
1706                  * We're done until the caller manually calls IoFreeAdapterChannel
1707                  * or IoFreeMapRegisters.
1708                  */
1709                 return;
1710 
1711             case DeallocateObjectKeepRegisters:
1712                 /*
1713                  * Hide the map registers so they aren't deallocated next time
1714                  * around.
1715                  */
1716                 AdapterObject->NumberOfMapRegisters = 0;
1717                 break;
1718 
1719             default:
1720                 break;
1721         }
1722     }
1723 }
1724 
1725 /**
1726  * @name IoFreeMapRegisters
1727  *
1728  * Free map registers reserved by the system for a DMA.
1729  *
1730  * @param AdapterObject
1731  *        DMA adapter to free map registers on.
1732  * @param MapRegisterBase
1733  *        Handle to map registers to free.
1734  * @param NumberOfRegisters
1735  *        Number of map registers to be freed.
1736  *
1737  * @implemented
1738  */
1739 VOID
1740 NTAPI
1741 IoFreeMapRegisters(IN PADAPTER_OBJECT AdapterObject,
1742                    IN PVOID MapRegisterBase,
1743                    IN ULONG NumberOfMapRegisters)
1744 {
1745     PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter;
1746     PLIST_ENTRY ListEntry;
1747     KIRQL OldIrql;
1748     ULONG Index;
1749     ULONG Result;
1750 
1751     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1752 
1753     if (!(MasterAdapter) || !(MapRegisterBase)) return;
1754 
1755     KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
1756 
1757     if (NumberOfMapRegisters != 0)
1758     {
1759         PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
1760 
1761         RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
1762         RtlClearBits(MasterAdapter->MapRegisters,
1763                      (ULONG)(RealMapRegisterBase - MasterAdapter->MapRegisterBase),
1764                      NumberOfMapRegisters);
1765     }
1766 
1767     /*
1768      * Now that we freed few map registers it's time to look at the master
1769      * adapter queue and see if there is someone waiting for map registers.
1770      */
1771     while (!IsListEmpty(&MasterAdapter->AdapterQueue))
1772     {
1773         ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue);
1774         AdapterObject = CONTAINING_RECORD(ListEntry, struct _ADAPTER_OBJECT, AdapterQueue);
1775 
1776         Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters,
1777                                        AdapterObject->NumberOfMapRegisters,
1778                                        0);
1779         if (Index == MAXULONG)
1780         {
1781             InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry);
1782             break;
1783         }
1784 
1785         KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1786 
1787         AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index;
1788         if (!AdapterObject->ScatterGather)
1789         {
1790             AdapterObject->MapRegisterBase =
1791                 (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG);
1792         }
1793 
1794         Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(AdapterObject->CurrentWcb->DeviceObject,
1795                                                                              AdapterObject->CurrentWcb->CurrentIrp,
1796                                                                              AdapterObject->MapRegisterBase,
1797                                                                              AdapterObject->CurrentWcb->DeviceContext);
1798         switch (Result)
1799         {
1800             case DeallocateObjectKeepRegisters:
1801                 AdapterObject->NumberOfMapRegisters = 0;
1802                 /* fall through */
1803 
1804             case DeallocateObject:
1805                 if (AdapterObject->NumberOfMapRegisters)
1806                 {
1807                     KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
1808                     RtlClearBits(MasterAdapter->MapRegisters,
1809                                  (ULONG)(AdapterObject->MapRegisterBase -
1810                                          MasterAdapter->MapRegisterBase),
1811                                  AdapterObject->NumberOfMapRegisters);
1812                     KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1813                 }
1814 
1815                 IoFreeAdapterChannel(AdapterObject);
1816                 break;
1817 
1818             default:
1819                 break;
1820         }
1821 
1822         KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
1823     }
1824 
1825     KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
1826 }
1827 
1828 /**
1829  * @name HalpCopyBufferMap
1830  *
1831  * Helper function for copying data from/to map register buffers.
1832  *
1833  * @see IoFlushAdapterBuffers, IoMapTransfer
1834  */
1835 VOID
1836 NTAPI
1837 HalpCopyBufferMap(IN PMDL Mdl,
1838                   IN PROS_MAP_REGISTER_ENTRY MapRegisterBase,
1839                   IN PVOID CurrentVa,
1840                   IN ULONG Length,
1841                   IN BOOLEAN WriteToDevice)
1842 {
1843     ULONG CurrentLength;
1844     ULONG_PTR CurrentAddress;
1845     ULONG ByteOffset;
1846     PVOID VirtualAddress;
1847 
1848     VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority);
1849     if (!VirtualAddress)
1850     {
1851         /*
1852          * NOTE: On real NT a mechanism with reserved pages is implemented
1853          * to handle this case in a slow, but graceful non-fatal way.
1854          */
1855          KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0);
1856     }
1857 
1858     CurrentAddress = (ULONG_PTR)VirtualAddress +
1859                      (ULONG_PTR)CurrentVa -
1860                      (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
1861 
1862     while (Length > 0)
1863     {
1864         ByteOffset = BYTE_OFFSET(CurrentAddress);
1865         CurrentLength = PAGE_SIZE - ByteOffset;
1866         if (CurrentLength > Length) CurrentLength = Length;
1867 
1868         if (WriteToDevice)
1869         {
1870             RtlCopyMemory((PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
1871                           (PVOID)CurrentAddress,
1872                           CurrentLength);
1873         }
1874         else
1875         {
1876             RtlCopyMemory((PVOID)CurrentAddress,
1877                           (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset),
1878                           CurrentLength);
1879         }
1880 
1881         Length -= CurrentLength;
1882         CurrentAddress += CurrentLength;
1883         MapRegisterBase++;
1884     }
1885 }
1886 
1887 /**
1888  * @name IoFlushAdapterBuffers
1889  *
1890  * Flush any data remaining in the DMA controller's memory into the host
1891  * memory.
1892  *
1893  * @param AdapterObject
1894  *        The adapter object to flush.
1895  * @param Mdl
1896  *        Original MDL to flush data into.
1897  * @param MapRegisterBase
1898  *        Map register base that was just used by IoMapTransfer, etc.
1899  * @param CurrentVa
1900  *        Offset into Mdl to be flushed into, same as was passed to
1901  *        IoMapTransfer.
1902  * @param Length
1903  *        Length of the buffer to be flushed into.
1904  * @param WriteToDevice
1905  *        TRUE if it's a write, FALSE if it's a read.
1906  *
1907  * @return TRUE in all cases.
1908  *
1909  * @remarks
1910  *    This copies data from the map register-backed buffer to the user's
1911  *    target buffer. Data are not in the user buffer until this function
1912  *    is called.
1913  *    For slave DMA transfers the controller channel is masked effectively
1914  *    stopping the current transfer.
1915  *
1916  * @unimplemented.
1917  */
1918 BOOLEAN
1919 NTAPI
1920 IoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject,
1921                       IN PMDL Mdl,
1922                       IN PVOID MapRegisterBase,
1923                       IN PVOID CurrentVa,
1924                       IN ULONG Length,
1925                       IN BOOLEAN WriteToDevice)
1926 {
1927     BOOLEAN SlaveDma = FALSE;
1928     PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
1929     PHYSICAL_ADDRESS HighestAcceptableAddress;
1930     PHYSICAL_ADDRESS PhysicalAddress;
1931     PPFN_NUMBER MdlPagesPtr;
1932 
1933     /* Sanity checks */
1934     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1935     ASSERT(AdapterObject);
1936 
1937     if (!AdapterObject->MasterDevice)
1938     {
1939         /* Mask out (disable) the DMA channel. */
1940         if (AdapterObject->AdapterNumber == 1)
1941         {
1942             PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
1943             WRITE_PORT_UCHAR(&DmaControl1->SingleMask,
1944                              AdapterObject->ChannelNumber | DMA_SETMASK);
1945         }
1946         else
1947         {
1948             PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
1949             WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
1950                              AdapterObject->ChannelNumber | DMA_SETMASK);
1951         }
1952         SlaveDma = TRUE;
1953     }
1954 
1955     /* This can happen if the device supports hardware scatter/gather. */
1956     if (MapRegisterBase == NULL) return TRUE;
1957 
1958     RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
1959 
1960     if (!WriteToDevice)
1961     {
1962         if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG)
1963         {
1964             if (RealMapRegisterBase->Counter != MAXULONG)
1965             {
1966                 if ((SlaveDma) && !(AdapterObject->IgnoreCount))
1967                 {
1968                     Length -= HalReadDmaCounter(AdapterObject);
1969                 }
1970             }
1971             HalpCopyBufferMap(Mdl,
1972                               RealMapRegisterBase,
1973                               CurrentVa,
1974                               Length,
1975                               FALSE);
1976         }
1977         else
1978         {
1979             MdlPagesPtr = MmGetMdlPfnArray(Mdl);
1980             MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
1981 
1982             PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT;
1983             PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa);
1984 
1985             HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
1986             if ((PhysicalAddress.QuadPart + Length) > HighestAcceptableAddress.QuadPart)
1987             {
1988                 HalpCopyBufferMap(Mdl,
1989                                   RealMapRegisterBase,
1990                                   CurrentVa,
1991                                   Length,
1992                                   FALSE);
1993             }
1994         }
1995     }
1996 
1997     RealMapRegisterBase->Counter = 0;
1998 
1999     return TRUE;
2000 }
2001 
2002 /**
2003  * @name IoMapTransfer
2004  *
2005  * Map a DMA for transfer and do the DMA if it's a slave.
2006  *
2007  * @param AdapterObject
2008  *        Adapter object to do the DMA on. Bus-master may pass NULL.
2009  * @param Mdl
2010  *        Locked-down user buffer to DMA in to or out of.
2011  * @param MapRegisterBase
2012  *        Handle to map registers to use for this dma.
2013  * @param CurrentVa
2014  *        Index into Mdl to transfer into/out of.
2015  * @param Length
2016  *        Length of transfer. Number of bytes actually transferred on
2017  *        output.
2018  * @param WriteToDevice
2019  *        TRUE if it's an output DMA, FALSE otherwise.
2020  *
2021  * @return
2022  *    A logical address that can be used to program a DMA controller, it's
2023  *    not meaningful for slave DMA device.
2024  *
2025  * @remarks
2026  *    This function does a copyover to contiguous memory <16MB represented
2027  *    by the map registers if needed. If the buffer described by MDL can be
2028  *    used as is no copyover is done.
2029  *    If it's a slave transfer, this function actually performs it.
2030  *
2031  * @implemented
2032  */
2033 PHYSICAL_ADDRESS
2034 NTAPI
2035 IoMapTransfer(IN PADAPTER_OBJECT AdapterObject,
2036               IN PMDL Mdl,
2037               IN PVOID MapRegisterBase,
2038               IN PVOID CurrentVa,
2039               IN OUT PULONG Length,
2040               IN BOOLEAN WriteToDevice)
2041 {
2042     PPFN_NUMBER MdlPagesPtr;
2043     PFN_NUMBER MdlPage1, MdlPage2;
2044     ULONG ByteOffset;
2045     ULONG TransferOffset;
2046     ULONG TransferLength;
2047     BOOLEAN UseMapRegisters;
2048     PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
2049     PHYSICAL_ADDRESS PhysicalAddress;
2050     PHYSICAL_ADDRESS HighestAcceptableAddress;
2051     ULONG Counter;
2052     DMA_MODE AdapterMode;
2053     KIRQL OldIrql;
2054 
2055     /*
2056      * Precalculate some values that are used in all cases.
2057      *
2058      * ByteOffset is offset inside the page at which the transfer starts.
2059      * MdlPagesPtr is pointer inside the MDL page chain at the page where the
2060      *             transfer start.
2061      * PhysicalAddress is physical address corresponding to the transfer
2062      *                 start page and offset.
2063      * TransferLength is the initial length of the transfer, which is reminder
2064      *                of the first page. The actual value is calculated below.
2065      *
2066      * Note that all the variables can change during the processing which
2067      * takes place below. These are just initial values.
2068      */
2069     ByteOffset = BYTE_OFFSET(CurrentVa);
2070 
2071     MdlPagesPtr = MmGetMdlPfnArray(Mdl);
2072     MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
2073 
2074     PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT;
2075     PhysicalAddress.QuadPart += ByteOffset;
2076 
2077     TransferLength = PAGE_SIZE - ByteOffset;
2078 
2079     /*
2080      * Special case for bus master adapters with S/G support. We can directly
2081      * use the buffer specified by the MDL, so not much work has to be done.
2082      *
2083      * Just return the passed VA's corresponding physical address and update
2084      * length to the number of physically contiguous bytes found. Also
2085      * pages crossing the 4Gb boundary aren't considered physically contiguous.
2086      */
2087     if (MapRegisterBase == NULL)
2088     {
2089         while (TransferLength < *Length)
2090         {
2091             MdlPage1 = *MdlPagesPtr;
2092             MdlPage2 = *(MdlPagesPtr + 1);
2093             if (MdlPage1 + 1 != MdlPage2) break;
2094             if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) break;
2095             TransferLength += PAGE_SIZE;
2096             MdlPagesPtr++;
2097         }
2098 
2099         if (TransferLength < *Length) *Length = TransferLength;
2100 
2101         return PhysicalAddress;
2102     }
2103 
2104     /*
2105      * The code below applies to slave DMA adapters and bus master adapters
2106      * without hardward S/G support.
2107      */
2108     RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
2109 
2110     /*
2111      * Try to calculate the size of the transfer. We can only transfer
2112      * pages that are physically contiguous and that don't cross the
2113      * 64Kb boundary (this limitation applies only for ISA controllers).
2114      */
2115     while (TransferLength < *Length)
2116     {
2117         MdlPage1 = *MdlPagesPtr;
2118         MdlPage2 = *(MdlPagesPtr + 1);
2119         if (MdlPage1 + 1 != MdlPage2) break;
2120         if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) break;
2121         TransferLength += PAGE_SIZE;
2122         MdlPagesPtr++;
2123     }
2124 
2125     if (TransferLength > *Length) TransferLength = *Length;
2126 
2127     /*
2128      * If we're about to simulate software S/G and not all the pages are
2129      * physically contiguous then we must use the map registers to store
2130      * the data and allow the whole transfer to proceed at once.
2131      */
2132     if (((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) && (TransferLength < *Length))
2133     {
2134         UseMapRegisters = TRUE;
2135         PhysicalAddress = RealMapRegisterBase->PhysicalAddress;
2136         PhysicalAddress.QuadPart += ByteOffset;
2137         TransferLength = *Length;
2138         RealMapRegisterBase->Counter = MAXULONG;
2139         Counter = 0;
2140     }
2141     else
2142     {
2143         /*
2144          * This is ordinary DMA transfer, so just update the progress
2145          * counters. These are used by IoFlushAdapterBuffers to track
2146          * the transfer progress.
2147          */
2148         UseMapRegisters = FALSE;
2149         Counter = RealMapRegisterBase->Counter;
2150         RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength);
2151 
2152         /*
2153          * Check if the buffer doesn't exceed the highest physical address
2154          * limit of the device. In that case we must use the map registers to
2155          * store the data.
2156          */
2157         HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
2158         if ((PhysicalAddress.QuadPart + TransferLength) > HighestAcceptableAddress.QuadPart)
2159         {
2160             UseMapRegisters = TRUE;
2161             PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress;
2162             PhysicalAddress.QuadPart += ByteOffset;
2163             if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG)
2164             {
2165                 RealMapRegisterBase->Counter = MAXULONG;
2166                 Counter = 0;
2167             }
2168         }
2169     }
2170 
2171     /*
2172      * If we decided to use the map registers (see above) and we're about
2173      * to transfer data to the device then copy the buffers into the map
2174      * register memory.
2175      */
2176     if ((UseMapRegisters) && (WriteToDevice))
2177     {
2178         HalpCopyBufferMap(Mdl,
2179                           RealMapRegisterBase + Counter,
2180                           CurrentVa,
2181                           TransferLength,
2182                           WriteToDevice);
2183     }
2184 
2185     /*
2186      * Return the length of transfer that actually takes place.
2187      */
2188     *Length = TransferLength;
2189 
2190     /*
2191      * If we're doing slave (system) DMA then program the (E)ISA controller
2192      * to actually start the transfer.
2193      */
2194     if ((AdapterObject) && !(AdapterObject->MasterDevice))
2195     {
2196         AdapterMode = AdapterObject->AdapterMode;
2197 
2198         if (WriteToDevice)
2199         {
2200             AdapterMode.TransferType = WRITE_TRANSFER;
2201         }
2202         else
2203         {
2204             AdapterMode.TransferType = READ_TRANSFER;
2205             if (AdapterObject->IgnoreCount)
2206             {
2207                 RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + ByteOffset,
2208                               TransferLength);
2209             }
2210         }
2211 
2212         TransferOffset = PhysicalAddress.LowPart & 0xFFFF;
2213         if (AdapterObject->Width16Bits)
2214         {
2215             TransferLength >>= 1;
2216             TransferOffset >>= 1;
2217         }
2218 
2219         KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
2220 
2221         if (AdapterObject->AdapterNumber == 1)
2222         {
2223             PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
2224 
2225             /* Reset Register */
2226             WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
2227 
2228             /* Set the Mode */
2229             WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte);
2230 
2231             /* Set the Offset Register */
2232             WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
2233                              (UCHAR)(TransferOffset));
2234             WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
2235                              (UCHAR)(TransferOffset >> 8));
2236 
2237             /* Set the Page Register */
2238             WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
2239                              (UCHAR)(PhysicalAddress.LowPart >> 16));
2240             if (HalpEisaDma)
2241             {
2242                 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
2243                                  0);
2244             }
2245 
2246             /* Set the Length */
2247             WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
2248                              (UCHAR)(TransferLength - 1));
2249             WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
2250                              (UCHAR)((TransferLength - 1) >> 8));
2251 
2252             /* Unmask the Channel */
2253             WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK);
2254         }
2255         else
2256         {
2257             PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
2258 
2259             /* Reset Register */
2260             WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
2261 
2262             /* Set the Mode */
2263             WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte);
2264 
2265             /* Set the Offset Register */
2266             WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
2267                              (UCHAR)(TransferOffset));
2268             WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress,
2269                              (UCHAR)(TransferOffset >> 8));
2270 
2271             /* Set the Page Register */
2272             WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages),
2273                              (UCHAR)(PhysicalAddress.u.LowPart >> 16));
2274             if (HalpEisaDma)
2275             {
2276                 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages),
2277                                  0);
2278             }
2279 
2280             /* Set the Length */
2281             WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
2282                              (UCHAR)(TransferLength - 1));
2283             WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
2284                              (UCHAR)((TransferLength - 1) >> 8));
2285 
2286             /* Unmask the Channel */
2287             WRITE_PORT_UCHAR(&DmaControl2->SingleMask,
2288                              AdapterObject->ChannelNumber | DMA_CLEARMASK);
2289         }
2290 
2291         KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
2292     }
2293 
2294     /*
2295      * Return physical address of the buffer with data that is used for the
2296      * transfer. It can either point inside the Mdl that was passed by the
2297      * caller or into the map registers if the Mdl buffer can't be used
2298      * directly.
2299      */
2300      return PhysicalAddress;
2301 }
2302 #endif
2303 
2304 /**
2305  * @name HalFlushCommonBuffer
2306  *
2307  * @implemented
2308  */
2309 BOOLEAN
2310 NTAPI
2311 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject,
2312                      IN ULONG Length,
2313                      IN PHYSICAL_ADDRESS LogicalAddress,
2314                      IN PVOID VirtualAddress)
2315 {
2316     /* Function always returns true */
2317     return TRUE;
2318 }
2319 
2320 /*
2321  * @implemented
2322  */
2323 PVOID
2324 NTAPI
2325 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject,
2326                               IN OUT PULONG NumberOfMapRegisters)
2327 {
2328     PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter;
2329     ULONG MapRegisterNumber;
2330 
2331     /* Check if it needs map registers */
2332     if (AdapterObject->NeedsMapRegisters)
2333     {
2334         /* Check if we have enough */
2335         if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)
2336         {
2337             /* We don't, fail */
2338             AdapterObject->NumberOfMapRegisters = 0;
2339             return NULL;
2340         }
2341 
2342         /* Try to find free map registers */
2343         MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters,
2344                                                    *NumberOfMapRegisters,
2345                                                    0);
2346 
2347         /* Check if nothing was found */
2348         if (MapRegisterNumber == MAXULONG)
2349         {
2350             /* No free registers found, so use the base registers */
2351             RtlSetBits(MasterAdapter->MapRegisters,
2352                        0,
2353                        *NumberOfMapRegisters);
2354             MapRegisterNumber = 0;
2355         }
2356 
2357         /* Calculate the new base */
2358         AdapterObject->MapRegisterBase =
2359             (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase +
2360                                       MapRegisterNumber);
2361 
2362         /* Check if scatter gather isn't supported */
2363         if (!AdapterObject->ScatterGather)
2364         {
2365             /* Set the flag */
2366             AdapterObject->MapRegisterBase =
2367                 (PROS_MAP_REGISTER_ENTRY)
2368                 ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG);
2369         }
2370     }
2371     else
2372     {
2373         AdapterObject->MapRegisterBase = NULL;
2374         AdapterObject->NumberOfMapRegisters = 0;
2375     }
2376 
2377     /* Return the base */
2378     return AdapterObject->MapRegisterBase;
2379 }
2380 
2381 /* EOF */
2382