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