📄 biosport.cpp
字号:
// ******************** START OF BIOSPORT.CPP ********************
//
// This file contains all of the code used by the BIOSPort and
// EBIOSPort classes.
//
#include <stdio.h>
#include <ctype.h>
#include "rs232.h"
#include "biosport.h"
#include "_8250.h"
// The BIOSPort constructor doesn't have very much work to do. It
// sets all the saved settings to invalid values, since none of them
// can be accessed. It has to set up the debug output, then set all
// of the port settings, and then return. Note that there is no way
// to detect an error when attempting to access a BIOS port, so the
// constructor always succeeds.
BIOSPort::BIOSPort( RS232PortName port,
long baud_rate,
char parity,
int word_length,
int stop_bits,
int dtr,
int rts,
int xon_xoff,
int rts_cts,
int dtr_dsr )
{
port_name = port;
error_status = RS232_SUCCESS;
first_debug_output_line = RS232::FormatDebugOutput();
debug_line_count = FormatDebugOutput();
saved_settings.BaudRate = -1L;
saved_settings.Parity = '?';
saved_settings.WordLength = -1;
saved_settings.StopBits = -1;
saved_settings.Dtr = -1;
saved_settings.Rts = -1;
saved_settings.XonXoff = -1;
saved_settings.RtsCts = -1;
saved_settings.DtrDsr = -1;
settings.Adjust( baud_rate,
parity,
word_length,
stop_bits,
dtr,
rts,
xon_xoff,
rts_cts,
dtr_dsr );
write_settings();
line_status = 0;
}
// The void constructor is called by the inherited class EBIOSPort when
// it is being constructed. Since EBIOSPort will initialize all the
// settings, this constructor just initializes the debug output.
// Note that this constructor is protected, since it doesn't create a
// properly initialized port that could be used as an object by itself.
BIOSPort::BIOSPort( void )
{
first_debug_output_line = RS232::FormatDebugOutput();
debug_line_count = FormatDebugOutput();
}
// There is no BIOS function to close a port, so the destructor
// doesn't have to do anything.
BIOSPort::~BIOSPort( void )
{
}
// The write_settings function is fairly limited when it comes to
// options. There are lots of opportunities for errors here.
// Note that if the constructor attempts an invalid settings, the
// error code never gets returned to the calling program, since
// the constructor doesn't return a value.
RS232Error BIOSPort::write_settings( void )
{
union REGS r;
RS232Error status = RS232_SUCCESS;
r.x.dx = port_name;
r.h.ah = 0;
r.h.al = 0;
switch ( toupper( settings.Parity ) ) {
case 'E' : r.h.al |= 0x18; break;
case 'O' : r.h.al |= 0x08; break;
default : settings.Parity = 'N';
status = RS232_ILLEGAL_PARITY_SETTING;
case 'N' : r.h.al |= 0x00; break;
}
switch ( settings.StopBits ) {
case 1 : r.h.al |= 0; break;
default : settings.StopBits = 2;
status = RS232_ILLEGAL_STOP_BITS;
case 2 : r.h.al |= 4; break;
}
switch ( settings.WordLength ) {
case 5 : r.h.al |= 0; break;
case 6 : r.h.al |= 1; break;
case 7 : r.h.al |= 2; break;
default : settings.WordLength = 8;
status = RS232_ILLEGAL_WORD_LENGTH;
case 8 : r.h.al |= 3; break;
}
switch ( settings.BaudRate ) {
case 110L : r.h.al |= 0x00; break;
case 150L : r.h.al |= 0x20; break;
case 300L : r.h.al |= 0x40; break;
case 600L : r.h.al |= 0x60; break;
case 1200L : r.h.al |= 0x80; break;
case 2400L : r.h.al |= 0xa0; break;
case 4800L : r.h.al |= 0xc0; break;
default : settings.BaudRate = 9600L;
status = RS232_ILLEGAL_BAUD_RATE;
case 9600L : r.h.al |= 0xe0; break;
}
int86( 0x14, &r, &r );
if ( settings.Dtr != -1 ) {
settings.Dtr = -1;
status = RS232_DTR_NOT_SUPPORTED;
}
if ( settings.Rts != -1 ) {
settings.Rts = -1;
status = RS232_RTS_NOT_SUPPORTED;
}
if ( settings.RtsCts != -1 ) {
settings.RtsCts = -1;
status = RS232_RTS_CTS_NOT_SUPPORTED;
}
if ( settings.DtrDsr != -1 ) {
settings.DtrDsr = -1;
status = RS232_DTR_DSR_NOT_SUPPORTED;
}
if ( settings.XonXoff != -1 ) {
settings.XonXoff = -1;
status = RS232_XON_XOFF_NOT_SUPPORTED;
}
return status;
}
// If the data ready bit is set in the UART LSR, this routine calls
// the BIOS function to read the character. Otherwise it returns
// a timeout. Even if the data ready bit is set, this routine is still
// vulnerable to hanging up in a several second delay if the
// incoming DSR line is not set.
int BIOSPort::read_byte( void )
{
union REGS r;
if ( error_status < 0 )
return error_status;
r.h.ah = 3;
r.x.dx = port_name;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
if ( r.h.ah & LSR_DATA_READY ) {
r.h.ah = 2;
r.x.dx = port_name;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
if ( ( r.h.ah & 0x80 ) == 0 )
return( r.h.al );
}
return( RS232_TIMEOUT );
}
// This function also uses a standard BIOS function call. It is also
// vulnerable to a delay in the event that DSR or CTS are not set.
int BIOSPort::write_byte( int c )
{
union REGS r;
if ( error_status < 0 )
return error_status;
r.x.dx = port_name;
r.h.ah = 0x01;
r.h.al = (char) c;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
if ( r.h.ah & 0x80 )
return RS232_TIMEOUT;
return RS232_SUCCESS;
}
RS232Error BIOSPort::Set( long baud_rate,
int parity,
int word_length,
int stop_bits )
{
settings.Adjust( baud_rate,
parity,
word_length,
stop_bits,
UNCHANGED,
UNCHANGED,
UNCHANGED,
UNCHANGED,
UNCHANGED );
return write_settings();
}
// The next four routines all execute the BIOS call that reads
// in the MSR. The appropriate bit is then masked out, and the
// result is returned to the calling routine.
int BIOSPort::Cd( void )
{
union REGS r;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
return ( r.h.al & MSR_CD ) != 0;
}
int BIOSPort::Ri( void )
{
union REGS r;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
return ( r.h.al & MSR_RI ) != 0;
}
int BIOSPort::Cts( void )
{
union REGS r;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
return ( r.h.al & MSR_CTS ) != 0;
}
int BIOSPort::Dsr( void )
{
union REGS r;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
return ( r.h.al & MSR_DSR ) != 0;
}
// The four routines that check line status bits operate almost
// identically to the modem status routines. The only difference
// is that the line status bits are accumulated in a private data
// member, so instead of just checking the bit in the LSR, these
// routines have to check the current state ORed with the cumulative
// state. In addition, each of the routines has the option of
// either leaving the bit set, or clearing it after reading it.
int BIOSPort::ParityError( int reset )
{
union REGS r;
int status;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
status = ( line_status & LSR_PARITY_ERROR ) != 0;
if ( reset != UNCHANGED && reset != 0 )
line_status &= ~LSR_PARITY_ERROR;
return status;
}
int BIOSPort::BreakDetect( int reset )
{
union REGS r;
int status;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
status = ( line_status & LSR_BREAK_DETECT ) != 0;
if ( reset != UNCHANGED && reset != 0 )
line_status &= ~LSR_BREAK_DETECT;
return status;
}
int BIOSPort::FramingError( int reset )
{
union REGS r;
int status;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
status = ( line_status & LSR_FRAMING_ERROR ) != 0;
if ( reset != UNCHANGED && reset != 0 )
line_status &= ~LSR_FRAMING_ERROR;
return status;
}
int BIOSPort::HardwareOverrunError( int reset )
{
union REGS r;
int status;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 3;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
status = ( line_status & LSR_OVERRUN_ERROR ) != 0;
if ( reset != UNCHANGED && reset != 0 )
line_status &= ~LSR_OVERRUN_ERROR;
return status;
}
// The formatted debug output for BIOSPort is sparse. It prints out
// two lines of information that dump the states of the MSR and LSR.
int BIOSPort::FormatDebugOutput( char *buffer, int line_number )
{
if ( buffer == 0 )
return( first_debug_output_line + 2 );
if ( line_number < first_debug_output_line )
return RS232::FormatDebugOutput( buffer, line_number );
switch( line_number - first_debug_output_line ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -