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