📄 dmatrans.cpp
字号:
Writes indicated number of bytes to DMA device, up to a
maximum of 4K. (The DMATransport device transmits data in 4K
chunks. We leave it up to the client of this driver to handle
breaking up packets.)
Returns failure, or the number of bytes actually written.
------------------------------------------------------------------*/
DWORD
DMA_Write( DWORD channel, // In: channel number: 4-7
LPCVOID writeBytes, // In: Data to write
DWORD numBytes // In: number of bytes to write
)
{
DWORD bytesWritten = 0;
// Enter critical section so no other write call can interfere
EnterCriticalSection( &writeMutex );
// Security: try/except is used to ensure that readMutex doesn't remain locked if the buffer
// memory becomes inaccessible during the read operation.
__try
{
DWORD index = 0;
if (channel < VIRTUAL_BASE )
{
index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
}
else
{
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;
}
memcpy( vOutputBuffer, (PUCHAR)writeBytes, vOutputPB->ioDataLength );
// 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 )
{
WRITE_PORT_ULONG( DMA_V_CHANNEL_WRITE, 0 );
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bytesWritten = -1;
}
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
)
{
DWORD bytesRead = 0;
if ( numRead != DMA_PACKET_SIZE ) // can only read 4KB chunks
{
return -1;
}
EnterCriticalSection( &readMutex );
// Security: try/except is used to ensure that readMutex doesn't remain locked if the buffer
// memory becomes inaccessible during the read operation.
__try
{
DWORD index = 0;
if (channel < VIRTUAL_BASE )
{
index = channel - NUM_DMA_FIRST_CHANNEL; // offset channel to match array indices
}
else
{
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.
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
{
vInputPB->ioDataLength = 0; // Nothing to read, 0 indicates end of file
}
bytesRead = vInputPB->ioDataLength;
if (channel >= VIRTUAL_BASE )
{
WRITE_PORT_ULONG( DMA_V_CHANNEL_READ, 0 );
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bytesRead = -1;
}
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
)
{
BOOL bRet = FALSE;
if ( code == 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 );
// Security: try/except is used to ensure that vchannelAccess doesn't remain locked if the buffer
// memory becomes inaccessible during the read operation.
__try
{
// 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) );
}
else
{
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()) );
}
else
{
// Write out the channel number
*((DWORD *)outBuf) = channel;
*actualOut = 8;
bRet = TRUE;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// Nothing needs to be done here - bRet is FALSE already
}
LeaveCriticalSection( &vchannelAccess );
return bRet;
}
else if ( code == IOCTL_GET_DMA_CHANNEL_CONNECTED )
{
*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 );
// Security: try/except is used to ensure that vchannelAccess doesn't remain locked if the buffer
// memory becomes inaccessible during the read operation.
__try
{
// 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) );
}
else
{
// 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;
bRet = TRUE;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// Nothing needs to be done here - bRet is FALSE already
}
LeaveCriticalSection( &vchannelAccess );
}
return bRet;
}
/*------------------------------------------------------------------
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 + -