xref: /reactos/subsystems/mvdm/ntvdm/hardware/dma.c (revision c2c66aff)
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