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