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