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 *******************************************************************/
20 /* PRIVATE VARIABLES **********************************************************/
23 * DMA Controller 0 (Channels 0..3): Slave controller
24 * DMA Controller 1 (Channels 4..7): Master controller
26 static DMA_CONTROLLER DmaControllers
[DMA_CONTROLLERS
];
28 /* External page registers for each channel of the two DMA controllers */
29 static DMA_PAGE_REGISTER DmaPageRegisters
[DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
];
31 /* PRIVATE FUNCTIONS **********************************************************/
33 #define READ_ADDR(CtrlIndex, ChanIndex, Data) \
36 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
37 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
38 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
41 #define READ_CNT(CtrlIndex, ChanIndex, Data) \
44 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
45 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
46 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
49 static BYTE WINAPI
DmaReadPort(USHORT Port
)
51 BYTE ReadValue
= 0xFF;
55 /* Start Address Registers */
58 READ_ADDR(0, 0, ReadValue
);
61 READ_ADDR(0, 1, ReadValue
);
64 READ_ADDR(0, 2, ReadValue
);
67 READ_ADDR(0, 3, ReadValue
);
70 READ_ADDR(1, 0, ReadValue
);
73 READ_ADDR(1, 1, ReadValue
);
76 READ_ADDR(1, 2, ReadValue
);
79 READ_ADDR(1, 3, ReadValue
);
83 /* Count Address Registers */
86 READ_CNT(0, 0, ReadValue
);
89 READ_CNT(0, 1, ReadValue
);
92 READ_CNT(0, 2, ReadValue
);
95 READ_CNT(0, 3, ReadValue
);
98 READ_CNT(1, 0, ReadValue
);
101 READ_CNT(1, 1, ReadValue
);
104 READ_CNT(1, 2, ReadValue
);
107 READ_CNT(1, 3, ReadValue
);
111 /* Status Registers */
114 return DmaControllers
[0].Status
;
116 return DmaControllers
[1].Status
;
119 /* DMA Intermediate (Temporary) Registers */
122 return DmaControllers
[0].TempReg
;
124 return DmaControllers
[1].TempReg
;
131 #define WRITE_ADDR(CtrlIndex, ChanIndex, Data) \
133 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseAddress + \
134 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
135 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
136 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
137 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
140 #define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
142 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseWordCnt + \
143 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
144 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
145 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
146 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
149 static VOID WINAPI
DmaWritePort(USHORT Port
, BYTE Data
)
153 /* Start Address Registers */
156 WRITE_ADDR(0, 0, Data
);
159 WRITE_ADDR(0, 1, Data
);
162 WRITE_ADDR(0, 2, Data
);
165 WRITE_ADDR(0, 3, Data
);
168 WRITE_ADDR(1, 0, Data
);
171 WRITE_ADDR(1, 1, Data
);
174 WRITE_ADDR(1, 2, Data
);
177 WRITE_ADDR(1, 3, Data
);
181 /* Count Address Registers */
184 WRITE_CNT(0, 0, Data
);
187 WRITE_CNT(0, 1, Data
);
190 WRITE_CNT(0, 2, Data
);
193 WRITE_CNT(0, 3, Data
);
196 WRITE_CNT(1, 0, Data
);
199 WRITE_CNT(1, 1, Data
);
202 WRITE_CNT(1, 2, Data
);
205 WRITE_CNT(1, 3, Data
);
209 /* Command Registers */
212 DmaControllers
[0].Command
= Data
;
215 DmaControllers
[1].Command
= Data
;
219 /* Request Registers */
222 DmaControllers
[0].Request
= Data
;
225 DmaControllers
[1].Request
= Data
;
229 /* Flip-Flop Reset */
232 DmaControllers
[0].FlipFlop
= 0;
235 DmaControllers
[1].FlipFlop
= 0;
239 /* DMA Master Reset */
242 DmaControllers
[0].Command
= 0x00;
243 DmaControllers
[0].Status
= 0x00;
244 DmaControllers
[0].Request
= 0x00;
245 DmaControllers
[0].TempReg
= 0x00;
246 DmaControllers
[0].FlipFlop
= 0;
247 DmaControllers
[0].Mask
= 0x0F;
250 DmaControllers
[1].Command
= 0x00;
251 DmaControllers
[1].Status
= 0x00;
252 DmaControllers
[1].Request
= 0x00;
253 DmaControllers
[1].TempReg
= 0x00;
254 DmaControllers
[1].FlipFlop
= 0;
255 DmaControllers
[1].Mask
= 0x0F;
261 /* Page Address Registers */
263 static BYTE WINAPI
DmaPageReadPort(USHORT Port
)
268 return DmaPageRegisters
[0].Page
;
270 return DmaPageRegisters
[1].Page
;
272 return DmaPageRegisters
[2].Page
;
274 return DmaPageRegisters
[3].Page
;
276 return DmaPageRegisters
[4].Page
;
278 return DmaPageRegisters
[5].Page
;
280 return DmaPageRegisters
[6].Page
;
282 return DmaPageRegisters
[7].Page
;
288 static VOID WINAPI
DmaPageWritePort(USHORT Port
, BYTE Data
)
293 DmaPageRegisters
[0].Page
= Data
;
296 DmaPageRegisters
[1].Page
= Data
;
299 DmaPageRegisters
[2].Page
= Data
;
302 DmaPageRegisters
[3].Page
= Data
;
305 DmaPageRegisters
[4].Page
= Data
;
308 DmaPageRegisters
[5].Page
= Data
;
311 DmaPageRegisters
[6].Page
= Data
;
314 DmaPageRegisters
[7].Page
= Data
;
319 /* PUBLIC FUNCTIONS ***********************************************************/
321 VOID
DmaInitialize(VOID
)
323 /* Register the I/O Ports */
325 /* Channels 0(Reserved)..3 */
326 RegisterIoPort(0x00, NULL
, DmaWritePort
); /* Start Address Register 0 (Reserved) */
327 RegisterIoPort(0x01, NULL
, DmaWritePort
); /* Count Address Register 0 (Reserved) */
328 RegisterIoPort(0x02, NULL
, DmaWritePort
); /* Start Address Register 1 */
329 RegisterIoPort(0x03, NULL
, DmaWritePort
); /* Count Address Register 1 */
330 RegisterIoPort(0x04, NULL
, DmaWritePort
); /* Start Address Register 2 */
331 RegisterIoPort(0x05, NULL
, DmaWritePort
); /* Count Address Register 2 */
332 RegisterIoPort(0x06, NULL
, DmaWritePort
); /* Start Address Register 3 */
333 RegisterIoPort(0x07, NULL
, DmaWritePort
); /* Count Address Register 3 */
335 RegisterIoPort(0x08, DmaReadPort
, DmaWritePort
); /* Status (Read) / Command (Write) Registers */
336 RegisterIoPort(0x09, NULL
, DmaWritePort
); /* Request Register */
337 RegisterIoPort(0x0A, NULL
, DmaWritePort
); /* Single Channel Mask Register */
338 RegisterIoPort(0x0B, NULL
, DmaWritePort
); /* Mode Register */
339 RegisterIoPort(0x0C, NULL
, DmaWritePort
); /* Flip-Flop Reset Register */
340 RegisterIoPort(0x0D, DmaReadPort
, DmaWritePort
); /* Intermediate (Read) / Master Reset (Write) Registers */
341 RegisterIoPort(0x0E, NULL
, DmaWritePort
); /* Mask Reset Register */
342 RegisterIoPort(0x0F, DmaReadPort
, DmaWritePort
); /* Multi-Channel Mask Reset Register */
345 /* Channels 4(Reserved)..7 */
346 RegisterIoPort(0xC0, NULL
, DmaWritePort
); /* Start Address Register 4 (Reserved) */
347 RegisterIoPort(0xC2, NULL
, DmaWritePort
); /* Count Address Register 4 (Reserved) */
348 RegisterIoPort(0xC4, NULL
, DmaWritePort
); /* Start Address Register 5 */
349 RegisterIoPort(0xC6, NULL
, DmaWritePort
); /* Count Address Register 5 */
350 RegisterIoPort(0xC8, NULL
, DmaWritePort
); /* Start Address Register 6 */
351 RegisterIoPort(0xCA, NULL
, DmaWritePort
); /* Count Address Register 6 */
352 RegisterIoPort(0xCC, NULL
, DmaWritePort
); /* Start Address Register 7 */
353 RegisterIoPort(0xCE, NULL
, DmaWritePort
); /* Count Address Register 7 */
355 RegisterIoPort(0xD0, DmaReadPort
, DmaWritePort
); /* Status (Read) / Command (Write) Registers */
356 RegisterIoPort(0xD2, NULL
, DmaWritePort
); /* Request Register */
357 RegisterIoPort(0xD4, NULL
, DmaWritePort
); /* Single Channel Mask Register */
358 RegisterIoPort(0xD6, NULL
, DmaWritePort
); /* Mode Register */
359 RegisterIoPort(0xD8, NULL
, DmaWritePort
); /* Flip-Flop Reset Register */
360 RegisterIoPort(0xDA, DmaReadPort
, DmaWritePort
); /* Intermediate (Read) / Master Reset (Write) Registers */
361 RegisterIoPort(0xDC, NULL
, DmaWritePort
); /* Mask Reset Register */
362 RegisterIoPort(0xDE, DmaReadPort
, DmaWritePort
); /* Multi-Channel Mask Reset Register */
365 /* Channels Page Address Registers */
366 RegisterIoPort(0x87, DmaPageReadPort
, DmaPageWritePort
); /* Channel 0 (Reserved) */
367 RegisterIoPort(0x83, DmaPageReadPort
, DmaPageWritePort
); /* Channel 1 */
368 RegisterIoPort(0x81, DmaPageReadPort
, DmaPageWritePort
); /* Channel 2 */
369 RegisterIoPort(0x82, DmaPageReadPort
, DmaPageWritePort
); /* Channel 3 */
370 RegisterIoPort(0x8F, DmaPageReadPort
, DmaPageWritePort
); /* Channel 4 (Reserved) */
371 RegisterIoPort(0x8B, DmaPageReadPort
, DmaPageWritePort
); /* Channel 5 */
372 RegisterIoPort(0x89, DmaPageReadPort
, DmaPageWritePort
); /* Channel 6 */
373 RegisterIoPort(0x8A, DmaPageReadPort
, DmaPageWritePort
); /* Channel 7 */
380 VDDRequestDMA(IN HANDLE hVdd
,
385 UNREFERENCED_PARAMETER(hVdd
);
387 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
389 SetLastError(ERROR_INVALID_ADDRESS
);
399 VDDQueryDMA(IN HANDLE hVdd
,
401 IN PVDD_DMA_INFO pDmaInfo
)
403 PDMA_CONTROLLER pDcp
;
406 UNREFERENCED_PARAMETER(hVdd
);
408 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
410 SetLastError(ERROR_INVALID_ADDRESS
);
414 pDcp
= &DmaControllers
[iChannel
/ DMA_CONTROLLER_CHANNELS
];
415 Channel
= iChannel
% DMA_CONTROLLER_CHANNELS
;
417 pDmaInfo
->addr
= pDcp
->DmaChannel
[Channel
].CurrAddress
;
418 pDmaInfo
->count
= pDcp
->DmaChannel
[Channel
].CurrWordCnt
;
420 // pDmaInfo->page = DmaPageRegisters[iChannel].Page;
421 pDmaInfo
->status
= pDcp
->Status
;
422 pDmaInfo
->mode
= pDcp
->DmaChannel
[Channel
].Mode
;
423 pDmaInfo
->mask
= pDcp
->Mask
;
430 VDDSetDMA(IN HANDLE hVdd
,
433 IN PVDD_DMA_INFO pDmaInfo
)
435 PDMA_CONTROLLER pDcp
;
438 UNREFERENCED_PARAMETER(hVdd
);
440 if (iChannel
>= DMA_CONTROLLERS
* DMA_CONTROLLER_CHANNELS
)
442 SetLastError(ERROR_INVALID_ADDRESS
);
446 pDcp
= &DmaControllers
[iChannel
/ DMA_CONTROLLER_CHANNELS
];
447 Channel
= iChannel
% DMA_CONTROLLER_CHANNELS
;
449 if (fDMA
& VDD_DMA_ADDR
)
450 pDcp
->DmaChannel
[Channel
].CurrAddress
= pDmaInfo
->addr
;
452 if (fDMA
& VDD_DMA_COUNT
)
453 pDcp
->DmaChannel
[Channel
].CurrWordCnt
= pDmaInfo
->count
;
455 // if (fDMA & VDD_DMA_PAGE)
456 // DmaPageRegisters[iChannel].Page = pDmaInfo->page;
458 if (fDMA
& VDD_DMA_STATUS
)
459 pDcp
->Status
= pDmaInfo
->status
;