7abee56565257feee9436a90c6a16835c4456c02
[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 HighestAddress.u.HighPart = 0;
58 if ((AdapterObject->Dma32BitAddresses) && (AdapterObject->MasterDevice)) {
59 HighestAddress.u.LowPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */
60 } else {
61 HighestAddress.u.LowPart = 0x00FFFFFF; /* 24Bit: 16MB address range */
62 }
63
64 BaseAddress = MmAllocateContiguousAlignedMemory(
65 Length,
66 LowestAddress,
67 HighestAddress,
68 BoundryAddressMultiple,
69 CacheEnabled ? MmCached : MmNonCached,
70 0x10000 );
71 if (!BaseAddress)
72 return 0;
73
74 *LogicalAddress = MmGetPhysicalAddress(BaseAddress);
75
76 return BaseAddress;
77 }
78
79 BOOLEAN STDCALL
80 HalFlushCommonBuffer (ULONG Unknown1,
81 ULONG Unknown2,
82 ULONG Unknown3,
83 ULONG Unknown4,
84 ULONG Unknown5,
85 ULONG Unknown6,
86 ULONG Unknown7,
87 ULONG Unknown8)
88 {
89 return TRUE;
90 }
91
92 VOID STDCALL
93 HalFreeCommonBuffer (PADAPTER_OBJECT AdapterObject,
94 ULONG Length,
95 PHYSICAL_ADDRESS LogicalAddress,
96 PVOID VirtualAddress,
97 BOOLEAN CacheEnabled)
98 {
99 MmFreeContiguousMemory(VirtualAddress);
100 }
101
102 PADAPTER_OBJECT STDCALL
103 HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription,
104 PULONG NumberOfMapRegisters)
105 /*
106 * FUNCTION: Returns a pointer to an adapter object for the DMA device
107 * defined in the device description structure
108 * ARGUMENTS:
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
114 * NULL on failure
115 * TODO:
116 * Testing
117 */
118 {
119 PADAPTER_OBJECT AdapterObject;
120 DWORD ChannelSelect;
121 DWORD Controller;
122 ULONG MaximumLength;
123 BOOLEAN ChannelSetup = TRUE;
124 DMA_MODE DmaMode = {0};
125
126 DPRINT("Entered Function\n");
127
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");
132 return NULL;
133 }
134
135 DPRINT("Checking Interface Type: %x \n", DeviceDescription->InterfaceType);
136 if (DeviceDescription->InterfaceType == PCIBus) {
137 if (DeviceDescription->Master == FALSE) {
138 DPRINT("Invalid request!\n");
139 return NULL;
140 }
141 ChannelSetup = FALSE;
142 }
143
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;
148 }
149
150 /* Channel 4 is Reserved for Chaining, so you cant use it */
151 if (DeviceDescription->DmaChannel == 4 && ChannelSetup) {
152 DPRINT("Invalid request!\n");
153 return NULL;
154 }
155
156 /* Devices that support Scatter/Gather do not need Map Registers */
157 if (DeviceDescription->ScatterGather ||
158 DeviceDescription->InterfaceType == PCIBus) {
159 *NumberOfMapRegisters = 0;
160 }
161
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) {
166 HalpEisaDma = TRUE;
167 }
168
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;
173
174 /* Set the Channel Selection */
175 ChannelSelect = DeviceDescription->DmaChannel & 0x03;
176 DmaMode.Channel = ChannelSelect;
177
178 /* Get the Controller Setup */
179 Controller = (DeviceDescription->DmaChannel & 0x04) ? 2 : 1;
180
181 /* Get the Adapter Object */
182 if (HalpEisaAdapter[DeviceDescription->DmaChannel] != NULL) {
183
184 /* Already allocated, return it */
185 DPRINT("Getting an Adapter Object from the Cache\n");
186 AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
187
188 /* Do we need more Map Registers this time? */
189 if ((AdapterObject->NeedsMapRegisters) &&
190 (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel)) {
191 AdapterObject->MapRegistersPerChannel = *NumberOfMapRegisters;
192 }
193
194 } else {
195
196 /* We have to allocate a new object! How exciting! */
197 DPRINT("Allocating a new Adapter Object\n");
198 AdapterObject = HalpAllocateAdapterEx(*NumberOfMapRegisters,
199 FALSE,
200 DeviceDescription->Dma32BitAddresses);
201
202 if (AdapterObject == NULL) return NULL;
203
204 HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
205
206 if (!*NumberOfMapRegisters) {
207 /* Easy case, no Map Registers needed */
208 AdapterObject->NeedsMapRegisters = FALSE;
209
210 /* If you're the master, you get all you want */
211 if (DeviceDescription->Master) {
212 AdapterObject->MapRegistersPerChannel= *NumberOfMapRegisters;
213 } else {
214 AdapterObject->MapRegistersPerChannel = 1;
215 }
216 } else {
217 /* We Desire Registers */
218 AdapterObject->NeedsMapRegisters = TRUE;
219
220 /* The registers you want */
221 AdapterObject->MapRegistersPerChannel = *NumberOfMapRegisters;
222
223 /* Increase commitment */
224 MasterAdapter->CommittedMapRegisters += *NumberOfMapRegisters;
225 }
226 }
227
228 /* Set up DMA Structure */
229 if (Controller == 1) {
230 AdapterObject->AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1);
231 } else {
232 AdapterObject->AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2);
233 }
234
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;
243
244 /* Everything below is not required if we don't need a channel */
245 if (!ChannelSetup) {
246 DPRINT("Retuning Adapter Object without Channel Setup\n");
247 return AdapterObject;
248 }
249
250 AdapterObject->ChannelNumber = ChannelSelect;
251
252
253 /* Set up the Page Port */
254 if (Controller == 1) {
255 switch (ChannelSelect) {
256
257 case 0:
258 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel0) +
259 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
260 break;
261 case 1:
262 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel1) +
263 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
264 break;
265 case 2:
266 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel2) +
267 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
268 break;
269 case 3:
270 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel3) +
271 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
272 break;
273 }
274
275 /* Set Controller Number */
276 AdapterObject->AdapterNumber = 1;
277 } else {
278 switch (ChannelSelect) {
279
280 case 1:
281 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel5) +
282 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
283 break;
284 case 2:
285 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel6) +
286 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
287 break;
288 case 3:
289 AdapterObject->PagePort = (PUCHAR)(FIELD_OFFSET(DMA_PAGE, Channel7) +
290 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages));
291 break;
292 }
293
294 /* Set Controller Number */
295 AdapterObject->AdapterNumber = 2;
296 }
297
298 /* Set up the Extended Register */
299 if (HalpEisaDma) {
300 DMA_EXTENDED_MODE ExtendedMode;
301
302 ExtendedMode.ChannelNumber = ChannelSelect;
303
304 switch (DeviceDescription->DmaSpeed) {
305
306 case Compatible:
307 ExtendedMode.TimingMode = COMPATIBLE_TIMING;
308 break;
309
310 case TypeA:
311 ExtendedMode.TimingMode = TYPE_A_TIMING;
312 break;
313
314 case TypeB:
315 ExtendedMode.TimingMode = TYPE_B_TIMING;
316 break;
317
318 case TypeC:
319 ExtendedMode.TimingMode = BURST_TIMING;
320 break;
321
322 default:
323 return NULL;
324 }
325
326 switch (DeviceDescription->DmaWidth) {
327
328 case Width8Bits:
329 ExtendedMode.TransferSize = B_8BITS;
330 break;
331
332 case Width16Bits:
333 ExtendedMode.TransferSize = B_16BITS;
334 break;
335
336 case Width32Bits:
337 ExtendedMode.TransferSize = B_32BITS;
338 break;
339
340 default:
341 return NULL;
342 }
343
344 if (Controller == 1) {
345 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1),
346 *((PUCHAR)&ExtendedMode));
347 } else {
348 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2),
349 *((PUCHAR)&ExtendedMode));
350 }
351 }
352
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 */
361 } else {
362 AdapterObject->Width16Bits = TRUE;
363 }
364 }
365 }
366
367 DPRINT("Final DMA Request Mode Setting of the Adapter Object\n");
368
369 /* Set the DMA Request Modes */
370 if (DeviceDescription->Master) {
371 /* This is a cascade request */
372 DmaMode.RequestMode = CASCADE_REQUEST_MODE;
373
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);
379
380 /* Unmask DMA Channel */
381 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterObject->AdapterBaseVa)->SingleMask,
382 AdapterObject->ChannelNumber | DMA_CLEARMASK);
383 } else {
384 /* Set the Request Data */
385 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterObject->AdapterBaseVa)->Mode,
386 AdapterObject->AdapterModeByte);
387
388 /* Unmask DMA Channel */
389 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterObject->AdapterBaseVa)->SingleMask,
390 AdapterObject->ChannelNumber | DMA_CLEARMASK);
391 }
392 } else if (DeviceDescription->DemandMode) {
393 /* This is a Demand request */
394 DmaMode.RequestMode = DEMAND_REQUEST_MODE;
395 } else {
396 /* Normal Request */
397 DmaMode.RequestMode = SINGLE_REQUEST_MODE;
398 }
399
400 /* Auto Initialize Enabled or Not*/
401 DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
402 AdapterObject->AdapterMode = DmaMode;
403 return AdapterObject;
404 }
405
406 ULONG STDCALL
407 HalReadDmaCounter (PADAPTER_OBJECT AdapterObject)
408 {
409 KIRQL OldIrql;
410 ULONG Count;
411
412 KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
413
414 /* Send the Request to the specific controller */
415 if (AdapterObject->AdapterNumber == 1) {
416
417 /* Set this for Ease */
418 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
419
420 /* Send Reset */
421 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
422
423 /* Read Count */
424 Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
425 [AdapterObject->ChannelNumber].DmaBaseCount);
426 Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
427 [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
428
429 } else {
430
431 /* Set this for Ease */
432 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
433
434 /* Send Reset */
435 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
436
437 /* Read Count */
438 Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
439 [AdapterObject->ChannelNumber].DmaBaseCount);
440 Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount
441 [AdapterObject->ChannelNumber].DmaBaseCount) << 8;
442 }
443
444 /* Play around with the count (add bias and multiply by 2 if 16-bit DMA) */
445 Count ++;
446 if (AdapterObject->Width16Bits) Count *=2 ;
447
448 KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
449
450 /* Return it */
451 return Count;
452 }
453
454 /* EOF */