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