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 if ((AdapterObject
->Dma64BitAddresses
) && (AdapterObject
->MasterDevice
)) {
58 HighestAddress
.QuadPart
= 0xFFFFFFFFFFFFFFFFLL
; /* 64Bit: >4GB address range */
60 } else if ((AdapterObject
->Dma32BitAddresses
) && (AdapterObject
->MasterDevice
)) {
61 HighestAddress
.QuadPart
= 0xFFFFFFFF; /* 32Bit: 4GB address range */
63 HighestAddress
.QuadPart
= 0x00FFFFFF; /* 24Bit: 16MB address range */
64 if (AdapterObject
->Width16Bits
)
66 BoundryAddressMultiple
.QuadPart
= 0x20000; /* 128k boundary */
70 BoundryAddressMultiple
.QuadPart
= 0x10000; /* 64k boundary */
74 BaseAddress
= MmAllocateContiguousMemorySpecifyCache(
78 BoundryAddressMultiple
,
79 CacheEnabled
? MmCached
: MmNonCached
);
83 *LogicalAddress
= MmGetPhysicalAddress(BaseAddress
);
89 HalFlushCommonBuffer (ULONG Unknown1
,
102 HalFreeCommonBuffer (PADAPTER_OBJECT AdapterObject
,
104 PHYSICAL_ADDRESS LogicalAddress
,
105 PVOID VirtualAddress
,
106 BOOLEAN CacheEnabled
)
108 MmFreeContiguousMemory(VirtualAddress
);
111 PADAPTER_OBJECT STDCALL
112 HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription
,
113 PULONG NumberOfMapRegisters
)
115 * FUNCTION: Returns a pointer to an adapter object for the DMA device
116 * defined in the device description structure
118 * DeviceDescription = Structure describing the attributes of the device
119 * NumberOfMapRegisters (OUT) = Returns the maximum number of map
120 * registers the device driver can
121 * allocate for DMA transfer operations
122 * RETURNS: The allocated adapter object on success
128 PADAPTER_OBJECT AdapterObject
;
132 BOOLEAN ChannelSetup
= TRUE
;
133 DMA_MODE DmaMode
= {0};
135 DPRINT("Entered Function\n");
137 /* Validate parameters in device description, and return a pointer to
138 the adapter object for the requested dma channel */
139 if(DeviceDescription
->Version
!= DEVICE_DESCRIPTION_VERSION
) {
140 DPRINT("Invalid Adapter version!\n");
144 DPRINT("Checking Interface Type: %x \n", DeviceDescription
->InterfaceType
);
145 if (DeviceDescription
->InterfaceType
== PCIBus
) {
146 if (DeviceDescription
->Master
== FALSE
) {
147 DPRINT("Invalid request!\n");
150 ChannelSetup
= FALSE
;
153 /* There are only 8 DMA channels on ISA, so any request above this
154 should not get any channel setup */
155 if (DeviceDescription
->DmaChannel
>= 8) {
156 ChannelSetup
= FALSE
;
159 /* Channel 4 is Reserved for Chaining, so you cant use it */
160 if (DeviceDescription
->DmaChannel
== 4 && ChannelSetup
) {
161 DPRINT("Invalid request!\n");
165 /* Devices that support Scatter/Gather do not need Map Registers */
166 if (DeviceDescription
->ScatterGather
||
167 DeviceDescription
->InterfaceType
== PCIBus
) {
168 *NumberOfMapRegisters
= 0;
171 /* Check if Extended DMA is available (we're just going to do a random read/write
172 I picked Channel 2 because it's the first Channel in the Register */
173 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
.Channel2
), 0x2A);
174 if (READ_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
.Channel2
)) == 0x2A) {
178 /* Find out how many Map Registers we need */
179 DPRINT("Setting up Adapter Settings!\n");
180 MaximumLength
= DeviceDescription
->MaximumLength
& 0x7FFFFFFF;
181 *NumberOfMapRegisters
= BYTES_TO_PAGES(MaximumLength
) + 1;
183 /* Set the Channel Selection */
184 ChannelSelect
= DeviceDescription
->DmaChannel
& 0x03;
185 DmaMode
.Channel
= ChannelSelect
;
187 /* Get the Controller Setup */
188 Controller
= (DeviceDescription
->DmaChannel
& 0x04) ? 2 : 1;
190 /* Get the Adapter Object */
191 if (HalpEisaAdapter
[DeviceDescription
->DmaChannel
] != NULL
) {
193 /* Already allocated, return it */
194 DPRINT("Getting an Adapter Object from the Cache\n");
195 AdapterObject
= HalpEisaAdapter
[DeviceDescription
->DmaChannel
];
197 /* Do we need more Map Registers this time? */
198 if ((AdapterObject
->NeedsMapRegisters
) &&
199 (*NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)) {
200 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
205 /* We have to allocate a new object! How exciting! */
206 DPRINT("Allocating a new Adapter Object\n");
207 AdapterObject
= HalpAllocateAdapterEx(*NumberOfMapRegisters
,
209 DeviceDescription
->Dma32BitAddresses
);
211 if (AdapterObject
== NULL
) return NULL
;
213 HalpEisaAdapter
[DeviceDescription
->DmaChannel
] = AdapterObject
;
215 if (!*NumberOfMapRegisters
) {
216 /* Easy case, no Map Registers needed */
217 AdapterObject
->NeedsMapRegisters
= FALSE
;
219 /* If you're the master, you get all you want */
220 if (DeviceDescription
->Master
) {
221 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
223 AdapterObject
->MapRegistersPerChannel
= 1;
226 /* We Desire Registers */
227 AdapterObject
->NeedsMapRegisters
= TRUE
;
229 /* The registers you want */
230 AdapterObject
->MapRegistersPerChannel
= *NumberOfMapRegisters
;
232 /* Increase commitment */
233 MasterAdapter
->CommittedMapRegisters
+= *NumberOfMapRegisters
;
237 /* Set up DMA Structure */
238 if (Controller
== 1) {
239 AdapterObject
->AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController1
);
241 AdapterObject
->AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController2
);
244 /* Set up Some Adapter Data */
245 DPRINT("Setting up an Adapter Object\n");
246 AdapterObject
->IgnoreCount
= DeviceDescription
->IgnoreCount
;
247 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
248 AdapterObject
->Dma64BitAddresses
= DeviceDescription
->Dma64BitAddresses
;
249 AdapterObject
->ScatterGather
= DeviceDescription
->ScatterGather
;
250 AdapterObject
->MasterDevice
= DeviceDescription
->Master
;
251 if (DeviceDescription
->InterfaceType
!= PCIBus
) AdapterObject
->LegacyAdapter
= TRUE
;
253 /* Everything below is not required if we don't need a channel */
255 DPRINT("Retuning Adapter Object without Channel Setup\n");
256 return AdapterObject
;
259 AdapterObject
->ChannelNumber
= ChannelSelect
;
262 /* Set up the Page Port */
263 if (Controller
== 1) {
264 switch (ChannelSelect
) {
267 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel0
) +
268 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
271 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel1
) +
272 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
275 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel2
) +
276 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
279 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel3
) +
280 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
284 /* Set Controller Number */
285 AdapterObject
->AdapterNumber
= 1;
287 switch (ChannelSelect
) {
290 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel5
) +
291 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
294 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel6
) +
295 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
298 AdapterObject
->PagePort
= (PUCHAR
)(FIELD_OFFSET(DMA_PAGE
, Channel7
) +
299 FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
));
303 /* Set Controller Number */
304 AdapterObject
->AdapterNumber
= 2;
307 /* Set up the Extended Register */
309 DMA_EXTENDED_MODE ExtendedMode
;
311 ExtendedMode
.ChannelNumber
= ChannelSelect
;
313 switch (DeviceDescription
->DmaSpeed
) {
316 ExtendedMode
.TimingMode
= COMPATIBLE_TIMING
;
320 ExtendedMode
.TimingMode
= TYPE_A_TIMING
;
324 ExtendedMode
.TimingMode
= TYPE_B_TIMING
;
328 ExtendedMode
.TimingMode
= BURST_TIMING
;
335 switch (DeviceDescription
->DmaWidth
) {
338 ExtendedMode
.TransferSize
= B_8BITS
;
342 ExtendedMode
.TransferSize
= B_16BITS
;
346 ExtendedMode
.TransferSize
= B_32BITS
;
353 if (Controller
== 1) {
354 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode1
),
355 *((PUCHAR
)&ExtendedMode
));
357 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode2
),
358 *((PUCHAR
)&ExtendedMode
));
362 /* Do 8/16-bit validation */
363 DPRINT("Validating an Adapter Object\n");
364 if (!DeviceDescription
->Master
) {
365 if ((DeviceDescription
->DmaWidth
== Width8Bits
) && (Controller
!= 1)) {
366 return NULL
; /* 8-bit is only avalable on Controller 1 */
367 } else if (DeviceDescription
->DmaWidth
== Width16Bits
) {
368 if (Controller
!= 2) {
369 return NULL
; /* 16-bit is only avalable on Controller 2 */
371 AdapterObject
->Width16Bits
= TRUE
;
376 DPRINT("Final DMA Request Mode Setting of the Adapter Object\n");
378 /* Set the DMA Request Modes */
379 if (DeviceDescription
->Master
) {
380 /* This is a cascade request */
381 DmaMode
.RequestMode
= CASCADE_REQUEST_MODE
;
383 /* Send the request */
384 if (AdapterObject
->AdapterNumber
== 1) {
385 /* Set the Request Data */
386 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterObject
->AdapterBaseVa
)->Mode
,
387 AdapterObject
->AdapterModeByte
);
389 /* Unmask DMA Channel */
390 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterObject
->AdapterBaseVa
)->SingleMask
,
391 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
393 /* Set the Request Data */
394 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterObject
->AdapterBaseVa
)->Mode
,
395 AdapterObject
->AdapterModeByte
);
397 /* Unmask DMA Channel */
398 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterObject
->AdapterBaseVa
)->SingleMask
,
399 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
401 } else if (DeviceDescription
->DemandMode
) {
402 /* This is a Demand request */
403 DmaMode
.RequestMode
= DEMAND_REQUEST_MODE
;
406 DmaMode
.RequestMode
= SINGLE_REQUEST_MODE
;
409 /* Auto Initialize Enabled or Not*/
410 DmaMode
.AutoInitialize
= DeviceDescription
->AutoInitialize
;
411 AdapterObject
->AdapterMode
= DmaMode
;
412 return AdapterObject
;
416 HalReadDmaCounter (PADAPTER_OBJECT AdapterObject
)
421 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
423 /* Send the Request to the specific controller */
424 if (AdapterObject
->AdapterNumber
== 1) {
426 /* Set this for Ease */
427 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
430 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
433 Count
= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
434 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
435 Count
|= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
436 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
440 /* Set this for Ease */
441 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
444 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
447 Count
= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
448 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
449 Count
|= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
450 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
453 /* Play around with the count (add bias and multiply by 2 if 16-bit DMA) */
455 if (AdapterObject
->Width16Bits
) Count
*=2 ;
457 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);