📄 dmatrans.cpp
字号:
memcpy( vOutputBuffer, (PUCHAR)writeBytes, vOutputPB->ioDataLength );
DWORD index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
// Write physical address to port to trigger an actual write
WRITE_PORT_ULONG( DMA_IO_OUTPUT_REG(index), ( ULONG )outputPB );
if ( vOutputPB->ioStatus != 0 ) // Error, return failure
{
vOutputPB->ioDataLength = -1;
}
LeaveCriticalSection( &writeMutex );
return vOutputPB->ioDataLength;
}
NewWriteCode:
// Enter critical section so no other write call can interfere
EnterCriticalSection( &writeMutex );
DWORD index = 0;
DWORD bytesWritten = 0;
if (channel < VIRTUAL_BASE )
{
index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
}
else
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:WRITE virtual on channel %x\n"), channel) );
WRITE_PORT_ULONG( DMA_V_CHANNEL_WRITE, channel );
}
vOutputPB->ioStatus = 0;
vOutputPB->ioDataPtr = (ULONG)outputBuffer; // specify physical address
if ( numBytes > DMA_PACKET_SIZE ) // Trying to write too many bytes, can only write at the max DMA_PACKET_SIZE
{
vOutputPB->ioDataLength = DMA_PACKET_SIZE;
}
else // Writing numBytes
{
vOutputPB->ioDataLength = numBytes;
}
DEBUGMSG( TRUE, (TEXT("DMA Transport:WRITE virtual %x/%x bytes on channel %x \n"), numBytes, vOutputPB->ioDataLength, channel) );
memcpy( vOutputBuffer, (PUCHAR)writeBytes, vOutputPB->ioDataLength );
DEBUGMSG( TRUE, (TEXT("DMA Transport:WRITE wrote out the data on %x \n"), channel) );
// Write physical address to port to trigger an actual write
WRITE_PORT_ULONG( DMA_IO_OUTPUT_REG(index), ( ULONG )outputPB );
bytesWritten = vOutputPB->ioDataLength;
if ( vOutputPB->ioStatus != 0 ) // Error, return failure
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:WRITE failed on channel %x with code %x\n"), channel, vOutputPB->ioStatus) );
if (channel >= VIRTUAL_BASE )
{
// Propagate the error code
SetLastError(vOutputPB->ioStatus);
}
bytesWritten = -1;
}
if (channel >= VIRTUAL_BASE )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:WRITE virtual on channel %x (Cleared W_REG)\n"), channel) );
WRITE_PORT_ULONG( DMA_V_CHANNEL_WRITE, 0 );
}
LeaveCriticalSection( &writeMutex );
return bytesWritten;
}
/*------------------------------------------------------------------
DMA_Read
Reads packets from device. Can only read 4 KB chunks, will
fail if another value is specified. (The DMATransport device
transmits data in 4K chunks. We leave it up to the client
of this driver to handle breaking up packets.)
------------------------------------------------------------------*/
DWORD
DMA_Read( DWORD channel, // In: Channel number
LPVOID buffer, // In\Out: buffer to read data into
DWORD numRead // In: Number of bytes to read into buffer
)
{
if ( channel >= VIRTUAL_BASE )
goto NewReadCode;
else
{
DWORD bytesRead = 0;
if ( numRead != DMA_PACKET_SIZE ) // can only read 4KB chunks
{
return -1;
}
EnterCriticalSection( &readMutex );
vInputPB->ioDataLength = DMA_PACKET_SIZE;
vInputPB->ioDataPtr = (ULONG)inputBuffer; // specify physical address
vInputPB->ioStatus = -1;
DWORD index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
if ( *(channels[index].vPFlags) & kDMATransportDataReady )
{
WRITE_PORT_ULONG((PULONG)DMA_IO_INPUT_REG( index ), ( ULONG )inputPB);
// Data and no error
if( vInputPB->ioDataLength != 0 && vInputPB->ioStatus == 0 )
{
// now copy that many bytes into output buffer.
memcpy(buffer, vInputBuffer, vInputPB->ioDataLength );
}
else // error
{
vInputPB->ioDataLength = -1; // 0 indicates error
}
}
else
{
vInputPB->ioDataLength = 0; // Nothing to read, 0 indicates end of file
}
bytesRead = vInputPB->ioDataLength;
LeaveCriticalSection( &readMutex );
return bytesRead;
}
NewReadCode:
DWORD bytesRead = 0;
if ( numRead != DMA_PACKET_SIZE ) // can only read 4KB chunks
{
return -1;
}
EnterCriticalSection( &readMutex );
DWORD index = 0;
if (channel < VIRTUAL_BASE )
{
index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
}
else
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:READ virtual on channel %x\n"), channel) );
WRITE_PORT_ULONG( DMA_V_CHANNEL_READ, channel );
}
vInputPB->ioDataLength = DMA_PACKET_SIZE;
vInputPB->ioDataPtr = (ULONG)inputBuffer; // specify physical address
vInputPB->ioStatus = -1;
if ( channel < VIRTUAL_BASE && (*(channels[index].vPFlags) & kDMATransportDataReady) ||
channel >= VIRTUAL_BASE && (*DMA_V_CHANNEL_READ & kDMATransportDataReady) )
{
WRITE_PORT_ULONG((PULONG)DMA_IO_INPUT_REG( index ), ( ULONG )inputPB);
// Data and no error
if( vInputPB->ioDataLength != 0 && vInputPB->ioStatus == 0 )
{
// now copy that many bytes into output buffer.
DEBUGMSG( TRUE, (TEXT("DMA Transport:READ %x bytes SUCCESS on channel %d\n"), vInputPB->ioDataLength, channel) );
memcpy(buffer, vInputBuffer, vInputPB->ioDataLength );
}
else // error
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:READ FAILED on channel %x\n"), channel) );
vInputPB->ioDataLength = -1; // 0 indicates error
}
}
else
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:READ nothing to read on channel %x\n"), channel) );
vInputPB->ioDataLength = 0; // Nothing to read, 0 indicates end of file
}
bytesRead = vInputPB->ioDataLength;
if (channel >= VIRTUAL_BASE )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:READ virtual on channel %x (Cleared R_REG)\n"), channel) );
WRITE_PORT_ULONG( DMA_V_CHANNEL_READ, 0 );
}
LeaveCriticalSection( &readMutex );
return bytesRead;
}
/*------------------------------------------------------------------
DMA_IOControl
Standard stream interface IOControl function. Does nothing here.
------------------------------------------------------------------*/
extern "C" BOOL
DMA_IOControl( DWORD channel, // In: channel number
DWORD code, // In: Holds the requested operation
PBYTE inBuf, // In: Buffer being passed in
DWORD inLength, // In: Length of the inBuf
PBYTE outBuf, // Out: Data sent from driver to application
DWORD outLength, // Out: length of the outBuf
PDWORD actualOut // Out: actual number of bytes received
)
{
if ( code == IOCTL_GET_DMA_CHANNEL_INFO )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:Processing IOCTL - %x \n"), IOCTL_GET_DMA_CHANNEL_INFO) );
*actualOut = 0;
// Verify arguments
if (channel < VIRTUAL_BASE )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - invalid channel number\n"), channel) );
return FALSE;
}
if (outBuf == NULL || outLength < 8)
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - invalid buffer arguments\n"), channel) );
return FALSE;
}
EnterCriticalSection( &vchannelAccess );
// Retrieve the channel
DMAChannel * channelObj = getVirtualChannel(channel);
if (channelObj == NULL)
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - couldn't find the channel\n"), channel) );
goto ErrorGetInfo;
}
if (!DuplicateHandle( GetCurrentProcess(),
channelObj->dataReadyEvent,
GetOwnerProcess(),
(void **)&outBuf[4],
0,
FALSE,
DUPLICATE_SAME_ACCESS ))
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:Couldn't duplicate event handle. Last Error %x\n"), GetLastError()) );
goto ErrorGetInfo;
}
// Write out the channel number
*((DWORD *)outBuf) = channel;
*actualOut = 8;
LeaveCriticalSection( &vchannelAccess );
DEBUGMSG( TRUE, (TEXT("DMA Transport:SUCCESS IOCTL for channel %x\n"), channel) );
return TRUE;
ErrorGetInfo:
LeaveCriticalSection( &vchannelAccess );
return FALSE;
}
else if ( code == IOCTL_GET_DMA_CHANNEL_CONNECTED )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:Processing IOCTL - %x \n"), IOCTL_GET_DMA_CHANNEL_INFO) );
*actualOut = 0;
// Verify arguments
if (channel < VIRTUAL_BASE )
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - invalid channel number\n"), channel) );
return FALSE;
}
if ( outBuf == NULL || outLength < 4)
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - invalid buffer arguments\n"), channel) );
return FALSE;
}
EnterCriticalSection( &vchannelAccess );
// Retrieve the channel
DMAChannel * channelObj = getVirtualChannel(channel);
if (channelObj == NULL)
{
DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED IOCTL for channel %x - couldn't find the channel\n"), channel) );
goto ErrorGetConnected;
}
// Get the channel status from the emulator
WRITE_PORT_ULONG(DMA_CURR_V_CHANNEL, channel);
WRITE_PORT_ULONG(DMA_CURR_V_OPERATION, kDMAVirtOpetationIsInUse);
*((DWORD *)outBuf) = *DMA_CURR_V_STATUS;
*actualOut = 4;
DEBUGMSG( TRUE, (TEXT("DMA Transport:Channel status for %x is %x \n"),channel, *((DWORD *)outBuf)) );
LeaveCriticalSection( &vchannelAccess );
DEBUGMSG( TRUE, (TEXT("DMA Transport:SUCCESS IOCTL for channel %x\n"), channel) );
return TRUE;
ErrorGetConnected:
LeaveCriticalSection( &vchannelAccess );
return FALSE;
}
return FALSE;
}
/*------------------------------------------------------------------
DMA_PowerUp
Standard stream interface PowerUp function. Does nothing here.
------------------------------------------------------------------*/
extern "C" void
DMA_PowerUp( DWORD hContext )
{
// do nothing
}
/*------------------------------------------------------------------
DMA_PowerDown
Standard stream interface PowerDown function. Does nothing here.
------------------------------------------------------------------*/
extern "C" void
DMA_PowerDown( DWORD hContext )
{
// do nothing
}
/*------------------------------------------------------------------
DMA_Seek
Standard stream interface seek function. Does nothing here.
------------------------------------------------------------------*/
extern "C" DWORD
DMA_Seek( DWORD hOpenContext,
long Amount,
WORD Type )
{
// Do nothing, return fail
return -1;
}
DMAChannel * getVirtualChannel(DWORD channelNumber)
{
DMAChannel * currChannel = virtChannels;
while (currChannel != NULL )
{
if ( currChannel->channelNumber == channelNumber)
{
return currChannel;
}
currChannel = currChannel->next;
}
// Failed to find the channel
return NULL;
}
DMAChannel * addVirtualChannel(DWORD channelNumber)
{
DMAChannel * currChannel = virtChannels;
DMAChannel * newChannel = new DMAChannel();
if ( newChannel == NULL )
return NULL;
while (currChannel != NULL && currChannel->next != NULL)
{
currChannel = currChannel->next;
}
if ( currChannel != NULL )
currChannel->next = newChannel;
else
virtChannels = newChannel;
newChannel->channelNumber = channelNumber;
return newChannel;
}
void deleteVirtualChannel(DMAChannel * channel)
{
DMAChannel * currChannel = virtChannels;
if ( channel == NULL )
return;
// Check with the head of the list
if (channel == virtChannels)
{
virtChannels = virtChannels->next;
delete channel;
return;
}
// Check the body of the list
while (currChannel != NULL && currChannel->next != channel)
{
currChannel = currChannel->next;
}
// If found in the body - relink around it.
if (currChannel != NULL )
{
currChannel->next = currChannel->next->next;
delete channel;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -