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