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)
14 * @page DMA Implementation Notes
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
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.
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.
38 * - Bus-master / Slave DMA
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
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
51 * - Allocation of map registers
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:
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.
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.
72 /* INCLUDES *****************************************************************/
78 static KEVENT HalpDmaLock
;
79 static LIST_ENTRY HalpDmaAdapterList
;
80 static PADAPTER_OBJECT HalpEisaAdapter
[8];
81 static BOOLEAN HalpEisaDma
;
82 static PADAPTER_OBJECT HalpMasterAdapter
;
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
),
90 FIELD_OFFSET(DMA_PAGE
, Channel5
),
91 FIELD_OFFSET(DMA_PAGE
, Channel6
),
92 FIELD_OFFSET(DMA_PAGE
, Channel7
)
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*/
115 #define MAX_MAP_REGISTERS 64
117 #define TAG_DMA TAG('D','M','A',' ')
119 /* FUNCTIONS *****************************************************************/
125 * Check if Extended DMA is available. We're just going to do a random
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)
134 * Intialize all the global variables and allocate master adapter with
138 InitializeListHead(&HalpDmaAdapterList
);
139 KeInitializeEvent(&HalpDmaLock
, NotificationEvent
, TRUE
);
141 HalpMasterAdapter
= HalpDmaAllocateMasterAdapter();
144 * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's
145 * used by IoGetDmaAdapter in the kernel.
148 HalGetDmaAdapter
= HalpGetDmaAdapter
;
152 * @name HalpGetAdapterMaximumPhysicalAddress
154 * Get the maximum physical address acceptable by the device represented
155 * by the passed DMA adapter.
158 PHYSICAL_ADDRESS STDCALL
159 HalpGetAdapterMaximumPhysicalAddress(
160 IN PADAPTER_OBJECT AdapterObject
)
162 PHYSICAL_ADDRESS HighestAddress
;
164 if (AdapterObject
->MasterDevice
)
166 if (AdapterObject
->Dma64BitAddresses
)
168 HighestAddress
.QuadPart
= 0xFFFFFFFFFFFFFFFFULL
;
169 return HighestAddress
;
171 else if (AdapterObject
->Dma32BitAddresses
)
173 HighestAddress
.QuadPart
= 0xFFFFFFFF;
174 return HighestAddress
;
178 HighestAddress
.QuadPart
= 0xFFFFFF;
179 return HighestAddress
;
183 * @name HalpGrowMapBuffers
185 * Allocate initial, or additional, map buffers for DMA master adapter.
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).
196 IN PADAPTER_OBJECT AdapterObject
,
197 IN ULONG SizeOfMapBuffers
)
199 PVOID VirtualAddress
;
200 PHYSICAL_ADDRESS PhysicalAddress
;
201 PHYSICAL_ADDRESS HighestAcceptableAddress
;
202 PHYSICAL_ADDRESS LowestAcceptableAddress
;
203 PHYSICAL_ADDRESS BoundryAddressMultiple
;
205 ULONG MapRegisterCount
;
207 /* FIXME: Check if enough map register slots are available. */
209 MapRegisterCount
= BYTES_TO_PAGES(SizeOfMapBuffers
);
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).
216 HighestAcceptableAddress
=
217 HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
218 LowestAcceptableAddress
.HighPart
= 0;
219 LowestAcceptableAddress
.LowPart
=
220 HighestAcceptableAddress
.LowPart
== 0xFFFFFFFF ? 0x1000000 : 0;
221 BoundryAddressMultiple
.QuadPart
= 0;
223 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
224 MapRegisterCount
<< PAGE_SHIFT
, LowestAcceptableAddress
,
225 HighestAcceptableAddress
, BoundryAddressMultiple
, MmNonCached
);
227 if (VirtualAddress
== NULL
&& LowestAcceptableAddress
.LowPart
!= 0)
229 LowestAcceptableAddress
.LowPart
= 0;
230 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
231 MapRegisterCount
<< PAGE_SHIFT
, LowestAcceptableAddress
,
232 HighestAcceptableAddress
, BoundryAddressMultiple
, MmNonCached
);
235 if (VirtualAddress
== NULL
)
238 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
241 * All the following must be done with the master adapter lock held
242 * to prevent corruption.
245 OldIrql
= KfAcquireSpinLock(&AdapterObject
->SpinLock
);
248 * Setup map register entries for the buffer allocated. Each entry has
249 * a virtual and physical address and corresponds to PAGE_SIZE large
253 if (MapRegisterCount
> 0)
255 PROS_MAP_REGISTER_ENTRY CurrentEntry
, PreviousEntry
;
257 CurrentEntry
= AdapterObject
->MapRegisterBase
+
258 AdapterObject
->NumberOfMapRegisters
;
262 * Leave one entry free for every non-contiguous memory region
263 * in the map register bitmap. This ensures that we can search
264 * using RtlFindClearBits for contiguous map register regions.
266 * Also for non-EISA DMA leave one free entry for every 64Kb
267 * break, because the DMA controller can handle only coniguous
271 if (CurrentEntry
!= AdapterObject
->MapRegisterBase
)
273 PreviousEntry
= CurrentEntry
- 1;
274 if (PreviousEntry
->PhysicalAddress
.LowPart
+ PAGE_SIZE
==
275 PhysicalAddress
.LowPart
)
279 if ((PreviousEntry
->PhysicalAddress
.LowPart
^
280 PhysicalAddress
.LowPart
) & 0xFFFF0000)
283 AdapterObject
->NumberOfMapRegisters
++;
290 AdapterObject
->NumberOfMapRegisters
++;
294 RtlClearBit(AdapterObject
->MapRegisters
,
295 CurrentEntry
- AdapterObject
->MapRegisterBase
);
296 CurrentEntry
->VirtualAddress
= VirtualAddress
;
297 CurrentEntry
->PhysicalAddress
= PhysicalAddress
;
299 PhysicalAddress
.LowPart
+= PAGE_SIZE
;
300 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
303 AdapterObject
->NumberOfMapRegisters
++;
306 while (MapRegisterCount
!= 0);
309 KfReleaseSpinLock(&AdapterObject
->SpinLock
, OldIrql
);
315 * @name HalpDmaAllocateMasterAdapter
317 * Helper routine to allocate and initialize master adapter object and it's
318 * associated map register buffers.
323 PADAPTER_OBJECT STDCALL
324 HalpDmaAllocateMasterAdapter(VOID
)
326 PADAPTER_OBJECT MasterAdapter
;
327 ULONG Size
, SizeOfBitmap
;
329 SizeOfBitmap
= MAX_MAP_REGISTERS
;
330 Size
= sizeof(ADAPTER_OBJECT
);
331 Size
+= sizeof(RTL_BITMAP
);
332 Size
+= (SizeOfBitmap
+ 7) >> 3;
334 MasterAdapter
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_DMA
);
335 if (MasterAdapter
== NULL
)
338 RtlZeroMemory(MasterAdapter
, Size
);
340 KeInitializeSpinLock(&MasterAdapter
->SpinLock
);
341 InitializeListHead(&MasterAdapter
->AdapterQueue
);
343 MasterAdapter
->MapRegisters
= (PVOID
)(MasterAdapter
+ 1);
345 MasterAdapter
->MapRegisters
,
346 (PULONG
)(MasterAdapter
->MapRegisters
+ 1),
348 RtlSetAllBits(MasterAdapter
->MapRegisters
);
349 MasterAdapter
->NumberOfMapRegisters
= 0;
350 MasterAdapter
->CommittedMapRegisters
= 0;
352 MasterAdapter
->MapRegisterBase
= ExAllocatePoolWithTag(
354 SizeOfBitmap
* sizeof(ROS_MAP_REGISTER_ENTRY
),
356 if (MasterAdapter
->MapRegisterBase
== NULL
)
358 ExFreePool(MasterAdapter
);
362 RtlZeroMemory(MasterAdapter
->MapRegisterBase
,
363 SizeOfBitmap
* sizeof(ROS_MAP_REGISTER_ENTRY
));
364 if (!HalpGrowMapBuffers(MasterAdapter
, 0x10000))
366 ExFreePool(MasterAdapter
);
370 return MasterAdapter
;
374 * @name HalpDmaAllocateChildAdapter
376 * Helper routine of HalGetAdapter. Allocate child adapter object and
377 * fill out some basic fields.
382 PADAPTER_OBJECT STDCALL
383 HalpDmaAllocateChildAdapter(
384 ULONG NumberOfMapRegisters
,
385 PDEVICE_DESCRIPTION DeviceDescription
)
387 PADAPTER_OBJECT AdapterObject
;
388 OBJECT_ATTRIBUTES ObjectAttributes
;
392 InitializeObjectAttributes(
395 OBJ_KERNEL_HANDLE
| OBJ_PERMANENT
,
399 Status
= ObCreateObject(
405 sizeof(ADAPTER_OBJECT
),
408 (PVOID
)&AdapterObject
);
409 if (!NT_SUCCESS(Status
))
412 Status
= ObReferenceObjectByPointer(
414 FILE_READ_DATA
| FILE_WRITE_DATA
,
417 if (!NT_SUCCESS(Status
))
420 RtlZeroMemory(AdapterObject
, sizeof(ADAPTER_OBJECT
));
422 Status
= ObInsertObject(
425 FILE_READ_DATA
| FILE_WRITE_DATA
,
429 if (!NT_SUCCESS(Status
))
434 AdapterObject
->DmaHeader
.Version
= DeviceDescription
->Version
;
435 AdapterObject
->DmaHeader
.Size
= sizeof(ADAPTER_OBJECT
);
436 AdapterObject
->DmaHeader
.DmaOperations
= &HalpDmaOperations
;
437 AdapterObject
->MapRegistersPerChannel
= 1;
438 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
439 AdapterObject
->ChannelNumber
= 0xFF;
440 AdapterObject
->MasterAdapter
= HalpMasterAdapter
;
441 KeInitializeDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
443 return AdapterObject
;
447 * @name HalpDmaInitializeEisaAdapter
449 * Setup DMA modes and extended modes for (E)ISA DMA adapter object.
453 HalpDmaInitializeEisaAdapter(
454 PADAPTER_OBJECT AdapterObject
,
455 PDEVICE_DESCRIPTION DeviceDescription
)
458 DMA_MODE DmaMode
= {{0 }};
459 DMA_EXTENDED_MODE ExtendedMode
= {{ 0 }};
462 Controller
= (DeviceDescription
->DmaChannel
& 4) ? 2 : 1;
465 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController1
);
467 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController2
);
469 AdapterObject
->AdapterNumber
= Controller
;
470 AdapterObject
->ChannelNumber
= DeviceDescription
->DmaChannel
& 3;
471 AdapterObject
->PagePort
= (PUCHAR
)HalpEisaPortPage
[DeviceDescription
->DmaChannel
];
472 AdapterObject
->Width16Bits
= FALSE
;
473 AdapterObject
->AdapterBaseVa
= AdapterBaseVa
;
477 ExtendedMode
.ChannelNumber
= AdapterObject
->ChannelNumber
;
479 switch (DeviceDescription
->DmaSpeed
)
481 case Compatible
: ExtendedMode
.TimingMode
= COMPATIBLE_TIMING
; break;
482 case TypeA
: ExtendedMode
.TimingMode
= TYPE_A_TIMING
; break;
483 case TypeB
: ExtendedMode
.TimingMode
= TYPE_B_TIMING
; break;
484 case TypeC
: ExtendedMode
.TimingMode
= BURST_TIMING
; break;
489 switch (DeviceDescription
->DmaWidth
)
491 case Width8Bits
: ExtendedMode
.TransferSize
= B_8BITS
; break;
492 case Width16Bits
: ExtendedMode
.TransferSize
= B_16BITS
; break;
493 case Width32Bits
: ExtendedMode
.TransferSize
= B_32BITS
; break;
499 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode1
),
502 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode2
),
508 * Validate setup for non-busmaster DMA adapter. Secondary controller
509 * supports only 16-bit transfers and main controller supports only
510 * 8-bit transfers. Anything else is invalid.
513 if (!DeviceDescription
->Master
)
515 if (Controller
== 2 && DeviceDescription
->DmaWidth
== Width16Bits
)
516 AdapterObject
->Width16Bits
= TRUE
;
517 else if (Controller
!= 1 || DeviceDescription
->DmaWidth
!= Width8Bits
)
522 DmaMode
.Channel
= AdapterObject
->ChannelNumber
;
523 DmaMode
.AutoInitialize
= DeviceDescription
->AutoInitialize
;
526 * Set the DMA request mode.
528 * For (E)ISA bus master devices just unmask (enable) the DMA channel
529 * and set it to cascade mode. Otherwise just select the right one
530 * bases on the passed device description.
533 if (DeviceDescription
->Master
)
535 DmaMode
.RequestMode
= CASCADE_REQUEST_MODE
;
538 /* Set the Request Data */
539 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->Mode
,
541 /* Unmask DMA Channel */
542 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->SingleMask
,
543 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
545 /* Set the Request Data */
546 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->Mode
,
548 /* Unmask DMA Channel */
549 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->SingleMask
,
550 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
555 if (DeviceDescription
->DemandMode
)
556 DmaMode
.RequestMode
= DEMAND_REQUEST_MODE
;
558 DmaMode
.RequestMode
= SINGLE_REQUEST_MODE
;
561 AdapterObject
->AdapterMode
= DmaMode
;
567 * @name HalGetAdapter
569 * Allocate an adapter object for DMA device.
571 * @param DeviceDescription
572 * Structure describing the attributes of the device.
573 * @param NumberOfMapRegisters
574 * On return filled with the maximum number of map registers the
575 * device driver can allocate for DMA transfer operations.
577 * @return The DMA adapter on success, NULL otherwise.
582 PADAPTER_OBJECT STDCALL
584 PDEVICE_DESCRIPTION DeviceDescription
,
585 PULONG NumberOfMapRegisters
)
587 PADAPTER_OBJECT AdapterObject
= NULL
;
588 PADAPTER_OBJECT MasterAdapter
;
593 /* Validate parameters in device description */
594 if (DeviceDescription
->Version
> DEVICE_DESCRIPTION_VERSION2
)
598 * See if we're going to use ISA/EISA DMA adapter. These adapters are
599 * special since they're reused.
601 * Also note that we check for channel number since there are only 8 DMA
602 * channels on ISA, so any request above this requires new adapter.
605 if (DeviceDescription
->InterfaceType
== Isa
|| !DeviceDescription
->Master
)
607 if (DeviceDescription
->InterfaceType
== Isa
&&
608 DeviceDescription
->DmaChannel
>= 8)
619 * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
620 * for cascading the controllers and it's not available for software use.
623 if (EisaAdapter
&& DeviceDescription
->DmaChannel
== 4)
627 * Calculate the number of map registers.
629 * - For EISA and PCI scatter/gather no map registers are needed.
630 * - For ISA slave scatter/gather one map register is needed.
631 * - For all other cases the number of map registers depends on
632 * DeviceDescription->MaximumLength.
635 MaximumLength
= DeviceDescription
->MaximumLength
& MAXLONG
;
636 if (DeviceDescription
->ScatterGather
&&
637 (DeviceDescription
->InterfaceType
== Eisa
||
638 DeviceDescription
->InterfaceType
== PCIBus
))
642 else if (DeviceDescription
->ScatterGather
&&
643 !DeviceDescription
->Master
)
650 * In the equation below the additional map register added by
651 * the "+1" accounts for the case when a transfer does not start
652 * at a page-aligned address.
654 MapRegisters
= BYTES_TO_PAGES(MaximumLength
) + 1;
655 if (MapRegisters
> 16)
660 * Acquire the DMA lock that is used to protect adapter lists and
661 * EISA adapter array.
664 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
668 * Now we must get ahold of the adapter object. For first eight ISA/EISA
669 * channels there are static adapter objects that are reused and updated
670 * on succesive HalGetAdapter calls. In other cases a new adapter object
671 * is always created and it's to the DMA adapter list (HalpDmaAdapterList).
676 AdapterObject
= HalpEisaAdapter
[DeviceDescription
->DmaChannel
];
677 if (AdapterObject
!= NULL
)
679 if (AdapterObject
->NeedsMapRegisters
&&
680 MapRegisters
> AdapterObject
->MapRegistersPerChannel
)
681 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
685 if (AdapterObject
== NULL
)
687 AdapterObject
= HalpDmaAllocateChildAdapter(
688 MapRegisters
, DeviceDescription
);
689 if (AdapterObject
== NULL
)
691 KeSetEvent(&HalpDmaLock
, 0, 0);
697 HalpEisaAdapter
[DeviceDescription
->DmaChannel
] = AdapterObject
;
700 if (MapRegisters
> 0)
702 AdapterObject
->NeedsMapRegisters
= TRUE
;
703 MasterAdapter
= HalpMasterAdapter
;
704 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
707 * FIXME: Verify that the following makes sense. Actually
708 * MasterAdapter->NumberOfMapRegisters contains even the number
709 * of gaps, so this will not work correctly all the time. It
710 * doesn't matter much since it's only optimization to avoid
711 * queuing work items in HalAllocateAdapterChannel.
714 MasterAdapter
->CommittedMapRegisters
+= MapRegisters
;
715 if (MasterAdapter
->CommittedMapRegisters
> MasterAdapter
->NumberOfMapRegisters
)
716 HalpGrowMapBuffers(MasterAdapter
, 0x10000);
720 AdapterObject
->NeedsMapRegisters
= FALSE
;
721 if (DeviceDescription
->Master
)
722 AdapterObject
->MapRegistersPerChannel
= BYTES_TO_PAGES(MaximumLength
) + 1;
724 AdapterObject
->MapRegistersPerChannel
= 1;
729 InsertTailList(&HalpDmaAdapterList
, &AdapterObject
->AdapterList
);
732 * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
733 * no longer be touched, so we don't need it.
736 KeSetEvent(&HalpDmaLock
, 0, 0);
739 * Setup the values in the adapter object that are common for all
743 if (DeviceDescription
->Version
>= DEVICE_DESCRIPTION_VERSION1
)
744 AdapterObject
->IgnoreCount
= DeviceDescription
->IgnoreCount
;
746 AdapterObject
->IgnoreCount
= 0;
748 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
749 AdapterObject
->Dma64BitAddresses
= DeviceDescription
->Dma64BitAddresses
;
750 AdapterObject
->ScatterGather
= DeviceDescription
->ScatterGather
;
751 AdapterObject
->MasterDevice
= DeviceDescription
->Master
;
752 *NumberOfMapRegisters
= AdapterObject
->MapRegistersPerChannel
;
755 * For non-(E)ISA adapters we have already done all the work. On the
756 * other hand for (E)ISA adapters we must still setup the DMA modes
757 * and prepare the controller.
762 if (!HalpDmaInitializeEisaAdapter(AdapterObject
, DeviceDescription
))
764 ObfDereferenceObject(AdapterObject
);
769 return AdapterObject
;
773 * @name HalpGetDmaAdapter
775 * Internal routine to allocate PnP DMA adapter object. It's exported through
776 * HalDispatchTable and used by IoGetDmaAdapter.
784 IN PDEVICE_DESCRIPTION DeviceDescription
,
785 OUT PULONG NumberOfMapRegisters
)
787 return &HalGetAdapter(DeviceDescription
, NumberOfMapRegisters
)->DmaHeader
;
791 * @name HalPutDmaAdapter
793 * Internal routine to free DMA adapter and resources for reuse. It's exported
794 * using the DMA_OPERATIONS interface by HalGetAdapter.
801 PADAPTER_OBJECT AdapterObject
)
803 if (AdapterObject
->ChannelNumber
== 0xFF)
805 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
807 RemoveEntryList(&AdapterObject
->AdapterList
);
808 KeSetEvent(&HalpDmaLock
, 0, 0);
811 ObfDereferenceObject(AdapterObject
);
815 * @name HalAllocateCommonBuffer
817 * Allocates memory that is visible to both the processor(s) and the DMA
820 * @param AdapterObject
821 * Adapter object representing the bus master or system dma controller.
823 * Number of bytes to allocate.
824 * @param LogicalAddress
825 * Logical address the driver can use to access the buffer.
826 * @param CacheEnabled
827 * Specifies if the memory can be cached.
829 * @return The base virtual address of the memory allocated or NULL on failure.
832 * On real NT x86 systems the CacheEnabled parameter is ignored, we honour
833 * it. If it proves to cause problems change it.
835 * @see HalFreeCommonBuffer
841 HalAllocateCommonBuffer(
842 PADAPTER_OBJECT AdapterObject
,
844 PPHYSICAL_ADDRESS LogicalAddress
,
845 BOOLEAN CacheEnabled
)
847 PHYSICAL_ADDRESS LowestAcceptableAddress
;
848 PHYSICAL_ADDRESS HighestAcceptableAddress
;
849 PHYSICAL_ADDRESS BoundryAddressMultiple
;
850 PVOID VirtualAddress
;
852 LowestAcceptableAddress
.QuadPart
= 0;
853 HighestAcceptableAddress
=
854 HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
855 BoundryAddressMultiple
.QuadPart
= 0;
858 * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
859 * slave DMA devices the 64Kb boundary mustn't be crossed since the
860 * controller wouldn't be able to handle it.
863 if (AdapterObject
->MasterDevice
)
864 BoundryAddressMultiple
.HighPart
= 1;
866 BoundryAddressMultiple
.LowPart
= 0x10000;
868 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
869 Length
, LowestAcceptableAddress
, HighestAcceptableAddress
,
870 BoundryAddressMultiple
, CacheEnabled
? MmCached
: MmNonCached
);
871 if (VirtualAddress
== NULL
)
874 *LogicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
876 return VirtualAddress
;
880 * @name HalFreeCommonBuffer
882 * Free common buffer allocated with HalAllocateCommonBuffer.
884 * @see HalAllocateCommonBuffer
891 PADAPTER_OBJECT AdapterObject
,
893 PHYSICAL_ADDRESS LogicalAddress
,
894 PVOID VirtualAddress
,
895 BOOLEAN CacheEnabled
)
897 MmFreeContiguousMemory(VirtualAddress
);
901 * @name HalpDmaGetDmaAlignment
903 * Internal routine to return the DMA alignment requirement. It's exported
904 * using the DMA_OPERATIONS interface by HalGetAdapter.
910 HalpDmaGetDmaAlignment(
911 PADAPTER_OBJECT AdapterObject
)
917 * @name HalReadDmaCounter
919 * Read DMA operation progress counter.
926 PADAPTER_OBJECT AdapterObject
)
929 ULONG Count
, OldCount
;
931 ASSERT(!AdapterObject
->MasterDevice
);
934 * Acquire the master adapter lock since we're going to mess with the
935 * system DMA controller registers and we really don't want anyone
936 * to do the same at the same time.
939 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
941 /* Send the request to the specific controller. */
942 if (AdapterObject
->AdapterNumber
== 1)
944 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
951 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
953 Count
= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
954 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
955 Count
|= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
956 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
958 while (0xffff00 & (OldCount
^ Count
));
962 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
969 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
971 Count
= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
972 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
973 Count
|= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
974 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
976 while (0xffff00 & (OldCount
^ Count
));
979 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
983 if (AdapterObject
->Width16Bits
)
990 * @name HalpGrowMapBufferWorker
992 * Helper routine of HalAllocateAdapterChannel for allocating map registers
993 * at PASSIVE_LEVEL in work item.
997 HalpGrowMapBufferWorker(PVOID DeferredContext
)
999 PGROW_WORK_ITEM WorkItem
= (PGROW_WORK_ITEM
)DeferredContext
;
1004 * Try to allocate new map registers for the adapter.
1006 * NOTE: The NT implementation actually tries to allocate more map
1007 * registers than needed as an optimization.
1010 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
1012 Succeeded
= HalpGrowMapBuffers(WorkItem
->AdapterObject
->MasterAdapter
,
1013 WorkItem
->NumberOfMapRegisters
);
1014 KeSetEvent(&HalpDmaLock
, 0, 0);
1019 * Flush the adapter queue now that new map registers are ready. The
1020 * easiest way to do that is to call IoFreeMapRegisters to not free
1021 * any registers. Note that we use the magic (PVOID)2 map register
1022 * base to bypass the parameter checking.
1025 OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1026 IoFreeMapRegisters(WorkItem
->AdapterObject
, (PVOID
)2, 0);
1027 KfLowerIrql(OldIrql
);
1030 ExFreePool(WorkItem
);
1034 * @name HalAllocateAdapterChannel
1036 * Setup map registers for an adapter object.
1038 * @param AdapterObject
1039 * Pointer to an ADAPTER_OBJECT to set up.
1040 * @param WaitContextBlock
1041 * Context block to be used with ExecutionRoutine.
1042 * @param NumberOfMapRegisters
1043 * Number of map registers requested.
1044 * @param ExecutionRoutine
1045 * Callback to call when map registers are allocated.
1048 * If not enough map registers can be allocated then
1049 * STATUS_INSUFFICIENT_RESOURCES is returned. If the function
1050 * succeeds or the callback is queued for later delivering then
1051 * STATUS_SUCCESS is returned.
1053 * @see IoFreeAdapterChannel
1059 HalAllocateAdapterChannel(
1060 PADAPTER_OBJECT AdapterObject
,
1061 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
1062 ULONG NumberOfMapRegisters
,
1063 PDRIVER_CONTROL ExecutionRoutine
)
1065 PADAPTER_OBJECT MasterAdapter
;
1066 PGROW_WORK_ITEM WorkItem
;
1071 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1073 /* Set up the wait context block in case we can't run right away. */
1074 WaitContextBlock
->DeviceRoutine
= ExecutionRoutine
;
1075 WaitContextBlock
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1077 /* Returns true if queued, else returns false and sets the queue to busy */
1078 if (KeInsertDeviceQueue(&AdapterObject
->ChannelWaitQueue
, &WaitContextBlock
->WaitQueueEntry
))
1079 return STATUS_SUCCESS
;
1081 MasterAdapter
= AdapterObject
->MasterAdapter
;
1083 AdapterObject
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1084 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1086 if (NumberOfMapRegisters
&& AdapterObject
->NeedsMapRegisters
)
1088 if (NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)
1090 AdapterObject
->NumberOfMapRegisters
= 0;
1091 IoFreeAdapterChannel(AdapterObject
);
1092 return STATUS_INSUFFICIENT_RESOURCES
;
1096 * Get the map registers. This is partly complicated by the fact
1097 * that new map registers can only be allocated at PASSIVE_LEVEL
1098 * and we're currently at DISPATCH_LEVEL. The following code has
1101 * - If there is no adapter queued for map register allocation,
1102 * try to see if enough contiguous map registers are present.
1103 * In case they're we can just get them and proceed further.
1105 * - If some adapter is already present in the queue we must
1106 * respect the order of adapters asking for map registers and
1107 * so the fast case described above can't take place.
1108 * This case is also entered if not enough coniguous map
1109 * registers are present.
1111 * A work queue item is allocated and queued, the adapter is
1112 * also queued into the master adapter queue. The worker
1113 * routine does the job of allocating the map registers at
1114 * PASSIVE_LEVEL and calling the ExecutionRoutine.
1117 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1119 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1121 Index
= RtlFindClearBitsAndSet(
1122 MasterAdapter
->MapRegisters
, NumberOfMapRegisters
, 0);
1125 AdapterObject
->MapRegisterBase
=
1126 MasterAdapter
->MapRegisterBase
+ Index
;
1127 if (!AdapterObject
->ScatterGather
)
1129 AdapterObject
->MapRegisterBase
=
1130 (PROS_MAP_REGISTER_ENTRY
)(
1131 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1139 WorkItem
= ExAllocatePoolWithTag(
1140 NonPagedPool
, sizeof(GROW_WORK_ITEM
), TAG_DMA
);
1141 if (WorkItem
== NULL
)
1143 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1144 AdapterObject
->NumberOfMapRegisters
= 0;
1145 IoFreeAdapterChannel(AdapterObject
);
1146 return STATUS_INSUFFICIENT_RESOURCES
;
1149 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1151 ExInitializeWorkItem(
1152 &WorkItem
->WorkQueueItem
, HalpGrowMapBufferWorker
, WorkItem
);
1153 WorkItem
->AdapterObject
= AdapterObject
;
1154 WorkItem
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1156 ExQueueWorkItem(&WorkItem
->WorkQueueItem
, DelayedWorkQueue
);
1158 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1160 return STATUS_SUCCESS
;
1163 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1167 AdapterObject
->MapRegisterBase
= NULL
;
1168 AdapterObject
->NumberOfMapRegisters
= 0;
1171 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1173 Result
= ExecutionRoutine(
1174 WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
1175 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
1178 * Possible return values:
1181 * Don't free any resources, the ADAPTER_OBJECT is still in use and
1182 * the caller will call IoFreeAdapterChannel later.
1184 * - DeallocateObject
1185 * Deallocate the map registers and release the ADAPTER_OBJECT, so
1186 * someone else can use it.
1188 * - DeallocateObjectKeepRegisters
1189 * Release the ADAPTER_OBJECT, but hang on to the map registers. The
1190 * client will later call IoFreeMapRegisters.
1193 * IoFreeAdapterChannel runs the queue, so it must be called unless
1194 * the adapter object is not to be freed.
1197 if (Result
== DeallocateObject
)
1199 IoFreeAdapterChannel(AdapterObject
);
1201 else if (Result
== DeallocateObjectKeepRegisters
)
1203 AdapterObject
->NumberOfMapRegisters
= 0;
1204 IoFreeAdapterChannel(AdapterObject
);
1207 return STATUS_SUCCESS
;
1211 * @name IoFreeAdapterChannel
1213 * Free DMA resources allocated by IoAllocateAdapterChannel.
1215 * @param AdapterObject
1216 * Adapter object with resources to free.
1219 * This function releases map registers registers assigned to the DMA
1220 * adapter. After releasing the adapter, it checks the adapter's queue
1221 * and runs each queued device object in series until the queue is
1222 * empty. This is the only way the device queue is emptied.
1224 * @see IoAllocateAdapterChannel
1230 IoFreeAdapterChannel(
1231 PADAPTER_OBJECT AdapterObject
)
1233 PADAPTER_OBJECT MasterAdapter
;
1234 PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
;
1235 PWAIT_CONTEXT_BLOCK WaitContextBlock
;
1240 MasterAdapter
= AdapterObject
->MasterAdapter
;
1245 * To keep map registers, call here with AdapterObject->
1246 * NumberOfMapRegisters set to zero. This trick is used in
1247 * HalAllocateAdapterChannel for example.
1249 if (AdapterObject
->NumberOfMapRegisters
)
1253 AdapterObject
->MapRegisterBase
,
1254 AdapterObject
->NumberOfMapRegisters
);
1257 DeviceQueueEntry
= KeRemoveDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
1258 if (DeviceQueueEntry
== NULL
)
1263 WaitContextBlock
= CONTAINING_RECORD(
1268 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1269 AdapterObject
->NumberOfMapRegisters
= WaitContextBlock
->NumberOfMapRegisters
;
1271 if (WaitContextBlock
->NumberOfMapRegisters
&&
1272 AdapterObject
->MasterAdapter
)
1274 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1276 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1278 Index
= RtlFindClearBitsAndSet(
1279 MasterAdapter
->MapRegisters
,
1280 WaitContextBlock
->NumberOfMapRegisters
, 0);
1283 AdapterObject
->MapRegisterBase
=
1284 MasterAdapter
->MapRegisterBase
+ Index
;
1285 if (!AdapterObject
->ScatterGather
)
1287 AdapterObject
->MapRegisterBase
=
1288 (PROS_MAP_REGISTER_ENTRY
)(
1289 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1297 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1298 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1302 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1306 AdapterObject
->MapRegisterBase
= NULL
;
1307 AdapterObject
->NumberOfMapRegisters
= 0;
1310 /* Call the adapter control routine. */
1311 Result
= ((PDRIVER_CONTROL
)WaitContextBlock
->DeviceRoutine
)(
1312 WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
1313 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
1319 * We're done until the caller manually calls IoFreeAdapterChannel
1320 * or IoFreeMapRegisters.
1324 case DeallocateObjectKeepRegisters
:
1326 * Hide the map registers so they aren't deallocated next time
1329 AdapterObject
->NumberOfMapRegisters
= 0;
1339 * @name IoFreeMapRegisters
1341 * Free map registers reserved by the system for a DMA.
1343 * @param AdapterObject
1344 * DMA adapter to free map registers on.
1345 * @param MapRegisterBase
1346 * Handle to map registers to free.
1347 * @param NumberOfRegisters
1348 * Number of map registers to be freed.
1355 IN PADAPTER_OBJECT AdapterObject
,
1356 IN PVOID MapRegisterBase
,
1357 IN ULONG NumberOfMapRegisters
)
1359 PADAPTER_OBJECT MasterAdapter
= AdapterObject
->MasterAdapter
;
1360 PLIST_ENTRY ListEntry
;
1365 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1367 if (MasterAdapter
== NULL
|| MapRegisterBase
== NULL
)
1370 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1372 if (NumberOfMapRegisters
!= 0)
1374 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1376 RealMapRegisterBase
=
1377 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1378 RtlClearBits(MasterAdapter
->MapRegisters
,
1379 RealMapRegisterBase
- MasterAdapter
->MapRegisterBase
,
1380 NumberOfMapRegisters
);
1384 * Now that we freed few map registers it's time to look at the master
1385 * adapter queue and see if there is someone waiting for map registers.
1388 while (!IsListEmpty(&MasterAdapter
->AdapterQueue
))
1390 ListEntry
= RemoveHeadList(&MasterAdapter
->AdapterQueue
);
1391 AdapterObject
= CONTAINING_RECORD(
1392 ListEntry
, struct _ADAPTER_OBJECT
, AdapterQueue
);
1394 Index
= RtlFindClearBitsAndSet(
1395 MasterAdapter
->MapRegisters
,
1396 AdapterObject
->NumberOfMapRegisters
,
1397 MasterAdapter
->NumberOfMapRegisters
);
1400 InsertHeadList(&MasterAdapter
->AdapterQueue
, ListEntry
);
1404 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1406 AdapterObject
->MapRegisterBase
=
1407 MasterAdapter
->MapRegisterBase
+ Index
;
1408 if (!AdapterObject
->ScatterGather
)
1410 AdapterObject
->MapRegisterBase
=
1411 (PROS_MAP_REGISTER_ENTRY
)(
1412 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1416 Result
= ((PDRIVER_CONTROL
)AdapterObject
->CurrentWcb
->DeviceRoutine
)(
1417 AdapterObject
->CurrentWcb
->DeviceObject
,
1418 AdapterObject
->CurrentWcb
->CurrentIrp
,
1419 AdapterObject
->MapRegisterBase
,
1420 AdapterObject
->CurrentWcb
->DeviceContext
);
1424 case DeallocateObjectKeepRegisters
:
1425 AdapterObject
->NumberOfMapRegisters
= 0;
1428 case DeallocateObject
:
1429 if (AdapterObject
->NumberOfMapRegisters
)
1431 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1432 RtlClearBits(MasterAdapter
->MapRegisters
,
1433 AdapterObject
->MapRegisterBase
-
1434 MasterAdapter
->MapRegisterBase
,
1435 AdapterObject
->NumberOfMapRegisters
);
1436 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1438 IoFreeAdapterChannel(AdapterObject
);
1445 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1448 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1452 * @name HalpCopyBufferMap
1454 * Helper function for copying data from/to map register buffers.
1456 * @see IoFlushAdapterBuffers, IoMapTransfer
1462 PROS_MAP_REGISTER_ENTRY MapRegisterBase
,
1465 BOOLEAN WriteToDevice
)
1467 ULONG CurrentLength
;
1468 ULONG_PTR CurrentAddress
;
1470 PVOID VirtualAddress
;
1472 VirtualAddress
= MmGetSystemAddressForMdlSafe(Mdl
, HighPagePriority
);
1473 if (VirtualAddress
== NULL
)
1476 * NOTE: On real NT a mechanism with reserved pages is implemented
1477 * to handle this case in a slow, but graceful non-fatal way.
1479 /* FIXME: The correct bug check code isn't defined. */
1480 /* KEBUGCHECKEX(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); */
1484 CurrentAddress
= (ULONG_PTR
)VirtualAddress
+
1485 (ULONG_PTR
)CurrentVa
-
1486 (ULONG_PTR
)MmGetMdlVirtualAddress(Mdl
);
1490 ByteOffset
= BYTE_OFFSET(CurrentAddress
);
1491 CurrentLength
= PAGE_SIZE
- ByteOffset
;
1492 if (CurrentLength
> Length
)
1493 CurrentLength
= Length
;
1498 (PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1499 (PVOID
)CurrentAddress
,
1505 (PVOID
)CurrentAddress
,
1506 (PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1510 Length
-= CurrentLength
;
1511 CurrentAddress
+= CurrentLength
;
1517 * @name IoFlushAdapterBuffers
1519 * Flush any data remaining in the DMA controller's memory into the host
1522 * @param AdapterObject
1523 * The adapter object to flush.
1525 * Original MDL to flush data into.
1526 * @param MapRegisterBase
1527 * Map register base that was just used by IoMapTransfer, etc.
1529 * Offset into Mdl to be flushed into, same as was passed to
1532 * Length of the buffer to be flushed into.
1533 * @param WriteToDevice
1534 * TRUE if it's a write, FALSE if it's a read.
1536 * @return TRUE in all cases.
1539 * This copies data from the map register-backed buffer to the user's
1540 * target buffer. Data are not in the user buffer until this function
1542 * For slave DMA transfers the controller channel is masked effectively
1543 * stopping the current transfer.
1549 IoFlushAdapterBuffers(
1550 PADAPTER_OBJECT AdapterObject
,
1552 PVOID MapRegisterBase
,
1555 BOOLEAN WriteToDevice
)
1557 BOOLEAN SlaveDma
= FALSE
;
1558 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1560 ASSERT_IRQL(DISPATCH_LEVEL
);
1562 if (AdapterObject
!= NULL
&& !AdapterObject
->MasterDevice
)
1564 /* Mask out (disable) the DMA channel. */
1565 if (AdapterObject
->AdapterNumber
== 1)
1567 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1568 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
,
1569 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1573 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1574 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
,
1575 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1580 /* This can happen if the device supports hardware scatter/gather. */
1581 if (MapRegisterBase
== NULL
)
1584 RealMapRegisterBase
=
1585 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1589 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1591 if (RealMapRegisterBase
->Counter
!= ~0)
1593 if (SlaveDma
&& !AdapterObject
->IgnoreCount
)
1594 Length
-= HalReadDmaCounter(AdapterObject
);
1597 HalpCopyBufferMap(Mdl
, RealMapRegisterBase
, CurrentVa
, Length
, FALSE
);
1601 /* FIXME: Unimplemented case */
1606 RealMapRegisterBase
->Counter
= 0;
1612 * @name IoMapTransfer
1614 * Map a DMA for transfer and do the DMA if it's a slave.
1616 * @param AdapterObject
1617 * Adapter object to do the DMA on. Bus-master may pass NULL.
1619 * Locked-down user buffer to DMA in to or out of.
1620 * @param MapRegisterBase
1621 * Handle to map registers to use for this dma.
1623 * Index into Mdl to transfer into/out of.
1625 * Length of transfer. Number of bytes actually transferred on
1627 * @param WriteToDevice
1628 * TRUE if it's an output DMA, FALSE otherwise.
1631 * A logical address that can be used to program a DMA controller, it's
1632 * not meaningful for slave DMA device.
1635 * This function does a copyover to contiguous memory <16MB represented
1636 * by the map registers if needed. If the buffer described by MDL can be
1637 * used as is no copyover is done.
1638 * If it's a slave transfer, this function actually performs it.
1643 PHYSICAL_ADDRESS STDCALL
1645 IN PADAPTER_OBJECT AdapterObject
,
1647 IN PVOID MapRegisterBase
,
1649 IN OUT PULONG Length
,
1650 IN BOOLEAN WriteToDevice
)
1652 PPFN_NUMBER MdlPagesPtr
;
1653 PFN_NUMBER MdlPage1
, MdlPage2
;
1655 ULONG TransferOffset
;
1656 ULONG TransferLength
;
1657 BOOLEAN UseMapRegisters
;
1658 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1659 PHYSICAL_ADDRESS PhysicalAddress
;
1660 PHYSICAL_ADDRESS HighestAcceptableAddress
;
1662 DMA_MODE AdapterMode
;
1666 * Precalculate some values that are used in all cases.
1668 * ByteOffset is offset inside the page at which the transfer starts.
1669 * MdlPagesPtr is pointer inside the MDL page chain at the page where the
1671 * PhysicalAddress is physical address corresponding to the transfer
1672 * start page and offset.
1673 * TransferLength is the inital length of the transfer, which is reminder
1674 * of the first page. The actual value is calculated below.
1676 * Note that all the variables can change during the processing which
1677 * takes place below. These are just initial values.
1680 ByteOffset
= BYTE_OFFSET(CurrentVa
);
1682 MdlPagesPtr
= MmGetMdlPfnArray(Mdl
);
1683 MdlPagesPtr
+= ((ULONG_PTR
)CurrentVa
- (ULONG_PTR
)Mdl
->StartVa
) >> PAGE_SHIFT
;
1685 PhysicalAddress
.QuadPart
= *MdlPagesPtr
<< PAGE_SHIFT
;
1686 PhysicalAddress
.QuadPart
+= ByteOffset
;
1688 TransferLength
= PAGE_SIZE
- ByteOffset
;
1691 * Special case for bus master adapters with S/G support. We can directly
1692 * use the buffer specified by the MDL, so not much work has to be done.
1694 * Just return the passed VA's corresponding physical address and update
1695 * length to the number of physically contiguous bytes found. Also
1696 * pages crossing the 4Gb boundary aren't considered physically contiguous.
1699 if (MapRegisterBase
== NULL
)
1701 while (TransferLength
< *Length
)
1703 MdlPage1
= *MdlPagesPtr
;
1704 MdlPage2
= *(MdlPagesPtr
+ 1);
1705 if (MdlPage1
+ 1 != MdlPage2
)
1707 if ((MdlPage1
^ MdlPage2
) & ~0xFFFFF)
1709 TransferLength
+= PAGE_SIZE
;
1713 if (TransferLength
< *Length
)
1714 *Length
= TransferLength
;
1716 return PhysicalAddress
;
1720 * The code below applies to slave DMA adapters and bus master adapters
1721 * without hardward S/G support.
1724 RealMapRegisterBase
=
1725 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1728 * Try to calculate the size of the transfer. We can only transfer
1729 * pages that are physically contiguous and that don't cross the
1730 * 64Kb boundary (this limitation applies only for ISA controllers).
1733 while (TransferLength
< *Length
)
1735 MdlPage1
= *MdlPagesPtr
;
1736 MdlPage2
= *(MdlPagesPtr
+ 1);
1737 if (MdlPage1
+ 1 != MdlPage2
)
1739 if (!HalpEisaDma
&& ((MdlPage1
^ MdlPage2
) & ~0xF))
1741 TransferLength
+= PAGE_SIZE
;
1745 if (TransferLength
> *Length
)
1746 TransferLength
= *Length
;
1749 * If we're about to simulate software S/G and not all the pages are
1750 * physically contiguous then we must use the map registers to store
1751 * the data and allow the whole transfer to proceed at once.
1754 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
&&
1755 TransferLength
< *Length
)
1757 UseMapRegisters
= TRUE
;
1758 PhysicalAddress
= RealMapRegisterBase
->PhysicalAddress
;
1759 PhysicalAddress
.QuadPart
+= ByteOffset
;
1760 TransferLength
= *Length
;
1761 RealMapRegisterBase
->Counter
= ~0;
1767 * This is ordinary DMA transfer, so just update the progress
1768 * counters. These are used by IoFlushAdapterBuffers to track
1769 * the transfer progress.
1772 UseMapRegisters
= FALSE
;
1773 Counter
= RealMapRegisterBase
->Counter
;
1774 RealMapRegisterBase
->Counter
+= BYTES_TO_PAGES(ByteOffset
+ TransferLength
);
1777 * Check if the buffer doesn't exceed the highest physical address
1778 * limit of the device. In that case we must use the map registers to
1782 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
1783 if (PhysicalAddress
.QuadPart
+ TransferLength
>
1784 HighestAcceptableAddress
.QuadPart
)
1786 UseMapRegisters
= TRUE
;
1787 PhysicalAddress
= RealMapRegisterBase
->PhysicalAddress
;
1788 PhysicalAddress
.QuadPart
+= ByteOffset
;
1789 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1791 RealMapRegisterBase
->Counter
= ~0;
1797 * If we decided to use the map registers (see above) and we're about
1798 * to transfer data to the device then copy the buffers into the map
1802 if (UseMapRegisters
&& WriteToDevice
)
1804 HalpCopyBufferMap(Mdl
, RealMapRegisterBase
+ Counter
,
1805 CurrentVa
, TransferLength
, WriteToDevice
);
1809 * Return the length of transfer that actually takes place.
1812 *Length
= TransferLength
;
1815 * If we're doing slave (system) DMA then program the (E)ISA controller
1816 * to actually start the transfer.
1819 if (AdapterObject
!= NULL
&& !AdapterObject
->MasterDevice
)
1821 AdapterMode
= AdapterObject
->AdapterMode
;
1825 AdapterMode
.TransferType
= WRITE_TRANSFER
;
1829 AdapterMode
.TransferType
= READ_TRANSFER
;
1830 if (AdapterObject
->IgnoreCount
)
1832 RtlZeroMemory((PUCHAR
)RealMapRegisterBase
[Counter
].VirtualAddress
+
1833 ByteOffset
, TransferLength
);
1837 TransferOffset
= PhysicalAddress
.LowPart
& 0xFFFF;
1838 if (AdapterObject
->Width16Bits
)
1840 TransferLength
>>= 1;
1841 TransferOffset
>>= 1;
1844 OldIrql
= KfAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
);
1846 if (AdapterObject
->AdapterNumber
== 1)
1848 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1850 /* Reset Register */
1851 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
1853 WRITE_PORT_UCHAR(&DmaControl1
->Mode
, AdapterMode
.Byte
);
1854 /* Set the Offset Register */
1855 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
1856 (UCHAR
)(TransferOffset
));
1857 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
1858 (UCHAR
)(TransferOffset
>> 8));
1859 /* Set the Page Register */
1860 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1861 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
),
1862 (UCHAR
)(PhysicalAddress
.LowPart
>> 16));
1865 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1866 FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
1869 /* Set the Length */
1870 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
1871 (UCHAR
)(TransferLength
- 1));
1872 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
1873 (UCHAR
)((TransferLength
- 1) >> 8));
1874 /* Unmask the Channel */
1875 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
,
1876 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
1880 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1882 /* Reset Register */
1883 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
1885 WRITE_PORT_UCHAR(&DmaControl2
->Mode
, AdapterMode
.Byte
);
1886 /* Set the Offset Register */
1887 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
1888 (UCHAR
)(TransferOffset
));
1889 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
1890 (UCHAR
)(TransferOffset
>> 8));
1891 /* Set the Page Register */
1892 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1893 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
),
1894 (UCHAR
)(PhysicalAddress
.u
.LowPart
>> 16));
1897 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1898 FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
1901 /* Set the Length */
1902 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
1903 (UCHAR
)(TransferLength
- 1));
1904 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
1905 (UCHAR
)((TransferLength
- 1) >> 8));
1906 /* Unmask the Channel */
1907 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
,
1908 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
1911 KfReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
1915 * Return physical address of the buffer with data that is used for the
1916 * transfer. It can either point inside the Mdl that was passed by the
1917 * caller or into the map registers if the Mdl buffer can't be used
1921 return PhysicalAddress
;
1925 * @name HalFlushCommonBuffer
1931 HalFlushCommonBuffer(