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)
13 * @page DMA Implementation Notes
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
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.
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.
37 * - Bus-master / Slave DMA
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
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
50 * - Allocation of map registers
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:
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.
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.
71 /* INCLUDES *****************************************************************/
77 static KEVENT HalpDmaLock
;
78 static LIST_ENTRY HalpDmaAdapterList
;
79 static PADAPTER_OBJECT HalpEisaAdapter
[8];
80 static BOOLEAN HalpEisaDma
;
81 static PADAPTER_OBJECT HalpMasterAdapter
;
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
),
89 FIELD_OFFSET(DMA_PAGE
, Channel5
),
90 FIELD_OFFSET(DMA_PAGE
, Channel6
),
91 FIELD_OFFSET(DMA_PAGE
, Channel7
)
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*/
114 #define MAX_MAP_REGISTERS 64
116 #define TAG_DMA ' AMD'
118 /* FUNCTIONS *****************************************************************/
124 * Initialize the DMA Operation table
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
;
133 * Check if Extended DMA is available. We're just going to do a random
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)
142 * Intialize all the global variables and allocate master adapter with
146 InitializeListHead(&HalpDmaAdapterList
);
147 KeInitializeEvent(&HalpDmaLock
, NotificationEvent
, TRUE
);
149 HalpMasterAdapter
= HalpDmaAllocateMasterAdapter();
152 * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's
153 * used by IoGetDmaAdapter in the kernel.
156 HalGetDmaAdapter
= HalpGetDmaAdapter
;
160 * @name HalpGetAdapterMaximumPhysicalAddress
162 * Get the maximum physical address acceptable by the device represented
163 * by the passed DMA adapter.
166 PHYSICAL_ADDRESS NTAPI
167 HalpGetAdapterMaximumPhysicalAddress(
168 IN PADAPTER_OBJECT AdapterObject
)
170 PHYSICAL_ADDRESS HighestAddress
;
172 if (AdapterObject
->MasterDevice
)
174 if (AdapterObject
->Dma64BitAddresses
)
176 HighestAddress
.QuadPart
= 0xFFFFFFFFFFFFFFFFULL
;
177 return HighestAddress
;
179 else if (AdapterObject
->Dma32BitAddresses
)
181 HighestAddress
.QuadPart
= 0xFFFFFFFF;
182 return HighestAddress
;
186 HighestAddress
.QuadPart
= 0xFFFFFF;
187 return HighestAddress
;
191 * @name HalpGrowMapBuffers
193 * Allocate initial, or additional, map buffers for DMA master adapter.
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).
204 IN PADAPTER_OBJECT AdapterObject
,
205 IN ULONG SizeOfMapBuffers
)
207 PVOID VirtualAddress
;
208 PHYSICAL_ADDRESS PhysicalAddress
;
209 PHYSICAL_ADDRESS HighestAcceptableAddress
;
210 PHYSICAL_ADDRESS LowestAcceptableAddress
;
211 PHYSICAL_ADDRESS BoundryAddressMultiple
;
213 ULONG MapRegisterCount
;
215 /* FIXME: Check if enough map register slots are available. */
217 MapRegisterCount
= BYTES_TO_PAGES(SizeOfMapBuffers
);
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).
224 HighestAcceptableAddress
=
225 HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
226 LowestAcceptableAddress
.HighPart
= 0;
227 LowestAcceptableAddress
.LowPart
=
228 HighestAcceptableAddress
.LowPart
== 0xFFFFFFFF ? 0x1000000 : 0;
229 BoundryAddressMultiple
.QuadPart
= 0;
231 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
232 MapRegisterCount
<< PAGE_SHIFT
, LowestAcceptableAddress
,
233 HighestAcceptableAddress
, BoundryAddressMultiple
, MmNonCached
);
235 if (VirtualAddress
== NULL
&& LowestAcceptableAddress
.LowPart
!= 0)
237 LowestAcceptableAddress
.LowPart
= 0;
238 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
239 MapRegisterCount
<< PAGE_SHIFT
, LowestAcceptableAddress
,
240 HighestAcceptableAddress
, BoundryAddressMultiple
, MmNonCached
);
243 if (VirtualAddress
== NULL
)
246 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
249 * All the following must be done with the master adapter lock held
250 * to prevent corruption.
253 OldIrql
= KfAcquireSpinLock(&AdapterObject
->SpinLock
);
256 * Setup map register entries for the buffer allocated. Each entry has
257 * a virtual and physical address and corresponds to PAGE_SIZE large
261 if (MapRegisterCount
> 0)
263 PROS_MAP_REGISTER_ENTRY CurrentEntry
, PreviousEntry
;
265 CurrentEntry
= AdapterObject
->MapRegisterBase
+
266 AdapterObject
->NumberOfMapRegisters
;
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.
274 * Also for non-EISA DMA leave one free entry for every 64Kb
275 * break, because the DMA controller can handle only coniguous
279 if (CurrentEntry
!= AdapterObject
->MapRegisterBase
)
281 PreviousEntry
= CurrentEntry
- 1;
282 if (PreviousEntry
->PhysicalAddress
.LowPart
+ PAGE_SIZE
==
283 PhysicalAddress
.LowPart
)
287 if ((PreviousEntry
->PhysicalAddress
.LowPart
^
288 PhysicalAddress
.LowPart
) & 0xFFFF0000)
291 AdapterObject
->NumberOfMapRegisters
++;
298 AdapterObject
->NumberOfMapRegisters
++;
302 RtlClearBit(AdapterObject
->MapRegisters
,
303 CurrentEntry
- AdapterObject
->MapRegisterBase
);
304 CurrentEntry
->VirtualAddress
= VirtualAddress
;
305 CurrentEntry
->PhysicalAddress
= PhysicalAddress
;
307 PhysicalAddress
.LowPart
+= PAGE_SIZE
;
308 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
311 AdapterObject
->NumberOfMapRegisters
++;
314 while (MapRegisterCount
!= 0);
317 KfReleaseSpinLock(&AdapterObject
->SpinLock
, OldIrql
);
323 * @name HalpDmaAllocateMasterAdapter
325 * Helper routine to allocate and initialize master adapter object and it's
326 * associated map register buffers.
331 PADAPTER_OBJECT NTAPI
332 HalpDmaAllocateMasterAdapter(VOID
)
334 PADAPTER_OBJECT MasterAdapter
;
335 ULONG Size
, SizeOfBitmap
;
337 SizeOfBitmap
= MAX_MAP_REGISTERS
;
338 Size
= sizeof(ADAPTER_OBJECT
);
339 Size
+= sizeof(RTL_BITMAP
);
340 Size
+= (SizeOfBitmap
+ 7) >> 3;
342 MasterAdapter
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_DMA
);
343 if (MasterAdapter
== NULL
)
346 RtlZeroMemory(MasterAdapter
, Size
);
348 KeInitializeSpinLock(&MasterAdapter
->SpinLock
);
349 InitializeListHead(&MasterAdapter
->AdapterQueue
);
351 MasterAdapter
->MapRegisters
= (PVOID
)(MasterAdapter
+ 1);
353 MasterAdapter
->MapRegisters
,
354 (PULONG
)(MasterAdapter
->MapRegisters
+ 1),
356 RtlSetAllBits(MasterAdapter
->MapRegisters
);
357 MasterAdapter
->NumberOfMapRegisters
= 0;
358 MasterAdapter
->CommittedMapRegisters
= 0;
360 MasterAdapter
->MapRegisterBase
= ExAllocatePoolWithTag(
362 SizeOfBitmap
* sizeof(ROS_MAP_REGISTER_ENTRY
),
364 if (MasterAdapter
->MapRegisterBase
== NULL
)
366 ExFreePool(MasterAdapter
);
370 RtlZeroMemory(MasterAdapter
->MapRegisterBase
,
371 SizeOfBitmap
* sizeof(ROS_MAP_REGISTER_ENTRY
));
372 if (!HalpGrowMapBuffers(MasterAdapter
, 0x10000))
374 ExFreePool(MasterAdapter
);
378 return MasterAdapter
;
382 * @name HalpDmaAllocateChildAdapter
384 * Helper routine of HalGetAdapter. Allocate child adapter object and
385 * fill out some basic fields.
390 PADAPTER_OBJECT NTAPI
391 HalpDmaAllocateChildAdapter(
392 ULONG NumberOfMapRegisters
,
393 PDEVICE_DESCRIPTION DeviceDescription
)
395 PADAPTER_OBJECT AdapterObject
;
396 OBJECT_ATTRIBUTES ObjectAttributes
;
400 InitializeObjectAttributes(
403 OBJ_KERNEL_HANDLE
| OBJ_PERMANENT
,
407 Status
= ObCreateObject(
413 sizeof(ADAPTER_OBJECT
),
416 (PVOID
)&AdapterObject
);
417 if (!NT_SUCCESS(Status
))
420 Status
= ObReferenceObjectByPointer(
422 FILE_READ_DATA
| FILE_WRITE_DATA
,
425 if (!NT_SUCCESS(Status
))
428 RtlZeroMemory(AdapterObject
, sizeof(ADAPTER_OBJECT
));
430 Status
= ObInsertObject(
433 FILE_READ_DATA
| FILE_WRITE_DATA
,
437 if (!NT_SUCCESS(Status
))
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
);
451 return AdapterObject
;
455 * @name HalpDmaInitializeEisaAdapter
457 * Setup DMA modes and extended modes for (E)ISA DMA adapter object.
461 HalpDmaInitializeEisaAdapter(
462 PADAPTER_OBJECT AdapterObject
,
463 PDEVICE_DESCRIPTION DeviceDescription
)
466 DMA_MODE DmaMode
= {{0 }};
467 DMA_EXTENDED_MODE ExtendedMode
= {{ 0 }};
470 Controller
= (DeviceDescription
->DmaChannel
& 4) ? 2 : 1;
473 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController1
);
475 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController2
);
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
;
485 ExtendedMode
.ChannelNumber
= AdapterObject
->ChannelNumber
;
487 switch (DeviceDescription
->DmaSpeed
)
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;
497 switch (DeviceDescription
->DmaWidth
)
499 case Width8Bits
: ExtendedMode
.TransferSize
= B_8BITS
; break;
500 case Width16Bits
: ExtendedMode
.TransferSize
= B_16BITS
; break;
501 case Width32Bits
: ExtendedMode
.TransferSize
= B_32BITS
; break;
507 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode1
),
510 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode2
),
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.
521 if (!DeviceDescription
->Master
)
523 if (Controller
== 2 && DeviceDescription
->DmaWidth
== Width16Bits
)
524 AdapterObject
->Width16Bits
= TRUE
;
525 else if (Controller
!= 1 || DeviceDescription
->DmaWidth
!= Width8Bits
)
530 DmaMode
.Channel
= AdapterObject
->ChannelNumber
;
531 DmaMode
.AutoInitialize
= DeviceDescription
->AutoInitialize
;
534 * Set the DMA request mode.
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.
541 if (DeviceDescription
->Master
)
543 DmaMode
.RequestMode
= CASCADE_REQUEST_MODE
;
546 /* Set the Request Data */
547 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->Mode
,
549 /* Unmask DMA Channel */
550 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->SingleMask
,
551 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
553 /* Set the Request Data */
554 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->Mode
,
556 /* Unmask DMA Channel */
557 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->SingleMask
,
558 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
563 if (DeviceDescription
->DemandMode
)
564 DmaMode
.RequestMode
= DEMAND_REQUEST_MODE
;
566 DmaMode
.RequestMode
= SINGLE_REQUEST_MODE
;
569 AdapterObject
->AdapterMode
= DmaMode
;
575 * @name HalGetAdapter
577 * Allocate an adapter object for DMA device.
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.
585 * @return The DMA adapter on success, NULL otherwise.
590 PADAPTER_OBJECT NTAPI
592 PDEVICE_DESCRIPTION DeviceDescription
,
593 PULONG NumberOfMapRegisters
)
595 PADAPTER_OBJECT AdapterObject
= NULL
;
596 PADAPTER_OBJECT MasterAdapter
;
601 /* Validate parameters in device description */
602 if (DeviceDescription
->Version
> DEVICE_DESCRIPTION_VERSION2
)
606 * See if we're going to use ISA/EISA DMA adapter. These adapters are
607 * special since they're reused.
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.
613 if (DeviceDescription
->InterfaceType
== Isa
|| !DeviceDescription
->Master
)
615 if (DeviceDescription
->InterfaceType
== Isa
&&
616 DeviceDescription
->DmaChannel
>= 8)
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.
631 if (EisaAdapter
&& DeviceDescription
->DmaChannel
== 4)
635 * Calculate the number of map registers.
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.
643 MaximumLength
= DeviceDescription
->MaximumLength
& MAXLONG
;
644 if (DeviceDescription
->ScatterGather
&&
645 (DeviceDescription
->InterfaceType
== Eisa
||
646 DeviceDescription
->InterfaceType
== PCIBus
))
650 else if (DeviceDescription
->ScatterGather
&&
651 !DeviceDescription
->Master
)
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.
662 MapRegisters
= BYTES_TO_PAGES(MaximumLength
) + 1;
663 if (MapRegisters
> 16)
668 * Acquire the DMA lock that is used to protect adapter lists and
669 * EISA adapter array.
672 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
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).
684 AdapterObject
= HalpEisaAdapter
[DeviceDescription
->DmaChannel
];
685 if (AdapterObject
!= NULL
)
687 if (AdapterObject
->NeedsMapRegisters
&&
688 MapRegisters
> AdapterObject
->MapRegistersPerChannel
)
689 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
693 if (AdapterObject
== NULL
)
695 AdapterObject
= HalpDmaAllocateChildAdapter(
696 MapRegisters
, DeviceDescription
);
697 if (AdapterObject
== NULL
)
699 KeSetEvent(&HalpDmaLock
, 0, 0);
705 HalpEisaAdapter
[DeviceDescription
->DmaChannel
] = AdapterObject
;
708 if (MapRegisters
> 0)
710 AdapterObject
->NeedsMapRegisters
= TRUE
;
711 MasterAdapter
= HalpMasterAdapter
;
712 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
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.
722 MasterAdapter
->CommittedMapRegisters
+= MapRegisters
;
723 if (MasterAdapter
->CommittedMapRegisters
> MasterAdapter
->NumberOfMapRegisters
)
724 HalpGrowMapBuffers(MasterAdapter
, 0x10000);
728 AdapterObject
->NeedsMapRegisters
= FALSE
;
729 if (DeviceDescription
->Master
)
730 AdapterObject
->MapRegistersPerChannel
= BYTES_TO_PAGES(MaximumLength
) + 1;
732 AdapterObject
->MapRegistersPerChannel
= 1;
737 InsertTailList(&HalpDmaAdapterList
, &AdapterObject
->AdapterList
);
740 * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
741 * no longer be touched, so we don't need it.
744 KeSetEvent(&HalpDmaLock
, 0, 0);
747 * Setup the values in the adapter object that are common for all
751 if (DeviceDescription
->Version
>= DEVICE_DESCRIPTION_VERSION1
)
752 AdapterObject
->IgnoreCount
= DeviceDescription
->IgnoreCount
;
754 AdapterObject
->IgnoreCount
= 0;
756 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
757 AdapterObject
->Dma64BitAddresses
= DeviceDescription
->Dma64BitAddresses
;
758 AdapterObject
->ScatterGather
= DeviceDescription
->ScatterGather
;
759 AdapterObject
->MasterDevice
= DeviceDescription
->Master
;
760 *NumberOfMapRegisters
= AdapterObject
->MapRegistersPerChannel
;
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.
770 if (!HalpDmaInitializeEisaAdapter(AdapterObject
, DeviceDescription
))
772 ObDereferenceObject(AdapterObject
);
777 return AdapterObject
;
781 * @name HalpGetDmaAdapter
783 * Internal routine to allocate PnP DMA adapter object. It's exported through
784 * HalDispatchTable and used by IoGetDmaAdapter.
792 IN PDEVICE_DESCRIPTION DeviceDescription
,
793 OUT PULONG NumberOfMapRegisters
)
795 return &HalGetAdapter(DeviceDescription
, NumberOfMapRegisters
)->DmaHeader
;
799 * @name HalPutDmaAdapter
801 * Internal routine to free DMA adapter and resources for reuse. It's exported
802 * using the DMA_OPERATIONS interface by HalGetAdapter.
809 PADAPTER_OBJECT AdapterObject
)
811 if (AdapterObject
->ChannelNumber
== 0xFF)
813 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
815 RemoveEntryList(&AdapterObject
->AdapterList
);
816 KeSetEvent(&HalpDmaLock
, 0, 0);
819 ObDereferenceObject(AdapterObject
);
823 * @name HalAllocateCommonBuffer
825 * Allocates memory that is visible to both the processor(s) and the DMA
828 * @param AdapterObject
829 * Adapter object representing the bus master or system dma controller.
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.
837 * @return The base virtual address of the memory allocated or NULL on failure.
840 * On real NT x86 systems the CacheEnabled parameter is ignored, we honour
841 * it. If it proves to cause problems change it.
843 * @see HalFreeCommonBuffer
849 HalAllocateCommonBuffer(
850 PADAPTER_OBJECT AdapterObject
,
852 PPHYSICAL_ADDRESS LogicalAddress
,
853 BOOLEAN CacheEnabled
)
855 PHYSICAL_ADDRESS LowestAcceptableAddress
;
856 PHYSICAL_ADDRESS HighestAcceptableAddress
;
857 PHYSICAL_ADDRESS BoundryAddressMultiple
;
858 PVOID VirtualAddress
;
860 LowestAcceptableAddress
.QuadPart
= 0;
861 HighestAcceptableAddress
=
862 HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
863 BoundryAddressMultiple
.QuadPart
= 0;
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.
871 if (AdapterObject
->MasterDevice
)
872 BoundryAddressMultiple
.HighPart
= 1;
874 BoundryAddressMultiple
.LowPart
= 0x10000;
876 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(
877 Length
, LowestAcceptableAddress
, HighestAcceptableAddress
,
878 BoundryAddressMultiple
, CacheEnabled
? MmCached
: MmNonCached
);
879 if (VirtualAddress
== NULL
)
882 *LogicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
884 return VirtualAddress
;
888 * @name HalFreeCommonBuffer
890 * Free common buffer allocated with HalAllocateCommonBuffer.
892 * @see HalAllocateCommonBuffer
899 PADAPTER_OBJECT AdapterObject
,
901 PHYSICAL_ADDRESS LogicalAddress
,
902 PVOID VirtualAddress
,
903 BOOLEAN CacheEnabled
)
905 MmFreeContiguousMemory(VirtualAddress
);
909 * @name HalpDmaGetDmaAlignment
911 * Internal routine to return the DMA alignment requirement. It's exported
912 * using the DMA_OPERATIONS interface by HalGetAdapter.
918 HalpDmaGetDmaAlignment(
919 PADAPTER_OBJECT AdapterObject
)
925 * @name HalReadDmaCounter
927 * Read DMA operation progress counter.
934 PADAPTER_OBJECT AdapterObject
)
937 ULONG Count
, OldCount
;
939 ASSERT(!AdapterObject
->MasterDevice
);
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.
947 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
949 /* Send the request to the specific controller. */
950 if (AdapterObject
->AdapterNumber
== 1)
952 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
959 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
961 Count
= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
962 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
963 Count
|= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
964 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
966 while (0xffff00 & (OldCount
^ Count
));
970 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
977 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
979 Count
= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
980 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
981 Count
|= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
982 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
984 while (0xffff00 & (OldCount
^ Count
));
987 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
991 if (AdapterObject
->Width16Bits
)
998 * @name HalpGrowMapBufferWorker
1000 * Helper routine of HalAllocateAdapterChannel for allocating map registers
1001 * at PASSIVE_LEVEL in work item.
1005 HalpGrowMapBufferWorker(PVOID DeferredContext
)
1007 PGROW_WORK_ITEM WorkItem
= (PGROW_WORK_ITEM
)DeferredContext
;
1012 * Try to allocate new map registers for the adapter.
1014 * NOTE: The NT implementation actually tries to allocate more map
1015 * registers than needed as an optimization.
1018 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
,
1020 Succeeded
= HalpGrowMapBuffers(WorkItem
->AdapterObject
->MasterAdapter
,
1021 WorkItem
->NumberOfMapRegisters
);
1022 KeSetEvent(&HalpDmaLock
, 0, 0);
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.
1033 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1034 IoFreeMapRegisters(WorkItem
->AdapterObject
, (PVOID
)2, 0);
1035 KeLowerIrql(OldIrql
);
1038 ExFreePool(WorkItem
);
1042 * @name HalAllocateAdapterChannel
1044 * Setup map registers for an adapter object.
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.
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.
1061 * @see IoFreeAdapterChannel
1067 HalAllocateAdapterChannel(
1068 PADAPTER_OBJECT AdapterObject
,
1069 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
1070 ULONG NumberOfMapRegisters
,
1071 PDRIVER_CONTROL ExecutionRoutine
)
1073 PADAPTER_OBJECT MasterAdapter
;
1074 PGROW_WORK_ITEM WorkItem
;
1075 ULONG Index
= MAXULONG
;
1079 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1081 /* Set up the wait context block in case we can't run right away. */
1082 WaitContextBlock
->DeviceRoutine
= ExecutionRoutine
;
1083 WaitContextBlock
->NumberOfMapRegisters
= NumberOfMapRegisters
;
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
;
1089 MasterAdapter
= AdapterObject
->MasterAdapter
;
1091 AdapterObject
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1092 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1094 if (NumberOfMapRegisters
&& AdapterObject
->NeedsMapRegisters
)
1096 if (NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)
1098 AdapterObject
->NumberOfMapRegisters
= 0;
1099 IoFreeAdapterChannel(AdapterObject
);
1100 return STATUS_INSUFFICIENT_RESOURCES
;
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
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.
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.
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.
1125 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1127 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1129 Index
= RtlFindClearBitsAndSet(
1130 MasterAdapter
->MapRegisters
, NumberOfMapRegisters
, 0);
1131 if (Index
!= MAXULONG
)
1133 AdapterObject
->MapRegisterBase
=
1134 MasterAdapter
->MapRegisterBase
+ Index
;
1135 if (!AdapterObject
->ScatterGather
)
1137 AdapterObject
->MapRegisterBase
=
1138 (PROS_MAP_REGISTER_ENTRY
)(
1139 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1145 if (Index
== MAXULONG
)
1147 WorkItem
= ExAllocatePoolWithTag(
1148 NonPagedPool
, sizeof(GROW_WORK_ITEM
), TAG_DMA
);
1149 if (WorkItem
== NULL
)
1151 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1152 AdapterObject
->NumberOfMapRegisters
= 0;
1153 IoFreeAdapterChannel(AdapterObject
);
1154 return STATUS_INSUFFICIENT_RESOURCES
;
1157 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1159 ExInitializeWorkItem(
1160 &WorkItem
->WorkQueueItem
, HalpGrowMapBufferWorker
, WorkItem
);
1161 WorkItem
->AdapterObject
= AdapterObject
;
1162 WorkItem
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1164 ExQueueWorkItem(&WorkItem
->WorkQueueItem
, DelayedWorkQueue
);
1166 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1168 return STATUS_SUCCESS
;
1171 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1175 AdapterObject
->MapRegisterBase
= NULL
;
1176 AdapterObject
->NumberOfMapRegisters
= 0;
1179 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1181 Result
= ExecutionRoutine(
1182 WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
1183 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
1186 * Possible return values:
1189 * Don't free any resources, the ADAPTER_OBJECT is still in use and
1190 * the caller will call IoFreeAdapterChannel later.
1192 * - DeallocateObject
1193 * Deallocate the map registers and release the ADAPTER_OBJECT, so
1194 * someone else can use it.
1196 * - DeallocateObjectKeepRegisters
1197 * Release the ADAPTER_OBJECT, but hang on to the map registers. The
1198 * client will later call IoFreeMapRegisters.
1201 * IoFreeAdapterChannel runs the queue, so it must be called unless
1202 * the adapter object is not to be freed.
1205 if (Result
== DeallocateObject
)
1207 IoFreeAdapterChannel(AdapterObject
);
1209 else if (Result
== DeallocateObjectKeepRegisters
)
1211 AdapterObject
->NumberOfMapRegisters
= 0;
1212 IoFreeAdapterChannel(AdapterObject
);
1215 return STATUS_SUCCESS
;
1219 * @name IoFreeAdapterChannel
1221 * Free DMA resources allocated by IoAllocateAdapterChannel.
1223 * @param AdapterObject
1224 * Adapter object with resources to free.
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.
1232 * @see IoAllocateAdapterChannel
1238 IoFreeAdapterChannel(
1239 PADAPTER_OBJECT AdapterObject
)
1241 PADAPTER_OBJECT MasterAdapter
;
1242 PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
;
1243 PWAIT_CONTEXT_BLOCK WaitContextBlock
;
1244 ULONG Index
= MAXULONG
;
1248 MasterAdapter
= AdapterObject
->MasterAdapter
;
1253 * To keep map registers, call here with AdapterObject->
1254 * NumberOfMapRegisters set to zero. This trick is used in
1255 * HalAllocateAdapterChannel for example.
1257 if (AdapterObject
->NumberOfMapRegisters
)
1261 AdapterObject
->MapRegisterBase
,
1262 AdapterObject
->NumberOfMapRegisters
);
1265 DeviceQueueEntry
= KeRemoveDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
1266 if (DeviceQueueEntry
== NULL
)
1271 WaitContextBlock
= CONTAINING_RECORD(
1276 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1277 AdapterObject
->NumberOfMapRegisters
= WaitContextBlock
->NumberOfMapRegisters
;
1279 if (WaitContextBlock
->NumberOfMapRegisters
&&
1280 AdapterObject
->MasterAdapter
)
1282 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1284 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1286 Index
= RtlFindClearBitsAndSet(
1287 MasterAdapter
->MapRegisters
,
1288 WaitContextBlock
->NumberOfMapRegisters
, 0);
1289 if (Index
!= MAXULONG
)
1291 AdapterObject
->MapRegisterBase
=
1292 MasterAdapter
->MapRegisterBase
+ Index
;
1293 if (!AdapterObject
->ScatterGather
)
1295 AdapterObject
->MapRegisterBase
=
1296 (PROS_MAP_REGISTER_ENTRY
)(
1297 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1303 if (Index
== MAXULONG
)
1305 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1306 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1310 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1314 AdapterObject
->MapRegisterBase
= NULL
;
1315 AdapterObject
->NumberOfMapRegisters
= 0;
1318 /* Call the adapter control routine. */
1319 Result
= ((PDRIVER_CONTROL
)WaitContextBlock
->DeviceRoutine
)(
1320 WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
1321 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
1327 * We're done until the caller manually calls IoFreeAdapterChannel
1328 * or IoFreeMapRegisters.
1332 case DeallocateObjectKeepRegisters
:
1334 * Hide the map registers so they aren't deallocated next time
1337 AdapterObject
->NumberOfMapRegisters
= 0;
1347 * @name IoFreeMapRegisters
1349 * Free map registers reserved by the system for a DMA.
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.
1363 IN PADAPTER_OBJECT AdapterObject
,
1364 IN PVOID MapRegisterBase
,
1365 IN ULONG NumberOfMapRegisters
)
1367 PADAPTER_OBJECT MasterAdapter
= AdapterObject
->MasterAdapter
;
1368 PLIST_ENTRY ListEntry
;
1373 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1375 if (MasterAdapter
== NULL
|| MapRegisterBase
== NULL
)
1378 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1380 if (NumberOfMapRegisters
!= 0)
1382 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1384 RealMapRegisterBase
=
1385 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1386 RtlClearBits(MasterAdapter
->MapRegisters
,
1387 RealMapRegisterBase
- MasterAdapter
->MapRegisterBase
,
1388 NumberOfMapRegisters
);
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.
1396 while (!IsListEmpty(&MasterAdapter
->AdapterQueue
))
1398 ListEntry
= RemoveHeadList(&MasterAdapter
->AdapterQueue
);
1399 AdapterObject
= CONTAINING_RECORD(
1400 ListEntry
, struct _ADAPTER_OBJECT
, AdapterQueue
);
1402 Index
= RtlFindClearBitsAndSet(
1403 MasterAdapter
->MapRegisters
,
1404 AdapterObject
->NumberOfMapRegisters
,
1405 MasterAdapter
->NumberOfMapRegisters
);
1406 if (Index
== MAXULONG
)
1408 InsertHeadList(&MasterAdapter
->AdapterQueue
, ListEntry
);
1412 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1414 AdapterObject
->MapRegisterBase
=
1415 MasterAdapter
->MapRegisterBase
+ Index
;
1416 if (!AdapterObject
->ScatterGather
)
1418 AdapterObject
->MapRegisterBase
=
1419 (PROS_MAP_REGISTER_ENTRY
)(
1420 (ULONG_PTR
)AdapterObject
->MapRegisterBase
|
1424 Result
= ((PDRIVER_CONTROL
)AdapterObject
->CurrentWcb
->DeviceRoutine
)(
1425 AdapterObject
->CurrentWcb
->DeviceObject
,
1426 AdapterObject
->CurrentWcb
->CurrentIrp
,
1427 AdapterObject
->MapRegisterBase
,
1428 AdapterObject
->CurrentWcb
->DeviceContext
);
1432 case DeallocateObjectKeepRegisters
:
1433 AdapterObject
->NumberOfMapRegisters
= 0;
1436 case DeallocateObject
:
1437 if (AdapterObject
->NumberOfMapRegisters
)
1439 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1440 RtlClearBits(MasterAdapter
->MapRegisters
,
1441 AdapterObject
->MapRegisterBase
-
1442 MasterAdapter
->MapRegisterBase
,
1443 AdapterObject
->NumberOfMapRegisters
);
1444 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1446 IoFreeAdapterChannel(AdapterObject
);
1453 OldIrql
= KfAcquireSpinLock(&MasterAdapter
->SpinLock
);
1456 KfReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1460 * @name HalpCopyBufferMap
1462 * Helper function for copying data from/to map register buffers.
1464 * @see IoFlushAdapterBuffers, IoMapTransfer
1470 PROS_MAP_REGISTER_ENTRY MapRegisterBase
,
1473 BOOLEAN WriteToDevice
)
1475 ULONG CurrentLength
;
1476 ULONG_PTR CurrentAddress
;
1478 PVOID VirtualAddress
;
1480 VirtualAddress
= MmGetSystemAddressForMdlSafe(Mdl
, HighPagePriority
);
1481 if (VirtualAddress
== NULL
)
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.
1487 KeBugCheckEx(HAL_MEMORY_ALLOCATION
, PAGE_SIZE
, 0, (ULONG_PTR
)__FILE__
, 0);
1490 CurrentAddress
= (ULONG_PTR
)VirtualAddress
+
1491 (ULONG_PTR
)CurrentVa
-
1492 (ULONG_PTR
)MmGetMdlVirtualAddress(Mdl
);
1496 ByteOffset
= BYTE_OFFSET(CurrentAddress
);
1497 CurrentLength
= PAGE_SIZE
- ByteOffset
;
1498 if (CurrentLength
> Length
)
1499 CurrentLength
= Length
;
1504 (PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1505 (PVOID
)CurrentAddress
,
1511 (PVOID
)CurrentAddress
,
1512 (PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1516 Length
-= CurrentLength
;
1517 CurrentAddress
+= CurrentLength
;
1523 * @name IoFlushAdapterBuffers
1525 * Flush any data remaining in the DMA controller's memory into the host
1528 * @param AdapterObject
1529 * The adapter object to flush.
1531 * Original MDL to flush data into.
1532 * @param MapRegisterBase
1533 * Map register base that was just used by IoMapTransfer, etc.
1535 * Offset into Mdl to be flushed into, same as was passed to
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.
1542 * @return TRUE in all cases.
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
1548 * For slave DMA transfers the controller channel is masked effectively
1549 * stopping the current transfer.
1555 IoFlushAdapterBuffers(
1556 PADAPTER_OBJECT AdapterObject
,
1558 PVOID MapRegisterBase
,
1561 BOOLEAN WriteToDevice
)
1563 BOOLEAN SlaveDma
= FALSE
;
1564 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1565 PHYSICAL_ADDRESS HighestAcceptableAddress
;
1566 PHYSICAL_ADDRESS PhysicalAddress
;
1567 PPFN_NUMBER MdlPagesPtr
;
1569 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1571 if (AdapterObject
!= NULL
&& !AdapterObject
->MasterDevice
)
1573 /* Mask out (disable) the DMA channel. */
1574 if (AdapterObject
->AdapterNumber
== 1)
1576 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1577 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
,
1578 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1582 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1583 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
,
1584 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1589 /* This can happen if the device supports hardware scatter/gather. */
1590 if (MapRegisterBase
== NULL
)
1593 RealMapRegisterBase
=
1594 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1598 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1600 if (RealMapRegisterBase
->Counter
!= MAXULONG
)
1602 if (SlaveDma
&& !AdapterObject
->IgnoreCount
)
1603 Length
-= HalReadDmaCounter(AdapterObject
);
1604 HalpCopyBufferMap(Mdl
, RealMapRegisterBase
, CurrentVa
, Length
, FALSE
);
1609 MdlPagesPtr
= MmGetMdlPfnArray(Mdl
);
1610 MdlPagesPtr
+= ((ULONG_PTR
)CurrentVa
- (ULONG_PTR
)Mdl
->StartVa
) >> PAGE_SHIFT
;
1612 PhysicalAddress
.QuadPart
= *MdlPagesPtr
<< PAGE_SHIFT
;
1613 PhysicalAddress
.QuadPart
+= BYTE_OFFSET(CurrentVa
);
1615 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
1616 if (PhysicalAddress
.QuadPart
+ Length
>
1617 HighestAcceptableAddress
.QuadPart
)
1619 HalpCopyBufferMap(Mdl
, RealMapRegisterBase
, CurrentVa
, Length
, FALSE
);
1624 RealMapRegisterBase
->Counter
= 0;
1630 * @name IoMapTransfer
1632 * Map a DMA for transfer and do the DMA if it's a slave.
1634 * @param AdapterObject
1635 * Adapter object to do the DMA on. Bus-master may pass NULL.
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.
1641 * Index into Mdl to transfer into/out of.
1643 * Length of transfer. Number of bytes actually transferred on
1645 * @param WriteToDevice
1646 * TRUE if it's an output DMA, FALSE otherwise.
1649 * A logical address that can be used to program a DMA controller, it's
1650 * not meaningful for slave DMA device.
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.
1661 PHYSICAL_ADDRESS NTAPI
1663 IN PADAPTER_OBJECT AdapterObject
,
1665 IN PVOID MapRegisterBase
,
1667 IN OUT PULONG Length
,
1668 IN BOOLEAN WriteToDevice
)
1670 PPFN_NUMBER MdlPagesPtr
;
1671 PFN_NUMBER MdlPage1
, MdlPage2
;
1673 ULONG TransferOffset
;
1674 ULONG TransferLength
;
1675 BOOLEAN UseMapRegisters
;
1676 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1677 PHYSICAL_ADDRESS PhysicalAddress
;
1678 PHYSICAL_ADDRESS HighestAcceptableAddress
;
1680 DMA_MODE AdapterMode
;
1684 * Precalculate some values that are used in all cases.
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
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.
1694 * Note that all the variables can change during the processing which
1695 * takes place below. These are just initial values.
1698 ByteOffset
= BYTE_OFFSET(CurrentVa
);
1700 MdlPagesPtr
= MmGetMdlPfnArray(Mdl
);
1701 MdlPagesPtr
+= ((ULONG_PTR
)CurrentVa
- (ULONG_PTR
)Mdl
->StartVa
) >> PAGE_SHIFT
;
1703 PhysicalAddress
.QuadPart
= *MdlPagesPtr
<< PAGE_SHIFT
;
1704 PhysicalAddress
.QuadPart
+= ByteOffset
;
1706 TransferLength
= PAGE_SIZE
- ByteOffset
;
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.
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.
1717 if (MapRegisterBase
== NULL
)
1719 while (TransferLength
< *Length
)
1721 MdlPage1
= *MdlPagesPtr
;
1722 MdlPage2
= *(MdlPagesPtr
+ 1);
1723 if (MdlPage1
+ 1 != MdlPage2
)
1725 if ((MdlPage1
^ MdlPage2
) & ~0xFFFFF)
1727 TransferLength
+= PAGE_SIZE
;
1731 if (TransferLength
< *Length
)
1732 *Length
= TransferLength
;
1734 return PhysicalAddress
;
1738 * The code below applies to slave DMA adapters and bus master adapters
1739 * without hardward S/G support.
1742 RealMapRegisterBase
=
1743 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
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).
1751 while (TransferLength
< *Length
)
1753 MdlPage1
= *MdlPagesPtr
;
1754 MdlPage2
= *(MdlPagesPtr
+ 1);
1755 if (MdlPage1
+ 1 != MdlPage2
)
1757 if (!HalpEisaDma
&& ((MdlPage1
^ MdlPage2
) & ~0xF))
1759 TransferLength
+= PAGE_SIZE
;
1763 if (TransferLength
> *Length
)
1764 TransferLength
= *Length
;
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.
1772 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
&&
1773 TransferLength
< *Length
)
1775 UseMapRegisters
= TRUE
;
1776 PhysicalAddress
= RealMapRegisterBase
->PhysicalAddress
;
1777 PhysicalAddress
.QuadPart
+= ByteOffset
;
1778 TransferLength
= *Length
;
1779 RealMapRegisterBase
->Counter
= MAXULONG
;
1785 * This is ordinary DMA transfer, so just update the progress
1786 * counters. These are used by IoFlushAdapterBuffers to track
1787 * the transfer progress.
1790 UseMapRegisters
= FALSE
;
1791 Counter
= RealMapRegisterBase
->Counter
;
1792 RealMapRegisterBase
->Counter
+= BYTES_TO_PAGES(ByteOffset
+ TransferLength
);
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
1800 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
1801 if (PhysicalAddress
.QuadPart
+ TransferLength
>
1802 HighestAcceptableAddress
.QuadPart
)
1804 UseMapRegisters
= TRUE
;
1805 PhysicalAddress
= RealMapRegisterBase
[Counter
].PhysicalAddress
;
1806 PhysicalAddress
.QuadPart
+= ByteOffset
;
1807 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1809 RealMapRegisterBase
->Counter
= MAXULONG
;
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
1821 if (UseMapRegisters
&& WriteToDevice
)
1823 HalpCopyBufferMap(Mdl
, RealMapRegisterBase
+ Counter
,
1824 CurrentVa
, TransferLength
, WriteToDevice
);
1828 * Return the length of transfer that actually takes place.
1831 *Length
= TransferLength
;
1834 * If we're doing slave (system) DMA then program the (E)ISA controller
1835 * to actually start the transfer.
1838 if (AdapterObject
!= NULL
&& !AdapterObject
->MasterDevice
)
1840 AdapterMode
= AdapterObject
->AdapterMode
;
1844 AdapterMode
.TransferType
= WRITE_TRANSFER
;
1848 AdapterMode
.TransferType
= READ_TRANSFER
;
1849 if (AdapterObject
->IgnoreCount
)
1851 RtlZeroMemory((PUCHAR
)RealMapRegisterBase
[Counter
].VirtualAddress
+
1852 ByteOffset
, TransferLength
);
1856 TransferOffset
= PhysicalAddress
.LowPart
& 0xFFFF;
1857 if (AdapterObject
->Width16Bits
)
1859 TransferLength
>>= 1;
1860 TransferOffset
>>= 1;
1863 OldIrql
= KfAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
);
1865 if (AdapterObject
->AdapterNumber
== 1)
1867 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1869 /* Reset Register */
1870 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
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));
1884 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1885 FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
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
);
1899 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1901 /* Reset Register */
1902 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
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));
1916 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+
1917 FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
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
);
1930 KfReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
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
1940 return PhysicalAddress
;
1944 * @name HalFlushCommonBuffer
1950 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject
,
1952 IN PHYSICAL_ADDRESS LogicalAddress
,
1953 IN PVOID VirtualAddress
)
1955 /* Function always returns true */
1964 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject
,
1965 IN OUT PULONG NumberOfMapRegisters
)
1967 PADAPTER_OBJECT MasterAdapter
= AdapterObject
->MasterAdapter
;
1968 ULONG MapRegisterNumber
;
1970 /* Check if it needs map registers */
1971 if (AdapterObject
->NeedsMapRegisters
)
1973 /* Check if we have enough */
1974 if (*NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)
1976 /* We don't, fail */
1977 AdapterObject
->NumberOfMapRegisters
= 0;
1981 /* Try to find free map registers */
1982 MapRegisterNumber
= MAXULONG
;
1983 MapRegisterNumber
= RtlFindClearBitsAndSet(MasterAdapter
->MapRegisters
,
1984 *NumberOfMapRegisters
,
1987 /* Check if nothing was found */
1988 if (MapRegisterNumber
== MAXULONG
)
1990 /* No free registers found, so use the base registers */
1991 RtlSetBits(MasterAdapter
->MapRegisters
,
1993 *NumberOfMapRegisters
);
1994 MapRegisterNumber
= 0;
1997 /* Calculate the new base */
1998 AdapterObject
->MapRegisterBase
=
1999 (PROS_MAP_REGISTER_ENTRY
)(MasterAdapter
->MapRegisterBase
+
2002 /* Check if scatter gather isn't supported */
2003 if (!AdapterObject
->ScatterGather
)
2006 AdapterObject
->MapRegisterBase
=
2007 (PROS_MAP_REGISTER_ENTRY
)
2008 ((ULONG_PTR
)AdapterObject
->MapRegisterBase
| MAP_BASE_SW_SG
);
2013 AdapterObject
->MapRegisterBase
= NULL
;
2014 AdapterObject
->NumberOfMapRegisters
= 0;
2017 /* Return the base */
2018 return AdapterObject
->MapRegisterBase
;