home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
CPPCOM17.ZIP
/
UART.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-27
|
10KB
|
470 lines
/***************************************************************************
These C++ classes are copyright 1990, by William Herrera.
All those who put this code or its derivatives in a commercial product MUST
mention this copyright in their documentation for users of the products in
which this code or its derivative classes are used. Otherwise, this code
may be freely distributed and freely used for any purpose.
***************************************************************************/
// File uart.cpp, class definitions for the uart class.
// By William Herrera.
// See your modem manual (I used MultiTech's) or the IBM Technical
// reference manual for more information on the 8250 UART used in the PC.
#include <stdio.h>
#include <stdlib.h>
#include "uart.hpp"
// Note: the parameters below are the defaults used by MultiTech.
// If you have problems with using your modem, look up the maximum
// speed it uses and its addresses and vectors and adjust accordingly.
static const long default_baud_rate = 38400L;
unsigned int uart::io_address[NUM_PORTS] = { 0x3F8, 0x2F8, 0x2E8, 0x3E8 };
int uart::portvector_num[NUM_PORTS] = { 0xC, 0xB, 0xB, 0xC };
char uart::intmaskbit[NUM_PORTS] = { 0x10, 0x08, 0x08, 0x10 };
char uart::old_intmask[NUM_PORTS] = { 0, 0 , 0 , 0 };
char uart::old_MCR[NUM_PORTS] = { 0, 0 , 0 , 0 };
char uart::old_IER[NUM_PORTS] = { 0, 0, 0, 0 };
#ifdef __TURBOC__
DRIVER uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
#else ifdef __ZTC__
void far * uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
#endif
uart::uart() { ; }
uart::~uart() { ; }
// the function below allows us to set the parameters for a given
// set of hadware used by the UART, especially for ports above COM2.
// Note this should be done BEFORE allocating a class instance.
void uart::SetPortAddresses(int portnum, unsigned int io_add,
int portvec, char imask)
{
int indx = portnum - 1;
if(
(indx < 0) || (indx > NUM_PORTS - 1) ||
(old_driver[indx] != NULL) )
{
fputs("uart::SetPortAdressses() cannot set port requested.\n",
stderr);
}
else
{
io_address[indx] = io_add;
portvector_num[indx] = portvec;
intmaskbit[indx] = imask;
}
}
// the following function sets up the PC for interrupt-driven serial
// communications through the UART. Returns 0 for success, -1 for
// port disallowed, -2 for uart interrupts not resettable.
int uart::RegisterDriver(int portnum, DRIVER driv)
{
int retval;
if(
(portnum < 1) || (portnum > NUM_PORTS) ||
(old_driver[portnum - 1] != NULL) )
{
fputs("uart::RegisterDriver() cannot set port requested.\n",
stderr);
retval = -1;
}
else
{
disable();
// Hardware interrupts off til we change the settings.
// Make sure DLAB of LSR is 0 to allow access to IER and MCR.
SetLCR_DLAB(false);
// Save old IER and MCR.
old_IER[portnum -1] = GetIER();
old_MCR[portnum- 1] = GetMCR();
// Then check the UART for accessibility.
SetIER(0);
if(GetIER() != 0)
{
fputs("uart error: unable to reset IER\n", stderr);
retval = -2;
}
else
{
// save the old interrupt mask.
old_intmask[portnum - 1] = inportb(0x21);
// reset vector to point to our handler.
#ifdef __TURBOC__
old_driver[portnum - 1] = getvect(portvector_num[portnum - 1]);
setvect(portvector_num[portnum - 1], driv);
#else ifdef __ZTC__
unsigned int iseg, ioff;
int_getvector(portvector_num[portnum - 1], &ioff, &iseg);
old_driver[portnum - 1] = MK_FP(iseg, ioff);
int_intercept(portvector_num[portnum - 1], driv, 0);
#endif
SetMCR(9); // turn on DTR and interrupts by modem (1|8).
SetIER(13); // turn on data ready, line, modem ints (1|4|8).
// Now enable controller for serial port interrupts.
outportb( 0x21, (inportb(0x21) & ~(intmaskbit[portnum - 1])) );
// set speed to predefined default_baud_rate.
SetSpeed(default_baud_rate);
// Set port to default parameters of 8 data, 1 stop, no parity.
SetParity(NOPAR);
SetWordLength(8);
SetStopBits(1);
retval = 0;
}
enable();
}
return retval;
}
// This function resets the interrupt controller and UART and
// generally cleans up after the RegisterDriver function.
// Returns 0 on success, -1 on port not restorable.
int uart::RestoreDriver(int portnum)
{
int retval;
if( (portnum < 1) || (portnum > NUM_PORTS) ||
(old_driver[portnum - 1] == NULL) )
{
fputs("UART Error: Cannot restore port.\n", stderr);
retval = -1;
}
else
{
// reset the interrupt vector.
disable();
#ifdef __TURBOC__
setvect(portvector_num[portnum - 1], old_driver[portnum - 1]);
#else ifdef __ZTC__
int_restore(portvector_num[portnum - 1]);
#endif
// reset the i8259 mask to its original state.
outportb(0x21, old_intmask[portnum - 1]);
// reset UART registers.
SetIER(old_IER[portnum -1]);
SetMCR(old_MCR[portnum - 1]);
enable();
old_driver[portnum - 1] = NULL;
retval = 0;
}
return retval;
}
char uart::GetLCR()
{
return inportb(LCR());
}
char uart::GetDLL()
{
return inportb(DLL());
}
char uart::GetDLM()
{
return inportb(DLM());
}
char uart::GetLSR()
{
return inportb(LSR());
}
char uart::GetMCR()
{
return inportb(MCR());
}
char uart::GetMSR()
{
return inportb(MSR());
}
char uart::GetRBR()
{
return inportb(RBR());
}
char uart::GetIER()
{
return inportb(IER());
}
char uart::GetIIR()
{
return inportb(IIR());
}
boolean uart::GetLSR_THRE()
{
return (GetLSR() & 32) ? true : false;
}
void uart::SetLCR(char byte)
{
outportb(LCR(), byte);
}
void uart::SetDLL(char byte)
{
outportb(DLL(), byte);
}
void uart::SetDLM(char byte)
{
outportb(DLM(), byte);
}
void uart::SetLSR(char byte)
{
outportb(LSR(), byte);
}
void uart::SetMCR(char byte)
{
outportb(MCR(), byte);
}
void uart::SetMSR(char byte)
{
outportb(MSR(), byte);
}
void uart::SetTHR(char byte)
{
outportb(THR(), byte);
}
void uart::SetIER(char byte)
{
outportb(IER(), byte);
}
void uart::SetIER_Recieve(boolean bit)
{
SetIER( (bit) ? GetIER() | 1 : GetIER() & (~1) );
}
void uart::SetIER_Transmit(boolean bit)
{
SetIER( (bit) ? GetIER() | 2 : GetIER() & (~2) );
}
void uart::SetIER_Line(boolean bit)
{
SetIER( (bit) ? GetIER() | 4 : GetIER() & (~4) );
}
void uart::SetIER_Modem(boolean bit)
{
SetIER( (bit) ? GetIER() | 8 : GetIER() & (~8) );
}
void uart::SetLCR_DLAB(boolean bit)
{
SetLCR( (bit) ? GetLCR() | 128 : GetLCR() & (~128) );
}
void uart::SetLSR_DR(boolean bit)
{
SetLSR( (bit) ? GetLSR() | 1 : GetLSR() & (~1) );
}
void uart::SetBaudRate(long speed)
{
long divisor = 115200L / speed;
char lsb = divisor & 0xFF;
char msb = (divisor >> 8) & 0xFF;
SetLCR_DLAB(true);
SetDLL(lsb);
SetDLM(msb);
SetLCR_DLAB(false);
}
long uart::GetBaudRate()
{
SetLCR_DLAB(true);
int lsb = GetDLL() & 0xFF;
int msb = GetDLM() & 0xFF;
SetLCR_DLAB(false);
return ( 115200L / (((long)msb << 8) + (long)lsb) );
}
void uart::SetParity(parity_t p)
{
SetLCR( (GetLCR() & 0xC7) | p);
}
parity_t uart::GetParity()
{
return (parity_t)(GetLCR() & 0x38);
}
void uart::SetWordLength(int len)
{
SetLCR( (GetLCR() & 0xFC) | ((len - 5) & 3) );
}
int uart::GetWordLength()
{
return (GetLCR() & 3) + 5;
}
void uart::SetStopBits(int num)
{
SetLCR( (GetLCR() & 0xFB) | ((num == 1) ? 0 : 4) );
}
int uart::GetStopBits()
{
return (GetLCR() & 4) ? 1 : 2;
}
void uart::SetBreak()
{
SetLCR(GetLCR() | 64);
}
void uart::StopBreak()
{
SetLCR(GetLCR() & (~64));
}
void uart::Pause(int msec)
{
// assumes the PC BIOS tick is 18.2 per second, or
// 55 msec per tick.
// DO NOT call this from an interrupt driver that uses the clock!
union REGS regs;
regs.x.ax = 0;
int86(0x1A, ®s, ®s);
int startcount = regs.x.dx;
int endcount = startcount + (msec / 55);
int i = startcount;
while(i < endcount && i >= startcount)
{
regs.x.ax = 0;
int86(0x1A, ®s, ®s);
i = regs.x.dx;
}
}
void uart::Break(int msec)
{
// assumes the PC BIOS tick is 18.2 per second, or
// 55 msec per tick.
// DO NOT call this from an interrupt driver that uses the clock!
SetBreak();
Pause(msec);
StopBreak();
}
void uart::SetCTS(boolean bit)
{
SetMSR( (bit) ? (GetMSR() | 16) : (GetMSR() & (~16)) );
}
void uart::SetDSR(boolean bit)
{
SetMSR( (bit) ? (GetMSR() | 32) : (GetMSR() & (~32)) );
}
boolean uart::CarrierPresent()
{
// actually tests RLSD, bit 7 of MSR.
return (GetMSR() & 128) ? true : false;
}
void uart::SetDTR(boolean bit)
{
SetMCR( (bit) ? (GetMCR() | 1) : (GetMCR() & (~1)) );
}
boolean uart::GetDTR()
{
return (GetMCR() & 1) ? true : false;
}
com_interrupt_t uart::GetIntrType()
{
int type = (int)GetIIR() & 0xFF;
if(type & 1)
return NONE_PENDING;
int r;
switch(type)
{
case 0:
r = GetMSR();
if(r & 4)
return RING;
else if (r & 128)
return CARRIER;
else
return NO_CARRIER;
case 2:
r = GetLSR();
if(r & 32) // THRE
return TRANSMIT_READY;
else
return TRANSMIT_FALSE_ALARM;
case 4:
return RECEIVE_READY;
case 6:
r = GetLSR();
if(r & 2) //
return OVERRUN_ERROR;
else if(r & 4)
return PARITY_ERROR;
else if(r & 8)
return FRAMING_ERROR;
else if(r & 16)
return BREAK_RECEIVED;
else
return UNKNOWN_ERROR;
default :
return UNKNOWN_ERROR;
}
}
int uart::GetChar()
{
// note: for this method to work, SetLCR_DLAB(false) must be called.
return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
}
void uart:: SendChar(char ch)
{
// note: for this method to work, SetLCR_DLAB(false) must be called.
// this method works only if there is room in the transmit register.
outportb(THR(), ch);
}
void uart::TransmitChar(char ch)
{
// similar to last one -- allows other to be overloaded separately
outportb(THR(), ch);
}
int uart::ReceiveChar()
{
// similar to GetChar() -- allows other to be overloaded separately
// note: for this method to work, SetLCR_DLAB(false) must be called.
return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
}