Author: hbelusca
Date: Sun May 10 18:02:45 2015
New Revision: 67629
URL:
http://svn.reactos.org/svn/reactos?rev=67629&view=rev
Log:
[NTVDM]: Implement support for DMA transfers, single-mode only for now, and fix its
support for VDDs.
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.c
trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.c [iso-8859-1] Sun May 10 18:02:45
2015
@@ -2,7 +2,7 @@
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dma.c
- * PURPOSE: Direct Memory Access Controller emulation -
+ * PURPOSE: ISA DMA - Direct Memory Access Controller emulation -
* i8237A compatible with 74LS612 Memory Mapper extension
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
*/
@@ -16,6 +16,7 @@
#include "dma.h"
#include "io.h"
+#include "memory.h"
/* PRIVATE VARIABLES **********************************************************/
@@ -41,7 +42,7 @@
#define READ_CNT(CtrlIndex, ChanIndex, Data) \
do { \
(Data) = \
- *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
+ *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrElemCnt + \
(DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
} while(0)
@@ -49,6 +50,8 @@
static BYTE WINAPI DmaReadPort(USHORT Port)
{
BYTE ReadValue = 0xFF;
+
+ DPRINT1("DmaReadPort(Port = 0x%04X)\n", Port);
switch (Port)
{
@@ -122,6 +125,14 @@
return DmaControllers[0].TempReg;
case 0xDA:
return DmaControllers[1].TempReg;
+ }
+
+ /* Multi-Channel Mask Registers */
+ {
+ case 0x0F:
+ return DmaControllers[0].Mask;
+ case 0xDE:
+ return DmaControllers[1].Mask;
}
}
@@ -139,15 +150,17 @@
#define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
do { \
- *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseWordCnt + \
+ *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseElemCnt + \
(DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
- *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
+ *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrElemCnt + \
(DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
} while(0)
static VOID WINAPI DmaWritePort(USHORT Port, BYTE Data)
{
+ DPRINT1("DmaWritePort(Port = 0x%04X, Data = 0x%02X)\n", Port, Data);
+
switch (Port)
{
/* Start Address Registers */
@@ -216,6 +229,16 @@
break;
}
+ /* Mode Registers */
+ {
+ case 0x0B:
+ DmaControllers[0].DmaChannel[Data & 0x03].Mode = (Data & ~0x03);
+ break;
+ case 0xD6:
+ DmaControllers[1].DmaChannel[Data & 0x03].Mode = (Data & ~0x03);
+ break;
+ }
+
/* Request Registers */
{
case 0x09:
@@ -226,6 +249,32 @@
break;
}
+ /* Single Channel Mask Registers */
+ {
+ case 0x0A:
+ if (Data & 0x04)
+ DmaControllers[0].Mask |= (1 << (Data & 0x03));
+ else
+ DmaControllers[0].Mask &= ~(1 << (Data & 0x03));
+ break;
+ case 0xD4:
+ if (Data & 0x04)
+ DmaControllers[1].Mask |= (1 << (Data & 0x03));
+ else
+ DmaControllers[1].Mask &= ~(1 << (Data & 0x03));
+ break;
+ }
+
+ /* Multi-Channel Mask Registers */
+ {
+ case 0x0F:
+ DmaControllers[0].Mask = (Data & 0x0F);
+ break;
+ case 0xDE:
+ DmaControllers[1].Mask = (Data & 0x0F);
+ break;
+ }
+
/* Flip-Flop Reset */
{
case 0x0C:
@@ -236,7 +285,7 @@
break;
}
- /* DMA Master Reset */
+ /* DMA Master Reset Registers */
{
case 0x0D:
DmaControllers[0].Command = 0x00;
@@ -255,6 +304,16 @@
DmaControllers[1].Mask = 0x0F;
break;
}
+
+ /* Mask Reset Registers */
+ {
+ case 0x0E:
+ DmaControllers[0].Mask = 0x00;
+ break;
+ case 0xDC:
+ DmaControllers[1].Mask = 0x00;
+ break;
+ }
}
}
@@ -262,6 +321,8 @@
static BYTE WINAPI DmaPageReadPort(USHORT Port)
{
+ DPRINT1("DmaPageReadPort(Port = 0x%04X)\n", Port);
+
switch (Port)
{
case 0x87:
@@ -287,6 +348,8 @@
static VOID WINAPI DmaPageWritePort(USHORT Port, BYTE Data)
{
+ DPRINT1("DmaPageWritePort(Port = 0x%04X, Data = 0x%02X)\n", Port, Data);
+
switch (Port)
{
case 0x87:
@@ -317,6 +380,169 @@
}
/* PUBLIC FUNCTIONS ***********************************************************/
+
+DWORD DmaRequest(IN WORD iChannel,
+ IN OUT PVOID Buffer,
+ IN DWORD length)
+{
+/*
+ * NOTE: This function is adapted from Wine's krnl386.exe,
+ * DMA emulation by Christian Costa.
+ */
+ PDMA_CONTROLLER pDcp;
+ WORD Channel;
+
+ DWORD i, Size, ret = 0;
+ BYTE RegMode, OpMode, Increment, Autoinit, TrMode;
+ PBYTE dmabuf = Buffer;
+
+ ULONG CurrAddress;
+
+ if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
+ {
+ SetLastError(ERROR_INVALID_ADDRESS);
+ return 0;
+ }
+
+ pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
+ Channel = iChannel % DMA_CONTROLLER_CHANNELS; // == (iChannel & 0x03)
+
+ RegMode = pDcp->DmaChannel[Channel].Mode;
+
+ DPRINT1("DMA_Command = %x length=%d\n", RegMode, length);
+
+ /* Exit if the controller is disabled or the channel is masked */
+ if ((pDcp->Command & 0x04) || (pDcp->Mask & (1 << Channel)))
+ return 0;
+
+ OpMode = (RegMode & 0xC0) >> 6;
+ Increment = !(RegMode & 0x20);
+ Autoinit = RegMode & 0x10;
+ TrMode = (RegMode & 0x0C) >> 2;
+
+ /* Process operating mode */
+ switch (OpMode)
+ {
+ case 0:
+ /* Request mode */
+ DPRINT1("Request Mode - Not Implemented\n");
+ return 0;
+ case 1:
+ /* Single Mode */
+ break;
+ case 2:
+ /* Request mode */
+ DPRINT1("Block Mode - Not Implemented\n");
+ return 0;
+ case 3:
+ /* Cascade Mode */
+ DPRINT1("Cascade Mode should not be used by regular apps\n");
+ return 0;
+ }
+
+ /* Perform one the 4 transfer modes */
+ if (TrMode == 4)
+ {
+ /* Illegal */
+ DPRINT1("DMA Transfer Type Illegal\n");
+ return 0;
+ }
+
+ /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
+ Size = (iChannel < 4) ? sizeof(BYTE) : sizeof(WORD);
+
+ // FIXME: Handle wrapping?
+ /* Get the number of elements to transfer */
+ ret = min(pDcp->DmaChannel[Channel].CurrElemCnt, length / Size);
+ length = ret * Size;
+
+ /* 16-bit mode addressing, see:
http://wiki.osdev.org/ISA_DMA#16_bit_issues */
+ CurrAddress = (iChannel < 4) ? (DmaPageRegisters[iChannel].Page << 16) |
(pDcp->DmaChannel[Channel].CurrAddress << 0)
+ : (DmaPageRegisters[iChannel].Page << 16) |
(pDcp->DmaChannel[Channel].CurrAddress << 1);
+
+ switch (TrMode)
+ {
+ /* Verification (no real transfer) */
+ case 0:
+ {
+ DPRINT1("Verification DMA operation\n");
+ break;
+ }
+
+ /* Write */
+ case 1:
+ {
+ DPRINT1("Perform Write transfer of %d elements (%d bytes) at 0x%x %s
with count %x\n",
+ ret, length, CurrAddress, Increment ? "up" :
"down", pDcp->DmaChannel[Channel].CurrElemCnt);
+
+ if (Increment)
+ {
+ MemWrite(CurrAddress, dmabuf, length);
+ }
+ else
+ {
+ for (i = 0; i < length; i++)
+ {
+ MemWrite(CurrAddress - i, dmabuf + i, sizeof(BYTE));
+ }
+ }
+
+ break;
+ }
+
+ /* Read */
+ case 2:
+ {
+ DPRINT1("Perform Read transfer of %d elements (%d bytes) at 0x%x %s with
count %x\n",
+ ret, length, CurrAddress, Increment ? "up" :
"down", pDcp->DmaChannel[Channel].CurrElemCnt);
+
+ if (Increment)
+ {
+ MemRead(CurrAddress, dmabuf, length);
+ }
+ else
+ {
+ for (i = 0; i < length; i++)
+ {
+ MemRead(CurrAddress - i, dmabuf + i, sizeof(BYTE));
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Update DMA registers */
+ pDcp->DmaChannel[Channel].CurrElemCnt -= ret;
+ if (Increment)
+ pDcp->DmaChannel[Channel].CurrAddress += ret;
+ else
+ pDcp->DmaChannel[Channel].CurrAddress -= ret;
+
+ /* Check for end of transfer */
+ if (pDcp->DmaChannel[Channel].CurrElemCnt == 0)
+ {
+ DPRINT1("DMA buffer empty\n");
+
+ /* Update status register of the DMA chip corresponding to the channel */
+ pDcp->Status |= 1 << Channel; /* Mark transfer as finished */
+ pDcp->Status &= ~(1 << (Channel + 4)); /* Reset soft request if any
*/
+
+ if (Autoinit)
+ {
+ /* Reload Current* registers to their initial values */
+ pDcp->DmaChannel[Channel].CurrAddress =
pDcp->DmaChannel[Channel].BaseAddress;
+ pDcp->DmaChannel[Channel].CurrElemCnt =
pDcp->DmaChannel[Channel].BaseElemCnt;
+ }
+ else
+ {
+ /* Set the mask bit for the channel */
+ pDcp->Mask |= (1 << Channel);
+ }
+ }
+
+ return length;
+}
VOID DmaInitialize(VOID)
{
@@ -339,7 +565,7 @@
RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
RegisterIoPort(0x0D, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master
Reset (Write) Registers */
RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
- RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset
Register */
+ RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register
*/
/* Channels 4(Reserved)..7 */
@@ -359,7 +585,7 @@
RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
RegisterIoPort(0xDA, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master
Reset (Write) Registers */
RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
- RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset
Register */
+ RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register
*/
/* Channels Page Address Registers */
@@ -390,8 +616,13 @@
return FALSE;
}
- UNIMPLEMENTED;
- return 0;
+ /*
+ * We assume success first. If something fails,
+ * DmaRequest sets an adequate last error.
+ */
+ SetLastError(ERROR_SUCCESS);
+
+ return DmaRequest(iChannel, Buffer, length);
}
BOOL
@@ -415,9 +646,9 @@
Channel = iChannel % DMA_CONTROLLER_CHANNELS;
pDmaInfo->addr = pDcp->DmaChannel[Channel].CurrAddress;
- pDmaInfo->count = pDcp->DmaChannel[Channel].CurrWordCnt;
-
- // pDmaInfo->page = DmaPageRegisters[iChannel].Page;
+ pDmaInfo->count = pDcp->DmaChannel[Channel].CurrElemCnt;
+
+ pDmaInfo->page = DmaPageRegisters[iChannel].Page;
pDmaInfo->status = pDcp->Status;
pDmaInfo->mode = pDcp->DmaChannel[Channel].Mode;
pDmaInfo->mask = pDcp->Mask;
@@ -450,10 +681,10 @@
pDcp->DmaChannel[Channel].CurrAddress = pDmaInfo->addr;
if (fDMA & VDD_DMA_COUNT)
- pDcp->DmaChannel[Channel].CurrWordCnt = pDmaInfo->count;
-
- // if (fDMA & VDD_DMA_PAGE)
- // DmaPageRegisters[iChannel].Page = pDmaInfo->page;
+ pDcp->DmaChannel[Channel].CurrElemCnt = pDmaInfo->count;
+
+ if (fDMA & VDD_DMA_PAGE)
+ DmaPageRegisters[iChannel].Page = pDmaInfo->page;
if (fDMA & VDD_DMA_STATUS)
pDcp->Status = pDmaInfo->status;
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/dma.h [iso-8859-1] Sun May 10 18:02:45
2015
@@ -2,7 +2,7 @@
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dma.h
- * PURPOSE: Direct Memory Access Controller emulation -
+ * PURPOSE: ISA DMA - Direct Memory Access Controller emulation -
* i8237A compatible with 74LS612 Memory Mapper extension
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
*/
@@ -18,9 +18,9 @@
typedef struct _DMA_CHANNEL
{
WORD BaseAddress;
- WORD BaseWordCnt;
+ WORD BaseElemCnt;
WORD CurrAddress;
- WORD CurrWordCnt;
+ WORD CurrElemCnt;
BYTE Mode;
} DMA_CHANNEL, *PDMA_CHANNEL;
@@ -29,7 +29,7 @@
DMA_CHANNEL DmaChannel[DMA_CONTROLLER_CHANNELS];
WORD TempAddress;
- WORD TempWordCnt;
+ WORD TempElemCnt;
BYTE TempReg;
@@ -49,9 +49,13 @@
} DMA_PAGE_REGISTER, *PDMA_PAGE_REGISTER;
// The 74LS612 contains 16 bytes, each of them being a page register.
-// They are accessible via ports 0x80 through 0x8F .
+// They are accessible via ports 0x80 through 0x8F.
/* FUNCTIONS ******************************************************************/
+
+DWORD DmaRequest(IN WORD iChannel,
+ IN OUT PVOID Buffer,
+ IN DWORD length);
VOID DmaInitialize(VOID);