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