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