📄 rio.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
//
// rio.cpp
//
// v1.01 14/01/99 Initial launch.
//
// v1.02 18/01/99 Additional debug added for ioperm() call.
//
// v1.03 25/01/99 Added download support.
// Added delete support.
// Progress callback for upload/download file.
// Boland Turbo C++ v1.01 supported.
//
// v1.04 27/01/99 Win NT v4.0 supported, using RIOIO driver provided.
//
// v1.05 29/01/99 Added version field in dir header to be compatible
// with later Rio Manager v1.01 software.
// Added CheckPresent() member function.
// Support for Alpha platform.
//
// v1.06 11/03/99 Added support for external flash ram.
// Added initialization with bad block check.
// Added file re-ordering support.
//
// v1.07 10/06/99 Added support for FreeBSD.
// Added support for BSDI.
// Added support for OS/2.
// Added support for Rio 64M SE (Special Edition).
// Improved detection of device, using manufacturer ID.
// Selectable IO delays.
//
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include "rio.h"
#include "binary.h"
// platform dependencies
#if defined(_WINNT)
// MS VC++ v5.0 for WinNT v4
#include <windows.h>
#include <winioctl.h>
#include "rioioctl.h"
#define OUTPORT( p, v ) WinNTOutPort( p, v )
#define INPORT( p ) WinNTInPort( p )
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#define ID_DRIVER_VERSION 101
#elif defined(_WIN32)
// MS VC++ v5.0 for Win9x
#include <conio.h>
#define OUTPORT( p, v ) _outp( p, v )
#define INPORT( p ) _inp( p )
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#elif defined(__linux__)
// linux g++
#include <unistd.h>
#include <sys/io.h>
#include <asm/io.h>
#define OUTPORT(p,v) outb( v, p )
#define INPORT(p) inb( p )
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#elif defined(__FreeBSD__)
// FreeBSD g++
#include <fcntl.h>
#include <unistd.h>
#include <machine/cpufunc.h>
#define OUTPORT(p,v) outb( p, v )
#define INPORT(p) inb( p )
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#elif defined(__bsdi__)
// BSD/OS g++
#include <unistd.h>
#include <machine/inline.h>
#define OUTPORT(p,v) outb( p, v )
#define INPORT(p) inb( p )
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#elif defined(__OS2__)
// OS/2 VisualAge C++ v. 3
#include "iopl32.h"
#define OUTPORT(p,v) WPORT( p, v )
#define INPORT(p) ((UCHAR)RPORT( p ))
#define CLOCK_SECOND CLOCKS_PER_SEC
#define DELETEARRAY delete[]
#elif defined(__TURBOC__)
// turboc v1.01
#include <dos.h>
#define OUTPORT( p, v ) outp( p, v )
#define INPORT( p ) inp( p )
#define CLOCK_SECOND ((int)CLOCKS_PER_SEC)
#define DELETEARRAY delete
#else
// not supported
#error ! ! compiler/platform not supported ! !
#endif
// port offset constants
#define OFFSET_PORT_DATA 0
#define OFFSET_PORT_STATUS 1
#define OFFSET_PORT_CONTROL 2
// max tx/rx block retry
#define MAX_RETRY 3
// flash ram bank pos
#define POS_BANK_EXTERNALFLASH 4
// delay's
#define IODELAY(c) { for( long _lA=0; _lA<c; ++_lA ) INPORT(m_iPortStatus); }
#define DELAY(t) { long _lTime=clock()+t; while( _lTime > clock() ) ; }
// new, delete
#define NEWBLOCK( p ) { p = new UCHAR[ CRIO_SIZE_32KBLOCK ]; if ( !p ) { LogError( CRIO_ERROR_ALLOC, "new failed" ); return FALSE; } }
#define ZERONEWBLOCK( p ) { NEWBLOCK(p); memset(p, 0, CRIO_SIZE_32KBLOCK); }
#define DELETEBLOCK( p ) { if ( p ) { DELETEARRAY p; p = NULL; } }
// command out
#define COMMANDOUT(v1, v2, v3) { OUTPORT(m_iPortData, v1); OUTPORT(m_iPortControl, v2); OUTPORT(m_iPortControl, v3); }
// wait for reply
#define WAITNIBBLE( v1 ) { if (!WaitInput(v1)) return FALSE; }
#define WAITACK() { if (!WaitAck()) return FALSE; }
///////////////////////////////////////////////////////////////////////////////
// if WinNT
#if defined(_WINNT)
// handle
static HANDLE m_hDriver;
// WinNT out port
void WinNTOutPort( int iPort, int iValue )
{
DWORD dwSizeReturn;
ULONG ulInput = ((ULONG)iPort-0x378) | ((ULONG)iValue << 16);
DeviceIoControl( m_hDriver, RIOIO_IOCTL_WRITE, &ulInput,
sizeof(long), NULL, 0, &dwSizeReturn, NULL );
}
// WinNT in port
int WinNTInPort( int iPort )
{
DWORD dwSizeReturn;
ULONG ulPort = iPort - 0x378;
ULONG ulData = 0;
DeviceIoControl( m_hDriver, RIOIO_IOCTL_READ, &ulPort, sizeof(ulPort),
&ulData, sizeof(char), &dwSizeReturn, NULL );
return (int)ulData;
}
#endif
///////////////////////////////////////////////////////////////////////////////
// if DOS
#if defined(__TURBOC__)
// get clock ticks
long clock( void )
{
return (long) (*(int far*)MK_FP( 0x40, 0x6c ));
}
#endif
///////////////////////////////////////////////////////////////////////////////
// return file only
static const char* GetFile( const char* pszPathFile )
{
int iLength = strlen( pszPathFile );
if ( !iLength )
return pszPathFile;
const char* pc = pszPathFile + iLength - 1;
while( *pc != '\\' && *pc != '/' && *pc != ':' )
{
if ( pc == pszPathFile )
return pc;
--pc;
}
++pc;
return pc;
}
///////////////////////////////////////////////////////////////////////////////
// set/unset, constructors and destructors
void CRio::Unset( void )
{
// if WinNT
#if defined(_WINNT)
// close device file
if ( m_hDriver )
{
CloseHandle( m_hDriver );
m_hDriver = NULL;
}
#endif
}
BOOL CRio::Set( int iPortBase )
{
// cleanup any previous Set()
Unset();
// determine ports
m_iPortBase = iPortBase;
m_iPortData = m_iPortBase + OFFSET_PORT_DATA;
m_iPortStatus = m_iPortBase + OFFSET_PORT_STATUS;
m_iPortControl = m_iPortBase + OFFSET_PORT_CONTROL;
// if linux
#if defined(__linux__)
// request access to required ports
if ( ioperm(m_iPortBase, 3, 1) )
{
LogError( CRIO_ERROR_IOPRERM, "ioperm() failed, reason '%s'", SZERROR );
return FALSE;
}
#endif
// if FreeBSD
#if defined(__FreeBSD__)
// request direct access to memory addresses
if ( open("/dev/io", O_RDONLY) == -1 )
{
LogError( CRIO_ERROR_IOPRERM, "open() failed, reason '%s'\n", SZERROR );
return FALSE;
}
#endif
// if WinNT
#if defined(_WINNT)
// open generic IO device
m_hDriver = CreateFile( "\\\\.\\RioDev", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if ( m_hDriver == INVALID_HANDLE_VALUE )
{
LogError( CRIO_ERROR_CREATEFILE, "CreateFile() failed, reason %ld\n", GetLastError() );
return FALSE;
}
// check version
DWORD dwSizeReturn;
ULONG ulVersion;
DeviceIoControl( m_hDriver, RIOIO_IOCTL_GETVERSION, NULL,
0, &ulVersion, sizeof(ulVersion), &dwSizeReturn, NULL );
if ( ulVersion != ID_DRIVER_VERSION )
{
LogError( CRIO_ERROR_DRIVERVERSION, "incorrect RioIO driver version, v%d.%d loaded, v%d.%d expected\n",
ulVersion/100, ulVersion%100, ID_DRIVER_VERSION/100, ID_DRIVER_VERSION%100 );
return FALSE;
}
#endif
return TRUE;
}
CRio::CRio()
{
// if WinNT
#if defined(_WINNT)
m_hDriver = NULL;
#endif
// default to use internal flash
m_bUseExternalFlash = FALSE;
// default to not using special edition
m_bSpecialEdition = FALSE;
// default io delay's
m_lTimeIODelayInit = CRIO_TIME_IODELAY_INIT;
m_lTimeIODelayTx = CRIO_TIME_IODELAY_TX;
m_lTimeIODelayRx = CRIO_TIME_IODELAY_RX;
}
CRio::~CRio()
{
Unset();
}
///////////////////////////////////////////////////////////////////////////////
// log error
void CRio::LogError( int iIDError, const char* pszFormat, ... )
{
va_list ArgPtr;
va_start( ArgPtr, pszFormat );
vsprintf( m_szError, pszFormat, ArgPtr );
va_end( ArgPtr );
m_iIDError = iIDError;
}
// find first free 32K block
UINT CRio::FindFirstFree32KBlock( void )
{
UINT uiA;
UCHAR* puc = m_cDirBlock.m_auc32KBlockUsed;
for( uiA=0; uiA<CRIO_MAX_32KBLOCK; ++uiA, ++puc )
{
if ( *puc == CRIO_ID_32KBLOCK_FREE )
return uiA;
}
return 0xffff;
}
// calculate checksum1 (checksum of directory header)
UINT CRio::CalculateChecksum1( void )
{
USHORT usChecksum = m_cDirBlock.m_cDirHeader.m_usChecksum1;
USHORT* paus = (USHORT*)&m_cDirBlock.m_cDirHeader;
for( unsigned int iA=0; iA<(sizeof(CDirHeader)/sizeof(short)); ++iA )
usChecksum -= *paus++;
return usChecksum;
}
// calculate checksum2 (checksum of directory entries, used flags and FAT)
UINT CRio::CalculateChecksum2( void )
{
USHORT usChecksum = 0;
USHORT* paus = (USHORT*)m_cDirBlock.m_acDirEntry;
int iSize = ( sizeof(CDirBlock) - sizeof(CDirHeader) ) / sizeof(short);
for( int iA=0; iA<iSize; ++iA )
usChecksum -= *paus++;
return usChecksum;
}
// wait for requested input from status port
BOOL CRio::WaitInput( int iValue )
{
long lTime = clock() + CLOCK_SECOND;
UCHAR ucRx;
while( lTime > clock() )
{
ucRx = INPORT( m_iPortStatus ) & 0xf8;
if ( ucRx == (int)iValue )
return TRUE;
}
return FALSE;
}
// wait for ack
BOOL CRio::WaitAck( void )
{
long lTime = clock() + CLOCK_SECOND;
while( lTime > clock() )
{
UCHAR ucRx = INPORT( m_iPortStatus );
if ( ucRx & 0x08 )
return TRUE;
}
return FALSE;
}
// get byte from status port
UINT CRio::GetDataByte( void )
{
// get hi nibble
OUTPORT( m_iPortControl, B_00000000 );
IODELAY( m_lTimeIODelayRx );
UCHAR ucRx = INPORT( m_iPortStatus );
UCHAR ucIn = ((ucRx & 0xf0) ^ 0x80) >> 4;
// get lo nibble and combine with previous nibble to make byte
OUTPORT( m_iPortControl, B_00000100 );
IODELAY( m_lTimeIODelayRx );
ucRx = INPORT( m_iPortStatus );
ucIn |= (ucRx & 0xf0) ^ 0x80;
// reverse bits in byte
UCHAR ucReversed = 0;
for( int iC=0; iC<8; ++iC )
{
ucReversed <<= 1;
ucReversed |= (ucIn & 1);
ucIn >>= 1;
}
return ucReversed;
}
// io intro
BOOL CRio::IOIntro( void )
{
OUTPORT( m_iPortControl, B_00000100 );
COMMANDOUT( B_10101000, B_00001100, B_00000100 );
OUTPORT( m_iPortControl, B_00000000 );
IODELAY( m_lTimeIODelayInit );
OUTPORT( m_iPortControl, B_00000100 );
IODELAY( m_lTimeIODelayInit );
COMMANDOUT( B_10101101, B_00001100, B_00000100 );
COMMANDOUT( B_01010101, B_00000000, B_00000100 );
COMMANDOUT( B_10101110, B_00001100, B_00000100 );
COMMANDOUT( B_10101010, B_00000000, B_00000100 );
COMMANDOUT( B_10101000, B_00001100, B_00000100 );
OUTPORT( m_iPortControl, B_00000000 );
IODELAY( m_lTimeIODelayInit );
OUTPORT( m_iPortControl, B_00000100 );
IODELAY( m_lTimeIODelayInit );
return TRUE;
}
// io outro
BOOL CRio::IOOutro( void )
{
COMMANDOUT( B_10101101, B_00001100, B_00000100 );
COMMANDOUT( B_11111111, B_00000000, B_00000100 );
OUTPORT( m_iPortData, B_00000000 );
return TRUE;
}
// tx 32K block retry
BOOL CRio::Tx32KBlockRetry( void* pv, UINT uiPos32KBlock, UINT uiPos32KBlockPrev,
UINT uiPos32KBlockNext )
{
ULONG ulPos512ByteBlock;
ULONG ulPosHi;
ULONG ulPosMid;
ULONG ulPosLo;
unsigned int iA, iB;
// io intro
if ( !IOIntro() )
return FALSE;
// if internal, blocksize = 8K else if external blocksize = 16K
int iCount8K = m_bUseExternalFlash ? 2 : 1;
// prepare all pages in block
for( iA=0; iA<4; iA+=iCount8K )
{
ulPos512ByteBlock = ((ULONG)uiPos32KBlock * 32768 + (ULONG)iA * 8192) / 512;
ulPosLo = ulPos512ByteBlock & 0xff;
if ( m_bUseExternalFlash )
{
ulPosHi = POS_BANK_EXTERNALFLASH;
ulPosMid = (ulPos512ByteBlock & 0xff00) >> 8;
}
else if ( m_bSpecialEdition )
{
ulPosHi = ulPos512ByteBlock / 32768;
ulPosMid = (ulPos512ByteBlock & 0x7f00) >> 8;
}
else
{
ulPosHi = ulPos512ByteBlock / 16384;
ulPosMid = (ulPos512ByteBlock & 0x3f00) >> 8;
}
COMMANDOUT( B_10101011, B_00001100, B_00000100 );
COMMANDOUT( ulPosHi, B_00000000, B_00000100 );
COMMANDOUT( B_10100001, B_00001100, B_00000100 );
COMMANDOUT( B_01100000, B_00000000, B_00000100 );
COMMANDOUT( B_10100010, B_00001100, B_00000100 );
COMMANDOUT( ulPosLo, B_00000000, B_00000100 );
COMMANDOUT( ulPosMid, B_00000000, B_00000100 );
COMMANDOUT( B_10100001, B_00001100, B_00000100 );
COMMANDOUT( B_11010000, B_00000000, B_00000100 );
WAITACK();
COMMANDOUT( B_10100001, B_00001100, B_00000100 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -