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