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