2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Direct Memory Access Controller emulation -
6 * i8237A compatible with 74LS612 Memory Mapper extension
7 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
18 /* PRIVATE VARIABLES **********************************************************/
21 * DMA Controller 0 (Channels 0..3): Slave controller
22 * DMA Controller 1 (Channels 4..7): Master controller
24 static DMA_CONTROLLER DmaControllers
[DMA_CONTROLLERS
];
26 /* External page registers for each channel of the two DMA controllers */
27 static DMA_PAGE_REGISTER DmaPageRegisters
[DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
];
29 /* PRIVATE FUNCTIONS **********************************************************/
31 #define READ_ADDR(CtrlIndex, ChanIndex, Data) \
34 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
35 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
36 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
39 #define READ_CNT(CtrlIndex, ChanIndex, Data) \
42 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
43 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
44 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
47 static BYTE WINAPI
DmaReadPort(USHORT Port
)
49 BYTE ReadValue
= 0xFF;
53 /* Start Address Registers */
56 READ_ADDR(0, 0, ReadValue
);
59 READ_ADDR(0, 1, ReadValue
);
62 READ_ADDR(0, 2, ReadValue
);
65 READ_ADDR(0, 3, ReadValue
);
68 READ_ADDR(1, 0, ReadValue
);
71 READ_ADDR(1, 1, ReadValue
);
74 READ_ADDR(1, 2, ReadValue
);
77 READ_ADDR(1, 3, ReadValue
);
81 /* Count Address Registers */
84 READ_CNT(0, 0, ReadValue
);
87 READ_CNT(0, 1, ReadValue
);
90 READ_CNT(0, 2, ReadValue
);
93 READ_CNT(0, 3, ReadValue
);
96 READ_CNT(1, 0, ReadValue
);
99 READ_CNT(1, 1, ReadValue
);
102 READ_CNT(1, 2, ReadValue
);
105 READ_CNT(1, 3, ReadValue
);
109 /* Status Registers */
112 return DmaControllers
[0].Status
;
114 return DmaControllers
[1].Status
;
117 /* DMA Intermediate (Temporary) Registers */
120 return DmaControllers
[0].TempReg
;
122 return DmaControllers
[1].TempReg
;
129 #define WRITE_ADDR(CtrlIndex, ChanIndex, Data) \
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; \
138 #define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
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; \
147 static VOID WINAPI
DmaWritePort(USHORT Port
, BYTE Data
)
151 /* Start Address Registers */
154 WRITE_ADDR(0, 0, Data
);
157 WRITE_ADDR(0, 1, Data
);
160 WRITE_ADDR(0, 2, Data
);
163 WRITE_ADDR(0, 3, Data
);
166 WRITE_ADDR(1, 0, Data
);
169 WRITE_ADDR(1, 1, Data
);
172 WRITE_ADDR(1, 2, Data
);
175 WRITE_ADDR(1, 3, Data
);
179 /* Count Address Registers */
182 WRITE_CNT(0, 0, Data
);
185 WRITE_CNT(0, 1, Data
);
188 WRITE_CNT(0, 2, Data
);
191 WRITE_CNT(0, 3, Data
);
194 WRITE_CNT(1, 0, Data
);
197 WRITE_CNT(1, 1, Data
);
200 WRITE_CNT(1, 2, Data
);
203 WRITE_CNT(1, 3, Data
);
207 /* Command Registers */
210 DmaControllers
[0].Command
= Data
;
213 DmaControllers
[1].Command
= Data
;
217 /* Request Registers */
220 DmaControllers
[0].Request
= Data
;
223 DmaControllers
[1].Request
= Data
;
227 /* Flip-Flop Reset */
230 DmaControllers
[0].FlipFlop
= 0;
233 DmaControllers
[1].FlipFlop
= 0;
237 /* DMA Master Reset */
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;
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;
259 /* Page Address Registers */
261 static BYTE WINAPI
DmaPageReadPort(USHORT Port
)
266 return DmaPageRegisters
[0].Page
;
268 return DmaPageRegisters
[1].Page
;
270 return DmaPageRegisters
[2].Page
;
272 return DmaPageRegisters
[3].Page
;
274 return DmaPageRegisters
[4].Page
;
276 return DmaPageRegisters
[5].Page
;
278 return DmaPageRegisters
[6].Page
;
280 return DmaPageRegisters
[7].Page
;
286 static VOID WINAPI
DmaPageWritePort(USHORT Port
, BYTE Data
)
291 DmaPageRegisters
[0].Page
= Data
;
294 DmaPageRegisters
[1].Page
= Data
;
297 DmaPageRegisters
[2].Page
= Data
;
300 DmaPageRegisters
[3].Page
= Data
;
303 DmaPageRegisters
[4].Page
= Data
;
306 DmaPageRegisters
[5].Page
= Data
;
309 DmaPageRegisters
[6].Page
= Data
;
312 DmaPageRegisters
[7].Page
= Data
;
317 /* PUBLIC FUNCTIONS ***********************************************************/
319 VOID
DmaInitialize(VOID
)
321 /* Register the I/O Ports */
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 */
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 */
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 */
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 */
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 */
378 VDDRequestDMA(IN HANDLE hVdd
,
383 UNREFERENCED_PARAMETER(hVdd
);
385 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
387 SetLastError(ERROR_INVALID_ADDRESS
);
397 VDDQueryDMA(IN HANDLE hVdd
,
399 IN PVDD_DMA_INFO pDmaInfo
)
401 PDMA_CONTROLLER pDcp
;
404 UNREFERENCED_PARAMETER(hVdd
);
406 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
408 SetLastError(ERROR_INVALID_ADDRESS
);
412 pDcp
= &DmaControllers
[iChannel
/ DMA_CONTROLLER_CHANNELS
];
413 Channel
= iChannel
% DMA_CONTROLLER_CHANNELS
;
415 pDmaInfo
->addr
= pDcp
->DmaChannel
[Channel
].CurrAddress
;
416 pDmaInfo
->count
= pDcp
->DmaChannel
[Channel
].CurrWordCnt
;
418 // pDmaInfo->page = DmaPageRegisters[iChannel].Page;
419 pDmaInfo
->status
= pDcp
->Status
;
420 pDmaInfo
->mode
= pDcp
->DmaChannel
[Channel
].Mode
;
421 pDmaInfo
->mask
= pDcp
->Mask
;
428 VDDSetDMA(IN HANDLE hVdd
,
431 IN PVDD_DMA_INFO pDmaInfo
)
433 PDMA_CONTROLLER pDcp
;
436 UNREFERENCED_PARAMETER(hVdd
);
438 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
440 SetLastError(ERROR_INVALID_ADDRESS
);
444 pDcp
= &DmaControllers
[iChannel
/ DMA_CONTROLLER_CHANNELS
];
445 Channel
= iChannel
% DMA_CONTROLLER_CHANNELS
;
447 if (fDMA
& VDD_DMA_ADDR
)
448 pDcp
->DmaChannel
[Channel
].CurrAddress
= pDmaInfo
->addr
;
450 if (fDMA
& VDD_DMA_COUNT
)
451 pDcp
->DmaChannel
[Channel
].CurrWordCnt
= pDmaInfo
->count
;
453 // if (fDMA & VDD_DMA_PAGE)
454 // DmaPageRegisters[iChannel].Page = pDmaInfo->page;
456 if (fDMA
& VDD_DMA_STATUS
)
457 pDcp
->Status
= pDmaInfo
->status
;