[INTRIN]
[reactos.git] / reactos / subsystems / mvdm / ntvdm / hardware / dma.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dma.c
5 * PURPOSE: Direct Memory Access Controller emulation -
6 * i8237A compatible with 74LS612 Memory Mapper extension
7 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #define NDEBUG
13
14 #include "emulator.h"
15 #include "io.h"
16 #include "dma.h"
17
18 /* PRIVATE VARIABLES **********************************************************/
19
20 /*
21 * DMA Controller 0 (Channels 0..3): Slave controller
22 * DMA Controller 1 (Channels 4..7): Master controller
23 */
24 static DMA_CONTROLLER DmaControllers[DMA_CONTROLLERS];
25
26 /* External page registers for each channel of the two DMA controllers */
27 static DMA_PAGE_REGISTER DmaPageRegisters[DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS];
28
29 /* PRIVATE FUNCTIONS **********************************************************/
30
31 #define READ_ADDR(CtrlIndex, ChanIndex, Data) \
32 do { \
33 (Data) = \
34 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
35 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
36 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
37 } while(0)
38
39 #define READ_CNT(CtrlIndex, ChanIndex, Data) \
40 do { \
41 (Data) = \
42 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
43 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
44 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
45 } while(0)
46
47 static BYTE WINAPI DmaReadPort(USHORT Port)
48 {
49 BYTE ReadValue = 0xFF;
50
51 switch (Port)
52 {
53 /* Start Address Registers */
54 {
55 case 0x00:
56 READ_ADDR(0, 0, ReadValue);
57 return ReadValue;
58 case 0x02:
59 READ_ADDR(0, 1, ReadValue);
60 return ReadValue;
61 case 0x04:
62 READ_ADDR(0, 2, ReadValue);
63 return ReadValue;
64 case 0x06:
65 READ_ADDR(0, 3, ReadValue);
66 return ReadValue;
67 case 0xC0:
68 READ_ADDR(1, 0, ReadValue);
69 return ReadValue;
70 case 0xC4:
71 READ_ADDR(1, 1, ReadValue);
72 return ReadValue;
73 case 0xC8:
74 READ_ADDR(1, 2, ReadValue);
75 return ReadValue;
76 case 0xCC:
77 READ_ADDR(1, 3, ReadValue);
78 return ReadValue;
79 }
80
81 /* Count Address Registers */
82 {
83 case 0x01:
84 READ_CNT(0, 0, ReadValue);
85 return ReadValue;
86 case 0x03:
87 READ_CNT(0, 1, ReadValue);
88 return ReadValue;
89 case 0x05:
90 READ_CNT(0, 2, ReadValue);
91 return ReadValue;
92 case 0x07:
93 READ_CNT(0, 3, ReadValue);
94 return ReadValue;
95 case 0xC2:
96 READ_CNT(1, 0, ReadValue);
97 return ReadValue;
98 case 0xC6:
99 READ_CNT(1, 1, ReadValue);
100 return ReadValue;
101 case 0xCA:
102 READ_CNT(1, 2, ReadValue);
103 return ReadValue;
104 case 0xCE:
105 READ_CNT(1, 3, ReadValue);
106 return ReadValue;
107 }
108
109 /* Status Registers */
110 {
111 case 0x08:
112 return DmaControllers[0].Status;
113 case 0xD0:
114 return DmaControllers[1].Status;
115 }
116
117 /* DMA Intermediate (Temporary) Registers */
118 {
119 case 0x0D:
120 return DmaControllers[0].TempReg;
121 case 0xDA:
122 return DmaControllers[1].TempReg;
123 }
124 }
125
126 return 0x00;
127 }
128
129 #define WRITE_ADDR(CtrlIndex, ChanIndex, Data) \
130 do { \
131 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseAddress + \
132 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
133 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
134 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
135 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
136 } while(0)
137
138 #define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
139 do { \
140 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseWordCnt + \
141 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
142 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
143 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
144 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
145 } while(0)
146
147 static VOID WINAPI DmaWritePort(USHORT Port, BYTE Data)
148 {
149 switch (Port)
150 {
151 /* Start Address Registers */
152 {
153 case 0x00:
154 WRITE_ADDR(0, 0, Data);
155 break;
156 case 0x02:
157 WRITE_ADDR(0, 1, Data);
158 break;
159 case 0x04:
160 WRITE_ADDR(0, 2, Data);
161 break;
162 case 0x06:
163 WRITE_ADDR(0, 3, Data);
164 break;
165 case 0xC0:
166 WRITE_ADDR(1, 0, Data);
167 break;
168 case 0xC4:
169 WRITE_ADDR(1, 1, Data);
170 break;
171 case 0xC8:
172 WRITE_ADDR(1, 2, Data);
173 break;
174 case 0xCC:
175 WRITE_ADDR(1, 3, Data);
176 break;
177 }
178
179 /* Count Address Registers */
180 {
181 case 0x01:
182 WRITE_CNT(0, 0, Data);
183 break;
184 case 0x03:
185 WRITE_CNT(0, 1, Data);
186 break;
187 case 0x05:
188 WRITE_CNT(0, 2, Data);
189 break;
190 case 0x07:
191 WRITE_CNT(0, 3, Data);
192 break;
193 case 0xC2:
194 WRITE_CNT(1, 0, Data);
195 break;
196 case 0xC6:
197 WRITE_CNT(1, 1, Data);
198 break;
199 case 0xCA:
200 WRITE_CNT(1, 2, Data);
201 break;
202 case 0xCE:
203 WRITE_CNT(1, 3, Data);
204 break;
205 }
206
207 /* Command Registers */
208 {
209 case 0x08:
210 DmaControllers[0].Command = Data;
211 break;
212 case 0xD0:
213 DmaControllers[1].Command = Data;
214 break;
215 }
216
217 /* Request Registers */
218 {
219 case 0x09:
220 DmaControllers[0].Request = Data;
221 break;
222 case 0xD2:
223 DmaControllers[1].Request = Data;
224 break;
225 }
226
227 /* Flip-Flop Reset */
228 {
229 case 0x0C:
230 DmaControllers[0].FlipFlop = 0;
231 break;
232 case 0xD8:
233 DmaControllers[1].FlipFlop = 0;
234 break;
235 }
236
237 /* DMA Master Reset */
238 {
239 case 0x0D:
240 DmaControllers[0].Command = 0x00;
241 DmaControllers[0].Status = 0x00;
242 DmaControllers[0].Request = 0x00;
243 DmaControllers[0].TempReg = 0x00;
244 DmaControllers[0].FlipFlop = 0;
245 DmaControllers[0].Mask = 0x0F;
246 break;
247 case 0xDA:
248 DmaControllers[1].Command = 0x00;
249 DmaControllers[1].Status = 0x00;
250 DmaControllers[1].Request = 0x00;
251 DmaControllers[1].TempReg = 0x00;
252 DmaControllers[1].FlipFlop = 0;
253 DmaControllers[1].Mask = 0x0F;
254 break;
255 }
256 }
257 }
258
259 /* Page Address Registers */
260
261 static BYTE WINAPI DmaPageReadPort(USHORT Port)
262 {
263 switch (Port)
264 {
265 case 0x87:
266 return DmaPageRegisters[0].Page;
267 case 0x83:
268 return DmaPageRegisters[1].Page;
269 case 0x81:
270 return DmaPageRegisters[2].Page;
271 case 0x82:
272 return DmaPageRegisters[3].Page;
273 case 0x8F:
274 return DmaPageRegisters[4].Page;
275 case 0x8B:
276 return DmaPageRegisters[5].Page;
277 case 0x89:
278 return DmaPageRegisters[6].Page;
279 case 0x8A:
280 return DmaPageRegisters[7].Page;
281 }
282
283 return 0x00;
284 }
285
286 static VOID WINAPI DmaPageWritePort(USHORT Port, BYTE Data)
287 {
288 switch (Port)
289 {
290 case 0x87:
291 DmaPageRegisters[0].Page = Data;
292 break;
293 case 0x83:
294 DmaPageRegisters[1].Page = Data;
295 break;
296 case 0x81:
297 DmaPageRegisters[2].Page = Data;
298 break;
299 case 0x82:
300 DmaPageRegisters[3].Page = Data;
301 break;
302 case 0x8F:
303 DmaPageRegisters[4].Page = Data;
304 break;
305 case 0x8B:
306 DmaPageRegisters[5].Page = Data;
307 break;
308 case 0x89:
309 DmaPageRegisters[6].Page = Data;
310 break;
311 case 0x8A:
312 DmaPageRegisters[7].Page = Data;
313 break;
314 }
315 }
316
317 /* PUBLIC FUNCTIONS ***********************************************************/
318
319 VOID DmaInitialize(VOID)
320 {
321 /* Register the I/O Ports */
322
323 /* Channels 0(Reserved)..3 */
324 RegisterIoPort(0x00, NULL, DmaWritePort); /* Start Address Register 0 (Reserved) */
325 RegisterIoPort(0x01, NULL, DmaWritePort); /* Count Address Register 0 (Reserved) */
326 RegisterIoPort(0x02, NULL, DmaWritePort); /* Start Address Register 1 */
327 RegisterIoPort(0x03, NULL, DmaWritePort); /* Count Address Register 1 */
328 RegisterIoPort(0x04, NULL, DmaWritePort); /* Start Address Register 2 */
329 RegisterIoPort(0x05, NULL, DmaWritePort); /* Count Address Register 2 */
330 RegisterIoPort(0x06, NULL, DmaWritePort); /* Start Address Register 3 */
331 RegisterIoPort(0x07, NULL, DmaWritePort); /* Count Address Register 3 */
332
333 RegisterIoPort(0x08, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
334 RegisterIoPort(0x09, NULL, DmaWritePort); /* Request Register */
335 RegisterIoPort(0x0A, NULL, DmaWritePort); /* Single Channel Mask Register */
336 RegisterIoPort(0x0B, NULL, DmaWritePort); /* Mode Register */
337 RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
338 RegisterIoPort(0x0D, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
339 RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
340 RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset Register */
341
342
343 /* Channels 4(Reserved)..7 */
344 RegisterIoPort(0xC0, NULL, DmaWritePort); /* Start Address Register 4 (Reserved) */
345 RegisterIoPort(0xC2, NULL, DmaWritePort); /* Count Address Register 4 (Reserved) */
346 RegisterIoPort(0xC4, NULL, DmaWritePort); /* Start Address Register 5 */
347 RegisterIoPort(0xC6, NULL, DmaWritePort); /* Count Address Register 5 */
348 RegisterIoPort(0xC8, NULL, DmaWritePort); /* Start Address Register 6 */
349 RegisterIoPort(0xCA, NULL, DmaWritePort); /* Count Address Register 6 */
350 RegisterIoPort(0xCC, NULL, DmaWritePort); /* Start Address Register 7 */
351 RegisterIoPort(0xCE, NULL, DmaWritePort); /* Count Address Register 7 */
352
353 RegisterIoPort(0xD0, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
354 RegisterIoPort(0xD2, NULL, DmaWritePort); /* Request Register */
355 RegisterIoPort(0xD4, NULL, DmaWritePort); /* Single Channel Mask Register */
356 RegisterIoPort(0xD6, NULL, DmaWritePort); /* Mode Register */
357 RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
358 RegisterIoPort(0xDA, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
359 RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
360 RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset Register */
361
362
363 /* Channels Page Address Registers */
364 RegisterIoPort(0x87, DmaPageReadPort, DmaPageWritePort); /* Channel 0 (Reserved) */
365 RegisterIoPort(0x83, DmaPageReadPort, DmaPageWritePort); /* Channel 1 */
366 RegisterIoPort(0x81, DmaPageReadPort, DmaPageWritePort); /* Channel 2 */
367 RegisterIoPort(0x82, DmaPageReadPort, DmaPageWritePort); /* Channel 3 */
368 RegisterIoPort(0x8F, DmaPageReadPort, DmaPageWritePort); /* Channel 4 (Reserved) */
369 RegisterIoPort(0x8B, DmaPageReadPort, DmaPageWritePort); /* Channel 5 */
370 RegisterIoPort(0x89, DmaPageReadPort, DmaPageWritePort); /* Channel 6 */
371 RegisterIoPort(0x8A, DmaPageReadPort, DmaPageWritePort); /* Channel 7 */
372 }
373
374
375
376 DWORD
377 WINAPI
378 VDDRequestDMA(IN HANDLE hVdd,
379 IN WORD iChannel,
380 IN OUT PVOID Buffer,
381 IN DWORD length)
382 {
383 UNREFERENCED_PARAMETER(hVdd);
384
385 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
386 {
387 SetLastError(ERROR_INVALID_ADDRESS);
388 return FALSE;
389 }
390
391 UNIMPLEMENTED;
392 return 0;
393 }
394
395 BOOL
396 WINAPI
397 VDDQueryDMA(IN HANDLE hVdd,
398 IN WORD iChannel,
399 IN PVDD_DMA_INFO pDmaInfo)
400 {
401 PDMA_CONTROLLER pDcp;
402 WORD Channel;
403
404 UNREFERENCED_PARAMETER(hVdd);
405
406 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
407 {
408 SetLastError(ERROR_INVALID_ADDRESS);
409 return FALSE;
410 }
411
412 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
413 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
414
415 pDmaInfo->addr = pDcp->DmaChannel[Channel].CurrAddress;
416 pDmaInfo->count = pDcp->DmaChannel[Channel].CurrWordCnt;
417
418 // pDmaInfo->page = DmaPageRegisters[iChannel].Page;
419 pDmaInfo->status = pDcp->Status;
420 pDmaInfo->mode = pDcp->DmaChannel[Channel].Mode;
421 pDmaInfo->mask = pDcp->Mask;
422
423 return TRUE;
424 }
425
426 BOOL
427 WINAPI
428 VDDSetDMA(IN HANDLE hVdd,
429 IN WORD iChannel,
430 IN WORD fDMA,
431 IN PVDD_DMA_INFO pDmaInfo)
432 {
433 PDMA_CONTROLLER pDcp;
434 WORD Channel;
435
436 UNREFERENCED_PARAMETER(hVdd);
437
438 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
439 {
440 SetLastError(ERROR_INVALID_ADDRESS);
441 return FALSE;
442 }
443
444 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
445 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
446
447 if (fDMA & VDD_DMA_ADDR)
448 pDcp->DmaChannel[Channel].CurrAddress = pDmaInfo->addr;
449
450 if (fDMA & VDD_DMA_COUNT)
451 pDcp->DmaChannel[Channel].CurrWordCnt = pDmaInfo->count;
452
453 // if (fDMA & VDD_DMA_PAGE)
454 // DmaPageRegisters[iChannel].Page = pDmaInfo->page;
455
456 if (fDMA & VDD_DMA_STATUS)
457 pDcp->Status = pDmaInfo->status;
458
459 return TRUE;
460 }
461
462 /* EOF */