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