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