Allocate the map registers according to the dma controllers properties (boundary...
[reactos.git] / reactos / hal / halx86 / generic / dma.c
1 /* $Id$
2 *
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 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <hal.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 /* Adapters for each channel */
19 PADAPTER_OBJECT HalpEisaAdapter[8];
20
21 /* FUNCTIONS *****************************************************************/
22
23 VOID
24 HalpInitDma (VOID)
25 {
26 /* TODO: Initialize the first Map Buffer */
27 }
28
29 PVOID STDCALL
30 HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject,
31 ULONG Length,
32 PPHYSICAL_ADDRESS LogicalAddress,
33 BOOLEAN CacheEnabled)
34 /*
35 * FUNCTION: Allocates memory that is visible to both the processor(s) and
36 * a dma device
37 * ARGUMENTS:
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
42 * buffer
43 * CacheEnabled = Specifies if the memory can be cached
44 * RETURNS: The base virtual address of the memory allocated
45 * NULL on failure
46 * NOTES:
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.
50 */
51 {
52 PHYSICAL_ADDRESS LowestAddress, HighestAddress, BoundryAddressMultiple;
53 PVOID BaseAddress;
54
55 LowestAddress.QuadPart = 0;
56 BoundryAddressMultiple.QuadPart = 0;
57 if ((AdapterObject->Dma64BitAddresses) && (AdapterObject->MasterDevice)) {
58 HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB address range */
59
60 } else if ((AdapterObject->Dma32BitAddresses) && (AdapterObject->MasterDevice)) {
61 HighestAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */
62 } else {
63 HighestAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address range */
64 if (AdapterObject->Width16Bits)
65 {
66 BoundryAddressMultiple.QuadPart = 0x20000; /* 128k boundary */
67 }
68 else
69 {
70 BoundryAddressMultiple.QuadPart = 0x10000; /* 64k boundary */
71 }
72 }
73
74 BaseAddress = MmAllocateContiguousMemorySpecifyCache(
75 Length,
76 LowestAddress,
77 HighestAddress,
78 BoundryAddressMultiple,
79 CacheEnabled ? MmCached : MmNonCached);
80 if (!BaseAddress)
81 return 0;
82
83 *LogicalAddress = MmGetPhysicalAddress(BaseAddress);
84
85 return BaseAddress;
86 }
87
88 BOOLEAN STDCALL
89 HalFlushCommonBuffer (ULONG Unknown1,
90 ULONG Unknown2,
91 ULONG Unknown3,
92 ULONG Unknown4,
93 ULONG Unknown5,
94 ULONG Unknown6,
95 ULONG Unknown7,
96 ULONG Unknown8)
97 {
98 return TRUE;
99 }
100
101 VOID STDCALL
102 HalFreeCommonBuffer (PADAPTER_OBJECT AdapterObject,
103 ULONG Length,
104 PHYSICAL_ADDRESS LogicalAddress,
105 PVOID VirtualAddress,
106 BOOLEAN CacheEnabled)
107 {
108 MmFreeContiguousMemory(VirtualAddress);
109 }
110
111 PADAPTER_OBJECT STDCALL
112 HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription,
113 PULONG NumberOfMapRegisters)
114 /*
115 * FUNCTION: Returns a pointer to an adapter object for the DMA device
116 * defined in the device description structure
117 * ARGUMENTS:
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
123 * NULL on failure
124 * TODO:
125 * Testing
126 */
127 {
128 PADAPTER_OBJECT AdapterObject;
129 DWORD ChannelSelect;
130 DWORD Controller;
131 ULONG MaximumLength;
132 BOOLEAN ChannelSetup = TRUE;
133 DMA_MODE DmaMode = {0};
134
135 DPRINT("Entered Function\n");
136
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");
141 return NULL;
142 }
143
144 DPRINT("Checking Interface Type: %x \n", DeviceDescription->InterfaceType);
145 if (DeviceDescription->InterfaceType == PCIBus) {
146 if (DeviceDescription->Master == FALSE) {
147 DPRINT("Invalid request!\n");
148 return NULL;
149 }
150 ChannelSetup = FALSE;
151 }
152
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;
157 }
158
159 /* Channel 4 is Reserved for Chaining, so you cant use it */
160 if (DeviceDescription->DmaChannel == 4 && ChannelSetup) {
161 DPRINT("Invalid request!\n");
162 return NULL;
163 }
164
165 /* Devices that support Scatter/Gather do not need Map Registers */
166 if (DeviceDescription->ScatterGather ||
167 DeviceDescription->InterfaceType == PCIBus) {
168 *NumberOfMapRegisters = 0;
169 }
170
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) {
175 HalpEisaDma = TRUE;
176 }
177
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;
182
183 /* Set the Channel Selection */
184 ChannelSelect = DeviceDescription->DmaChannel & 0x03;
185 DmaMode.Channel = ChannelSelect;
186
187 /* Get the Controller Setup */
188 Controller = (DeviceDescription->DmaChannel & 0x04) ? 2 : 1;
189
190 /* Get the Adapter Object */
191 if (HalpEisaAdapter[DeviceDescription->DmaChannel] != NULL) {
192
193 /* Already allocated, return it */
194 DPRINT("Getting an Adapter Object from the Cache\n");
195 AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
196
197 /* Do we need more Map Registers this time? */
198 if ((AdapterObject->NeedsMapRegisters) &&
199 (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)) {
200 AdapterObject->MapRegistersPerChannel = *NumberOfMapRegisters;
201 }
202
203 } else {
204
205 /* We have to allocate a new object! How exciting! */
206 DPRINT("Allocating a new Adapter Object\n");
207 AdapterObject = HalpAllocateAdapterEx(*NumberOfMapRegisters,
208 FALSE,
209 DeviceDescription->Dma32BitAddresses);
210
211 if (AdapterObject == NULL) return NULL;
212
213 HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
214
215 if (!*NumberOfMapRegisters) {
216 /* Easy case, no Map Registers needed */
217 AdapterObject->NeedsMapRegisters = FALSE;
218
219 /* If you're the master, you get all you want */
220 if (DeviceDescription->Master) {
221 AdapterObject->MapRegistersPerChannel= *NumberOfMapRegisters;
222 } else {
223 AdapterObject->MapRegistersPerChannel = 1;
224 }
225 } else {
226 /* We Desire Registers */
227 AdapterObject->NeedsMapRegisters = TRUE;
228
229 /* The registers you want */
230 AdapterObject->MapRegistersPerChannel = *NumberOfMapRegisters;
231
232 /* Increase commitment */
233 MasterAdapter->CommittedMapRegisters += *NumberOfMapRegisters;
234 }
235 }
236
237 /* Set up DMA Structure */
238 if (Controller == 1) {
239 AdapterObject->AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1);
240 } else {
241 AdapterObject->AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2);
242 }
243
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;
252
253 /* Everything below is not required if we don't need a channel */
254 if (!ChannelSetup) {
255 DPRINT("Retuning Adapter Object without Channel Setup\n");
256 return AdapterObject;
257 }
258
259 AdapterObject->ChannelNumber = ChannelSelect;
260
261
262 /* Set up the Page Port */
263 if (Controller == 1) {
264 switch (ChannelSelect) {
265
266 case 0:
267 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel0) +
268 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
269 break;
270 case 1:
271 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel1) +
272 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
273 break;
274 case 2:
275 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel2) +
276 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
277 break;
278 case 3:
279 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel3) +
280 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
281 break;
282 }
283
284 /* Set Controller Number */
285 AdapterObject->AdapterNumber = 1;
286 } else {
287 switch (ChannelSelect) {
288
289 case 1:
290 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel5) +
291 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
292 break;
293 case 2:
294 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel6) +
295 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
296 break;
297 case 3:
298 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel7) +
299 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
300 break;
301 }
302
303 /* Set Controller Number */
304 AdapterObject->AdapterNumber = 2;
305 }
306
307 /* Set up the Extended Register */
308 if (HalpEisaDma) {
309 DMA_EXTENDED_MODE ExtendedMode;
310
311 ExtendedMode.ChannelNumber = ChannelSelect;
312
313 switch (DeviceDescription->DmaSpeed) {
314
315 case Compatible:
316 ExtendedMode.TimingMode = COMPATIBLE_TIMING;
317 break;
318
319 case TypeA:
320 ExtendedMode.TimingMode = TYPE_A_TIMING;
321 break;
322
323 case TypeB:
324 ExtendedMode.TimingMode = TYPE_B_TIMING;
325 break;
326
327 case TypeC:
328 ExtendedMode.TimingMode = BURST_TIMING;
329 break;
330
331 default:
332 return NULL;
333 }
334
335 switch (DeviceDescription->DmaWidth) {
336
337 case Width8Bits:
338 ExtendedMode.TransferSize = B_8BITS;
339 break;
340
341 case Width16Bits:
342 ExtendedMode.TransferSize = B_16BITS;
343 break;
344
345 case Width32Bits:
346 ExtendedMode.TransferSize = B_32BITS;
347 break;
348
349 default:
350 return NULL;
351 }
352
353 if (Controller == 1) {
354 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1),
355 *((PUCHAR)&ExtendedMode));
356 } else {
357 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2),
358 *((PUCHAR)&ExtendedMode));
359 }
360 }
361
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 */
370 } else {
371 AdapterObject->Width16Bits = TRUE;
372 }
373 }
374 }
375
376 DPRINT("Final DMA Request Mode Setting of the Adapter Object\n");
377
378 /* Set the DMA Request Modes */
379 if (DeviceDescription->Master) {
380 /* This is a cascade request */
381 DmaMode.RequestMode = CASCADE_REQUEST_MODE;
382
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);
388
389 /* Unmask DMA Channel */
390 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterObject->AdapterBaseVa)->SingleMask,
391 AdapterObject->ChannelNumber | DMA_CLEARMASK);
392 } else {
393 /* Set the Request Data */
394 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterObject->AdapterBaseVa)->Mode,
395 AdapterObject->AdapterModeByte);
396
397 /* Unmask DMA Channel */
398 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterObject->AdapterBaseVa)->SingleMask,
399 AdapterObject->ChannelNumber | DMA_CLEARMASK);
400 }
401 } else if (DeviceDescription->DemandMode) {
402 /* This is a Demand request */
403 DmaMode.RequestMode = DEMAND_REQUEST_MODE;
404 } else {
405 /* Normal Request */
406 DmaMode.RequestMode = SINGLE_REQUEST_MODE;
407 }
408
409 /* Auto Initialize Enabled or Not*/
410 DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
411 AdapterObject->AdapterMode = DmaMode;
412 return AdapterObject;
413 }
414
415 ULONG STDCALL
416 HalReadDmaCounter (PADAPTER_OBJECT AdapterObject)
417 {
418 KIRQL OldIrql;
419 ULONG Count;
420
421 KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
422
423 /* Send the Request to the specific controller */
424 if (AdapterObject->AdapterNumber == 1) {
425
426 /* Set this for Ease */
427 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
428
429 /* Send Reset */
430 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
431
432 /* Read Count */
433 Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
434 [AdapterObject->ChannelNumber].DmaBaseCount);
435 Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
436 [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
437
438 } else {
439
440 /* Set this for Ease */
441 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
442
443 /* Send Reset */
444 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
445
446 /* Read Count */
447 Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
448 [AdapterObject->ChannelNumber].DmaBaseCount);
449 Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
450 [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
451 }
452
453 /* Play around with the count (add bias and multiply by 2 if 16-bit DMA) */
454 Count ++;
455 if (AdapterObject->Width16Bits) Count *=2 ;
456
457 KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
458
459 /* Return it */
460 return Count;
461 }
462
463 /* EOF */