[TRANSLATION] Polish translation update (#781)
[reactos.git] / 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: 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
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
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
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
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
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
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
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
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
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 */