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