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