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)
12 /* INCLUDES *****************************************************************/
18 /* Adapters for each channel */
19 PADAPTER_OBJECT HalpEisaAdapter
[8];
21 /* FUNCTIONS *****************************************************************/
26 /* TODO: Initialize the first Map Buffer */
30 HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject
,
32 PPHYSICAL_ADDRESS LogicalAddress
,
35 * FUNCTION: Allocates memory that is visible to both the processor(s) and
38 * AdapterObject = Adapter object representing the bus master or
39 * system dma controller
40 * Length = Number of bytes to allocate
41 * LogicalAddress = Logical address the driver can use to access the
43 * CacheEnabled = Specifies if the memory can be cached
44 * RETURNS: The base virtual address of the memory allocated
47 * CacheEnabled is ignored - it's all cache-disabled (like in NT)
48 * UPDATE: It's not ignored now. If that's wrong just modify the
49 * CacheEnabled comparsion below.
52 PHYSICAL_ADDRESS LowestAddress
, HighestAddress
, BoundryAddressMultiple
;
55 LowestAddress
.QuadPart
= 0;
56 BoundryAddressMultiple
.QuadPart
= 0;
57 HighestAddress
.u
.HighPart
= 0;
58 if ((AdapterObject
->Dma32BitAddresses
) && (AdapterObject
->MasterDevice
)) {
59 HighestAddress
.u
.LowPart
= 0xFFFFFFFF; /* 32Bit: 4GB address range */
61 HighestAddress
.u
.LowPart
= 0x00FFFFFF; /* 24Bit: 16MB address range */
64 BaseAddress
= MmAllocateContiguousAlignedMemory(
68 BoundryAddressMultiple
,
69 CacheEnabled
? MmCached
: MmNonCached
,
74 *LogicalAddress
= MmGetPhysicalAddress(BaseAddress
);
80 HalFlushCommonBuffer (ULONG Unknown1
,
93 HalFreeCommonBuffer (PADAPTER_OBJECT AdapterObject
,
95 PHYSICAL_ADDRESS LogicalAddress
,
99 MmFreeContiguousMemory(VirtualAddress
);
102 PADAPTER_OBJECT STDCALL
103 HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription
,
104 PULONG NumberOfMapRegisters
)
106 * FUNCTION: Returns a pointer to an adapter object for the DMA device
107 * defined in the device description structure
109 * DeviceDescription = Structure describing the attributes of the device
110 * NumberOfMapRegisters (OUT) = Returns the maximum number of map
111 * registers the device driver can
112 * allocate for DMA transfer operations
113 * RETURNS: The allocated adapter object on success
119 PADAPTER_OBJECT AdapterObject
;
123 BOOLEAN ChannelSetup
= TRUE
;
124 DMA_MODE DmaMode
= {0};
126 DPRINT("Entered Function\n");
128 /* Validate parameters in device description, and return a pointer to
129 the adapter object for the requested dma channel */
130 if(DeviceDescription
->Version
!= DEVICE_DESCRIPTION_VERSION
) {
131 DPRINT("Invalid Adapter version!\n");
135 DPRINT("Checking Interface Type: %x \n", DeviceDescription
->InterfaceType
);
136 if (DeviceDescription
->InterfaceType
== PCIBus
) {
137 if (DeviceDescription
->Master
== FALSE
) {
138 DPRINT("Invalid request!\n");
141 ChannelSetup
= FALSE
;
144 /* There are only 8 DMA channels on ISA, so any request above this
145 should not get any channel setup */
146 if (DeviceDescription
->DmaChannel
>= 8) {
147 ChannelSetup
= FALSE
;
150 /* Channel 4 is Reserved for Chaining, so you cant use it */
151 if (DeviceDescription
->DmaChannel
== 4 && ChannelSetup
) {
152 DPRINT("Invalid request!\n");
156 /* Devices that support Scatter/Gather do not need Map Registers */
157 if (DeviceDescription
->ScatterGather
||
158 DeviceDescription
->InterfaceType
== PCIBus
) {
159 *NumberOfMapRegisters
= 0;
162 /* Check if Extended DMA is available (we're just going to do a random read/write
163 I picked Channel 2 because it's the first Channel in the Register */
164 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
.Channel2
), 0x2A);
165 if (READ_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
.Channel2
)) == 0x2A) {
169 /* Find out how many Map Registers we need */
170 DPRINT("Setting up Adapter Settings!\n");
171 MaximumLength
= DeviceDescription
->MaximumLength
& 0x7FFFFFFF;
172 *NumberOfMapRegisters
= BYTES_TO_PAGES(MaximumLength
) + 1;
174 /* Set the Channel Selection */
175 ChannelSelect
= DeviceDescription
->DmaChannel
& 0x03;
176 DmaMode
.Channel
= ChannelSelect
;
178 /* Get the Controller Setup */
179 Controller
= (DeviceDescription
->DmaChannel
& 0x04) ? 2 : 1;
181 /* Get the Adapter Object */
182 if (HalpEisaAdapter
[DeviceDescription
->DmaChannel
] != NULL
) {
184 /* Already allocated, return it */
185 DPRINT("Getting an Adapter Object from the Cache\n");
186 AdapterObject
= HalpEisaAdapter
[DeviceDescription
->DmaChannel
];
188 /* Do we need more Map Registers this time? */
189 if ((AdapterObject
->NeedsMapRegisters
) &&
190 (*NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)) {
191 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
196 /* We have to allocate a new object! How exciting! */
197 DPRINT("Allocating a new Adapter Object\n");
198 AdapterObject
= HalpAllocateAdapterEx(*NumberOfMapRegisters
,
200 DeviceDescription
->Dma32BitAddresses
);
202 if (AdapterObject
== NULL
) return NULL
;
204 HalpEisaAdapter
[DeviceDescription
->DmaChannel
] = AdapterObject
;
206 if (!*NumberOfMapRegisters
) {
207 /* Easy case, no Map Registers needed */
208 AdapterObject
->NeedsMapRegisters
= FALSE
;
210 /* If you're the master, you get all you want */
211 if (DeviceDescription
->Master
) {
212 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
214 AdapterObject
->MapRegistersPerChannel
= 1;
217 /* We Desire Registers */
218 AdapterObject
->NeedsMapRegisters
= TRUE
;
220 /* The registers you want */
221 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
223 /* Increase commitment */
224 MasterAdapter
->CommittedMapRegisters
+= *NumberOfMapRegisters
;
228 /* Set up DMA Structure */
229 if (Controller
== 1) {
230 AdapterObject
->AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController1
);
232 AdapterObject
->AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController2
);
235 /* Set up Some Adapter Data */
236 DPRINT("Setting up an Adapter Object\n");
237 AdapterObject
->IgnoreCount
= DeviceDescription
->IgnoreCount
;
238 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
239 AdapterObject
->Dma64BitAddresses
= DeviceDescription
->Dma64BitAddresses
;
240 AdapterObject
->ScatterGather
= DeviceDescription
->ScatterGather
;
241 AdapterObject
->MasterDevice
= DeviceDescription
->Master
;
242 if (DeviceDescription
->InterfaceType
!= PCIBus
) AdapterObject
->LegacyAdapter
= TRUE
;
244 /* Everything below is not required if we don't need a channel */
246 DPRINT("Retuning Adapter Object without Channel Setup\n");
247 return AdapterObject
;
250 AdapterObject
->ChannelNumber
= ChannelSelect
;
253 /* Set up the Page Port */
254 if (Controller
== 1) {
255 switch (ChannelSelect
) {
258 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel0
) +
259 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
262 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel1
) +
263 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
266 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel2
) +
267 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
270 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel3
) +
271 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
275 /* Set Controller Number */
276 AdapterObject
->AdapterNumber
= 1;
278 switch (ChannelSelect
) {
281 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel5
) +
282 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
285 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel6
) +
286 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
289 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel7
) +
290 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
294 /* Set Controller Number */
295 AdapterObject
->AdapterNumber
= 2;
298 /* Set up the Extended Register */
300 DMA_EXTENDED_MODE ExtendedMode
;
302 ExtendedMode
.ChannelNumber
= ChannelSelect
;
304 switch (DeviceDescription
->DmaSpeed
) {
307 ExtendedMode
.TimingMode
= COMPATIBLE_TIMING
;
311 ExtendedMode
.TimingMode
= TYPE_A_TIMING
;
315 ExtendedMode
.TimingMode
= TYPE_B_TIMING
;
319 ExtendedMode
.TimingMode
= BURST_TIMING
;
326 switch (DeviceDescription
->DmaWidth
) {
329 ExtendedMode
.TransferSize
= B_8BITS
;
333 ExtendedMode
.TransferSize
= B_16BITS
;
337 ExtendedMode
.TransferSize
= B_32BITS
;
344 if (Controller
== 1) {
345 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode1
),
346 *((PUCHAR
)&ExtendedMode
));
348 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode2
),
349 *((PUCHAR
)&ExtendedMode
));
353 /* Do 8/16-bit validation */
354 DPRINT("Validating an Adapter Object\n");
355 if (!DeviceDescription
->Master
) {
356 if ((DeviceDescription
->DmaWidth
== Width8Bits
) && (Controller
!= 1)) {
357 return NULL
; /* 8-bit is only avalable on Controller 1 */
358 } else if (DeviceDescription
->DmaWidth
== Width16Bits
) {
359 if (Controller
!= 2) {
360 return NULL
; /* 16-bit is only avalable on Controller 2 */
362 AdapterObject
->Width16Bits
= TRUE
;
367 DPRINT("Final DMA Request Mode Setting of the Adapter Object\n");
369 /* Set the DMA Request Modes */
370 if (DeviceDescription
->Master
) {
371 /* This is a cascade request */
372 DmaMode
.RequestMode
= CASCADE_REQUEST_MODE
;
374 /* Send the request */
375 if (AdapterObject
->AdapterNumber
== 1) {
376 /* Set the Request Data */
377 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterObject
->AdapterBaseVa
)->Mode
,
378 AdapterObject
->AdapterModeByte
);
380 /* Unmask DMA Channel */
381 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterObject
->AdapterBaseVa
)->SingleMask
,
382 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
384 /* Set the Request Data */
385 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterObject
->AdapterBaseVa
)->Mode
,
386 AdapterObject
->AdapterModeByte
);
388 /* Unmask DMA Channel */
389 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterObject
->AdapterBaseVa
)->SingleMask
,
390 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
392 } else if (DeviceDescription
->DemandMode
) {
393 /* This is a Demand request */
394 DmaMode
.RequestMode
= DEMAND_REQUEST_MODE
;
397 DmaMode
.RequestMode
= SINGLE_REQUEST_MODE
;
400 /* Auto Initialize Enabled or Not*/
401 DmaMode
.AutoInitialize
= DeviceDescription
->AutoInitialize
;
402 AdapterObject
->AdapterMode
= DmaMode
;
403 return AdapterObject
;
407 HalReadDmaCounter (PADAPTER_OBJECT AdapterObject
)
412 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
414 /* Send the Request to the specific controller */
415 if (AdapterObject
->AdapterNumber
== 1) {
417 /* Set this for Ease */
418 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
421 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
424 Count
= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
425 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
426 Count
|= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
427 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
431 /* Set this for Ease */
432 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
435 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
438 Count
= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
439 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
440 Count
|= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
441 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
444 /* Play around with the count (add bias and multiply by 2 if 16-bit DMA) */
446 if (AdapterObject
->Width16Bits
) Count
*=2 ;
448 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);