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