1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/dma.c
5 * PURPOSE: ISA DMA - 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 #include "ntvdm.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #include "emulator.h"
18 #include "dma.h"
19
20 #include "io.h"
21 #include "memory.h"
22
23 /* PRIVATE VARIABLES **********************************************************/
24
25 /*
26 * DMA Controller 0 (Channels 0..3): Slave controller
27 * DMA Controller 1 (Channels 4..7): Master controller
28 */
29 static DMA_CONTROLLER DmaControllers[DMA_CONTROLLERS];
30
31 /* External page registers for each channel of the two DMA controllers */
32 static DMA_PAGE_REGISTER DmaPageRegisters[DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS];
33
34 /* PRIVATE FUNCTIONS **********************************************************/
35
36 #define READ_ADDR(CtrlIndex, ChanIndex, Data) \
37 do { \
38 (Data) = \
39 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
40 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
41 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
42 } while(0)
43
44 #define READ_CNT(CtrlIndex, ChanIndex, Data) \
45 do { \
46 (Data) = \
47 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrElemCnt + \
48 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
49 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
50 } while(0)
51
DmaReadPort(USHORT Port)52 static BYTE WINAPI DmaReadPort(USHORT Port)
53 {
54 BYTE ReadValue = 0xFF;
55
56 DPRINT1("DmaReadPort(Port = 0x%04X)\n", Port);
57
58 switch (Port)
59 {
60 /* Current Address Registers */
61 {
62 case 0x00:
63 READ_ADDR(0, 0, ReadValue);
64 return ReadValue;
65 case 0x02:
66 READ_ADDR(0, 1, ReadValue);
67 return ReadValue;
68 case 0x04:
69 READ_ADDR(0, 2, ReadValue);
70 return ReadValue;
71 case 0x06:
72 READ_ADDR(0, 3, ReadValue);
73 return ReadValue;
74 case 0xC0:
75 READ_ADDR(1, 0, ReadValue);
76 return ReadValue;
77 case 0xC4:
78 READ_ADDR(1, 1, ReadValue);
79 return ReadValue;
80 case 0xC8:
81 READ_ADDR(1, 2, ReadValue);
82 return ReadValue;
83 case 0xCC:
84 READ_ADDR(1, 3, ReadValue);
85 return ReadValue;
86 }
87
88 /* Current Count Registers */
89 {
90 case 0x01:
91 READ_CNT(0, 0, ReadValue);
92 return ReadValue;
93 case 0x03:
94 READ_CNT(0, 1, ReadValue);
95 return ReadValue;
96 case 0x05:
97 READ_CNT(0, 2, ReadValue);
98 return ReadValue;
99 case 0x07:
100 READ_CNT(0, 3, ReadValue);
101 return ReadValue;
102 case 0xC2:
103 READ_CNT(1, 0, ReadValue);
104 return ReadValue;
105 case 0xC6:
106 READ_CNT(1, 1, ReadValue);
107 return ReadValue;
108 case 0xCA:
109 READ_CNT(1, 2, ReadValue);
110 return ReadValue;
111 case 0xCE:
112 READ_CNT(1, 3, ReadValue);
113 return ReadValue;
114 }
115
116 /* Status Registers */
117 {
118 case 0x08:
119 return DmaControllers[0].Status;
120 case 0xD0:
121 return DmaControllers[1].Status;
122 }
123
124 /* DMA Intermediate (Temporary) Registers */
125 {
126 case 0x0D:
127 return DmaControllers[0].TempReg;
128 case 0xDA:
129 return DmaControllers[1].TempReg;
130 }
131
132 /* Multi-Channel Mask Registers */
133 {
134 case 0x0F:
135 return DmaControllers[0].Mask;
136 case 0xDE:
137 return DmaControllers[1].Mask;
138 }
139 }
140
141 return 0x00;
142 }
143
144 #define WRITE_ADDR(CtrlIndex, ChanIndex, Data) \
145 do { \
146 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseAddress + \
147 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
148 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
149 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
150 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
151 } while(0)
152
153 #define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
154 do { \
155 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseElemCnt + \
156 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
157 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrElemCnt + \
158 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
159 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
160 } while(0)
161
DmaWritePort(USHORT Port,BYTE Data)162 static VOID WINAPI DmaWritePort(USHORT Port, BYTE Data)
163 {
164 DPRINT1("DmaWritePort(Port = 0x%04X, Data = 0x%02X)\n", Port, Data);
165
166 switch (Port)
167 {
168 /* Start Address Registers */
169 {
170 case 0x00:
171 WRITE_ADDR(0, 0, Data);
172 break;
173 case 0x02:
174 WRITE_ADDR(0, 1, Data);
175 break;
176 case 0x04:
177 WRITE_ADDR(0, 2, Data);
178 break;
179 case 0x06:
180 WRITE_ADDR(0, 3, Data);
181 break;
182 case 0xC0:
183 WRITE_ADDR(1, 0, Data);
184 break;
185 case 0xC4:
186 WRITE_ADDR(1, 1, Data);
187 break;
188 case 0xC8:
189 WRITE_ADDR(1, 2, Data);
190 break;
191 case 0xCC:
192 WRITE_ADDR(1, 3, Data);
193 break;
194 }
195
196 /* Base Count Registers */
197 {
198 case 0x01:
199 WRITE_CNT(0, 0, Data);
200 break;
201 case 0x03:
202 WRITE_CNT(0, 1, Data);
203 break;
204 case 0x05:
205 WRITE_CNT(0, 2, Data);
206 break;
207 case 0x07:
208 WRITE_CNT(0, 3, Data);
209 break;
210 case 0xC2:
211 WRITE_CNT(1, 0, Data);
212 break;
213 case 0xC6:
214 WRITE_CNT(1, 1, Data);
215 break;
216 case 0xCA:
217 WRITE_CNT(1, 2, Data);
218 break;
219 case 0xCE:
220 WRITE_CNT(1, 3, Data);
221 break;
222 }
223
224 /* Command Registers */
225 {
226 case 0x08:
227 DmaControllers[0].Command = Data;
228 break;
229 case 0xD0:
230 DmaControllers[1].Command = Data;
231 break;
232 }
233
234 /* Mode Registers */
235 {
236 case 0x0B:
237 DmaControllers[0].DmaChannel[Data & 0x03].Mode = (Data & ~0x03);
238 break;
239 case 0xD6:
240 DmaControllers[1].DmaChannel[Data & 0x03].Mode = (Data & ~0x03);
241 break;
242 }
243
244 /* Request Registers */
245 {
246 case 0x09:
247 DmaControllers[0].Request = Data;
248 break;
249 case 0xD2:
250 DmaControllers[1].Request = Data;
251 break;
252 }
253
254 /* Single Channel Mask Registers */
255 {
256 case 0x0A:
257 if (Data & 0x04)
258 DmaControllers[0].Mask |= (1 << (Data & 0x03));
259 else
260 DmaControllers[0].Mask &= ~(1 << (Data & 0x03));
261 break;
262 case 0xD4:
263 if (Data & 0x04)
264 DmaControllers[1].Mask |= (1 << (Data & 0x03));
265 else
266 DmaControllers[1].Mask &= ~(1 << (Data & 0x03));
267 break;
268 }
269
270 /* Multi-Channel Mask Registers */
271 {
272 case 0x0F:
273 DmaControllers[0].Mask = (Data & 0x0F);
274 break;
275 case 0xDE:
276 DmaControllers[1].Mask = (Data & 0x0F);
277 break;
278 }
279
280 /* Flip-Flop Reset */
281 {
282 case 0x0C:
283 DmaControllers[0].FlipFlop = 0;
284 break;
285 case 0xD8:
286 DmaControllers[1].FlipFlop = 0;
287 break;
288 }
289
290 /* DMA Master Reset Registers */
291 {
292 case 0x0D:
293 DmaControllers[0].Command = 0x00;
294 DmaControllers[0].Status = 0x00;
295 DmaControllers[0].Request = 0x00;
296 DmaControllers[0].TempReg = 0x00;
297 DmaControllers[0].FlipFlop = 0;
298 DmaControllers[0].Mask = 0x0F;
299 break;
300 case 0xDA:
301 DmaControllers[1].Command = 0x00;
302 DmaControllers[1].Status = 0x00;
303 DmaControllers[1].Request = 0x00;
304 DmaControllers[1].TempReg = 0x00;
305 DmaControllers[1].FlipFlop = 0;
306 DmaControllers[1].Mask = 0x0F;
307 break;
308 }
309
310 /* Mask Reset Registers */
311 {
312 case 0x0E:
313 DmaControllers[0].Mask = 0x00;
314 break;
315 case 0xDC:
316 DmaControllers[1].Mask = 0x00;
317 break;
318 }
319 }
320 }
321
322 /* Page Address Registers */
323
DmaPageReadPort(USHORT Port)324 static BYTE WINAPI DmaPageReadPort(USHORT Port)
325 {
326 DPRINT1("DmaPageReadPort(Port = 0x%04X)\n", Port);
327
328 switch (Port)
329 {
330 case 0x87:
331 return DmaPageRegisters[0].Page;
332 case 0x83:
333 return DmaPageRegisters[1].Page;
334 case 0x81:
335 return DmaPageRegisters[2].Page;
336 case 0x82:
337 return DmaPageRegisters[3].Page;
338 case 0x8F:
339 return DmaPageRegisters[4].Page;
340 case 0x8B:
341 return DmaPageRegisters[5].Page;
342 case 0x89:
343 return DmaPageRegisters[6].Page;
344 case 0x8A:
345 return DmaPageRegisters[7].Page;
346 }
347
348 return 0x00;
349 }
350
DmaPageWritePort(USHORT Port,BYTE Data)351 static VOID WINAPI DmaPageWritePort(USHORT Port, BYTE Data)
352 {
353 DPRINT1("DmaPageWritePort(Port = 0x%04X, Data = 0x%02X)\n", Port, Data);
354
355 switch (Port)
356 {
357 case 0x87:
358 DmaPageRegisters[0].Page = Data;
359 break;
360 case 0x83:
361 DmaPageRegisters[1].Page = Data;
362 break;
363 case 0x81:
364 DmaPageRegisters[2].Page = Data;
365 break;
366 case 0x82:
367 DmaPageRegisters[3].Page = Data;
368 break;
369 case 0x8F:
370 DmaPageRegisters[4].Page = Data;
371 break;
372 case 0x8B:
373 DmaPageRegisters[5].Page = Data;
374 break;
375 case 0x89:
376 DmaPageRegisters[6].Page = Data;
377 break;
378 case 0x8A:
379 DmaPageRegisters[7].Page = Data;
380 break;
381 }
382 }
383
384 /* PUBLIC FUNCTIONS ***********************************************************/
385
DmaRequest(IN WORD iChannel,IN OUT PVOID Buffer,IN DWORD length)386 DWORD DmaRequest(IN WORD iChannel,
387 IN OUT PVOID Buffer,
388 IN DWORD length)
389 {
390 /*
391 * NOTE: This function is adapted from Wine's krnl386.exe,
392 * DMA emulation by Christian Costa.
393 */
394 PDMA_CONTROLLER pDcp;
395 WORD Channel;
396
397 DWORD i, Size, ret = 0;
398 BYTE RegMode, OpMode, Increment, Autoinit, TrMode;
399 PBYTE dmabuf = Buffer;
400
401 ULONG CurrAddress;
402
403 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
404 {
405 SetLastError(ERROR_INVALID_ADDRESS);
406 return 0;
407 }
408
409 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
410 Channel = iChannel % DMA_CONTROLLER_CHANNELS; // == (iChannel & 0x03)
411
412 RegMode = pDcp->DmaChannel[Channel].Mode;
413
414 DPRINT1("DMA_Command = %x length=%d\n", RegMode, length);
415
416 /* Exit if the controller is disabled or the channel is masked */
417 if ((pDcp->Command & 0x04) || (pDcp->Mask & (1 << Channel)))
418 return 0;
419
420 OpMode = (RegMode & 0xC0) >> 6;
421 Increment = !(RegMode & 0x20);
422 Autoinit = RegMode & 0x10;
423 TrMode = (RegMode & 0x0C) >> 2;
424
425 /* Process operating mode */
426 switch (OpMode)
427 {
428 case 0:
429 /* Request mode */
430 DPRINT1("Request Mode - Not Implemented\n");
431 return 0;
432 case 1:
433 /* Single Mode */
434 break;
435 case 2:
436 /* Request mode */
437 DPRINT1("Block Mode - Not Implemented\n");
438 return 0;
439 case 3:
440 /* Cascade Mode */
441 DPRINT1("Cascade Mode should not be used by regular apps\n");
442 return 0;
443 }
444
445 /* Perform one the 4 transfer modes */
446 if (TrMode == 4)
447 {
448 /* Illegal */
449 DPRINT1("DMA Transfer Type Illegal\n");
450 return 0;
451 }
452
453 /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
454 Size = (iChannel < 4) ? sizeof(BYTE) : sizeof(WORD);
455
456 // FIXME: Handle wrapping?
457 /* Get the number of elements to transfer */
458 ret = min(pDcp->DmaChannel[Channel].CurrElemCnt, length / Size);
459 length = ret * Size;
460
461 /* 16-bit mode addressing, see: http://wiki.osdev.org/ISA_DMA#16_bit_issues */
462 CurrAddress = (iChannel < 4) ? (DmaPageRegisters[iChannel].Page << 16) | ((pDcp->DmaChannel[Channel].CurrAddress << 0) & 0xFFFF)
463 : (DmaPageRegisters[iChannel].Page << 16) | ((pDcp->DmaChannel[Channel].CurrAddress << 1) & 0xFFFF);
464
465 switch (TrMode)
466 {
467 /* Verification (no real transfer) */
468 case 0:
469 {
470 DPRINT1("Verification DMA operation\n");
471 break;
472 }
473
474 /* Write */
475 case 1:
476 {
477 DPRINT1("Perform Write transfer of %d elements (%d bytes) at 0x%x %s with count %x\n",
478 ret, length, CurrAddress, Increment ? "up" : "down", pDcp->DmaChannel[Channel].CurrElemCnt);
479
480 if (Increment)
481 {
482 EmulatorWriteMemory(&EmulatorContext, CurrAddress, dmabuf, length);
483 }
484 else
485 {
486 for (i = 0; i < length; i++)
487 {
488 EmulatorWriteMemory(&EmulatorContext, CurrAddress - i, dmabuf + i, sizeof(BYTE));
489 }
490 }
491
492 break;
493 }
494
495 /* Read */
496 case 2:
497 {
498 DPRINT1("Perform Read transfer of %d elements (%d bytes) at 0x%x %s with count %x\n",
499 ret, length, CurrAddress, Increment ? "up" : "down", pDcp->DmaChannel[Channel].CurrElemCnt);
500
501 if (Increment)
502 {
503 EmulatorReadMemory(&EmulatorContext, CurrAddress, dmabuf, length);
504 }
505 else
506 {
507 for (i = 0; i < length; i++)
508 {
509 EmulatorReadMemory(&EmulatorContext, CurrAddress - i, dmabuf + i, sizeof(BYTE));
510 }
511 }
512
513 break;
514 }
515 }
516
517 /* Update DMA registers */
518 pDcp->DmaChannel[Channel].CurrElemCnt -= ret;
519 if (Increment)
520 pDcp->DmaChannel[Channel].CurrAddress += ret;
521 else
522 pDcp->DmaChannel[Channel].CurrAddress -= ret;
523
524 /* Check for end of transfer */
525 if (pDcp->DmaChannel[Channel].CurrElemCnt == 0)
526 {
527 DPRINT1("DMA buffer empty\n");
528
529 /* Update status register of the DMA chip corresponding to the channel */
530 pDcp->Status |= 1 << Channel; /* Mark transfer as finished */
531 pDcp->Status &= ~(1 << (Channel + 4)); /* Reset soft request if any */
532
533 if (Autoinit)
534 {
535 /* Reload Current* registers to their initial values */
536 pDcp->DmaChannel[Channel].CurrAddress = pDcp->DmaChannel[Channel].BaseAddress;
537 pDcp->DmaChannel[Channel].CurrElemCnt = pDcp->DmaChannel[Channel].BaseElemCnt;
538 }
539 else
540 {
541 /* Set the mask bit for the channel */
542 pDcp->Mask |= (1 << Channel);
543 }
544 }
545
546 return length;
547 }
548
DmaInitialize(VOID)549 VOID DmaInitialize(VOID)
550 {
551 /* Register the I/O Ports */
552
553 /* Channels 0(Reserved)..3 */
554 RegisterIoPort(0x00, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 0 (Reserved) */
555 RegisterIoPort(0x01, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 0 (Reserved) */
556 RegisterIoPort(0x02, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 1 */
557 RegisterIoPort(0x03, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 1 */
558 RegisterIoPort(0x04, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 2 */
559 RegisterIoPort(0x05, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 2 */
560 RegisterIoPort(0x06, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 3 */
561 RegisterIoPort(0x07, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 3 */
562
563 RegisterIoPort(0x08, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
564 RegisterIoPort(0x09, NULL, DmaWritePort); /* Request Register */
565 RegisterIoPort(0x0A, NULL, DmaWritePort); /* Single Channel Mask Register */
566 RegisterIoPort(0x0B, NULL, DmaWritePort); /* Mode Register */
567 RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
568 RegisterIoPort(0x0D, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
569 RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
570 RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register */
571
572
573 /* Channels 4(Reserved)..7 */
574 RegisterIoPort(0xC0, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 4 (Reserved) */
575 RegisterIoPort(0xC2, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 4 (Reserved) */
576 RegisterIoPort(0xC4, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 5 */
577 RegisterIoPort(0xC6, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 5 */
578 RegisterIoPort(0xC8, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 6 */
579 RegisterIoPort(0xCA, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 6 */
580 RegisterIoPort(0xCC, DmaReadPort, DmaWritePort); /* Current(R) / Start(W) Address Register 7 */
581 RegisterIoPort(0xCE, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 7 */
582
583 RegisterIoPort(0xD0, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
584 RegisterIoPort(0xD2, NULL, DmaWritePort); /* Request Register */
585 RegisterIoPort(0xD4, NULL, DmaWritePort); /* Single Channel Mask Register */
586 RegisterIoPort(0xD6, NULL, DmaWritePort); /* Mode Register */
587 RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
588 RegisterIoPort(0xDA, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
589 RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
590 RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register */
591
592
593 /* Channels Page Address Registers */
594 RegisterIoPort(0x87, DmaPageReadPort, DmaPageWritePort); /* Channel 0 (Reserved) */
595 RegisterIoPort(0x83, DmaPageReadPort, DmaPageWritePort); /* Channel 1 */
596 RegisterIoPort(0x81, DmaPageReadPort, DmaPageWritePort); /* Channel 2 */
597 RegisterIoPort(0x82, DmaPageReadPort, DmaPageWritePort); /* Channel 3 */
598 RegisterIoPort(0x8F, DmaPageReadPort, DmaPageWritePort); /* Channel 4 (Reserved) */
599 RegisterIoPort(0x8B, DmaPageReadPort, DmaPageWritePort); /* Channel 5 */
600 RegisterIoPort(0x89, DmaPageReadPort, DmaPageWritePort); /* Channel 6 */
601 RegisterIoPort(0x8A, DmaPageReadPort, DmaPageWritePort); /* Channel 7 */
602 }
603
604
605
606 DWORD
607 WINAPI
VDDRequestDMA(IN HANDLE hVdd,IN WORD iChannel,IN OUT PVOID Buffer,IN DWORD length)608 VDDRequestDMA(IN HANDLE hVdd,
609 IN WORD iChannel,
610 IN OUT PVOID Buffer,
611 IN DWORD length)
612 {
613 UNREFERENCED_PARAMETER(hVdd);
614
615 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
616 {
617 SetLastError(ERROR_INVALID_ADDRESS);
618 return FALSE;
619 }
620
621 /*
622 * We assume success first. If something fails,
623 * DmaRequest sets an adequate last error.
624 */
625 SetLastError(ERROR_SUCCESS);
626
627 return DmaRequest(iChannel, Buffer, length);
628 }
629
630 BOOL
631 WINAPI
VDDQueryDMA(IN HANDLE hVdd,IN WORD iChannel,IN PVDD_DMA_INFO pDmaInfo)632 VDDQueryDMA(IN HANDLE hVdd,
633 IN WORD iChannel,
634 IN PVDD_DMA_INFO pDmaInfo)
635 {
636 PDMA_CONTROLLER pDcp;
637 WORD Channel;
638
639 UNREFERENCED_PARAMETER(hVdd);
640
641 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
642 {
643 SetLastError(ERROR_INVALID_ADDRESS);
644 return FALSE;
645 }
646
647 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
648 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
649
650 pDmaInfo->addr = pDcp->DmaChannel[Channel].CurrAddress;
651 pDmaInfo->count = pDcp->DmaChannel[Channel].CurrElemCnt;
652
653 pDmaInfo->page = DmaPageRegisters[iChannel].Page;
654 pDmaInfo->status = pDcp->Status;
655 pDmaInfo->mode = pDcp->DmaChannel[Channel].Mode;
656 pDmaInfo->mask = pDcp->Mask;
657
658 return TRUE;
659 }
660
661 BOOL
662 WINAPI
VDDSetDMA(IN HANDLE hVdd,IN WORD iChannel,IN WORD fDMA,IN PVDD_DMA_INFO pDmaInfo)663 VDDSetDMA(IN HANDLE hVdd,
664 IN WORD iChannel,
665 IN WORD fDMA,
666 IN PVDD_DMA_INFO pDmaInfo)
667 {
668 PDMA_CONTROLLER pDcp;
669 WORD Channel;
670
671 UNREFERENCED_PARAMETER(hVdd);
672
673 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
674 {
675 SetLastError(ERROR_INVALID_ADDRESS);
676 return FALSE;
677 }
678
679 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
680 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
681
682 if (fDMA & VDD_DMA_ADDR)
683 pDcp->DmaChannel[Channel].CurrAddress = pDmaInfo->addr;
684
685 if (fDMA & VDD_DMA_COUNT)
686 pDcp->DmaChannel[Channel].CurrElemCnt = pDmaInfo->count;
687
688 if (fDMA & VDD_DMA_PAGE)
689 DmaPageRegisters[iChannel].Page = pDmaInfo->page;
690
691 if (fDMA & VDD_DMA_STATUS)
692 pDcp->Status = pDmaInfo->status;
693
694 return TRUE;
695 }
696
697 /* EOF */
698