home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
D!Zone (Collector's Edition)
/
D_ZONE_CD.ISO
/
programs
/
editors
/
serial28
/
source.exe
/
PORT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-08
|
8KB
|
424 lines
// port.c
#include "doomnet.h"
#include "sersetup.h"
void jump_start( void );
void interrupt isr_8250 (void);
void interrupt isr_16550 (void);
union REGS regs;
struct SREGS sregs;
que_t inque, outque;
int uart; // io address
enum {UART_8250, UART_16550} uart_type;
int irq;
int modem_status = -1;
int line_status = -1;
void interrupt (*oldirqvect) (void);
int irqintnum;
int comport;
extern unsigned char bauddivl, usehardhand;
extern int useextirq;
extern int useextport;
int accessTX;
int accessRX;
int accessIIR;
int accessLCR;
int accessMCR;
int accessLSR;
int accessMSR;
long intRX;
long intTX;
/*
==============
=
= GetUart
=
==============
*/
void GetUart (void)
{
char far *system_data;
static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8};
static int ISA_IRQs[] = {4,3,4,3};
static int MCA_uarts[] = {0x03f8,0x02f8,0x3220,0x3228};
static int MCA_IRQs[] = {4,3,3,3};
int p;
if (CheckParm ("-com2"))
comport = 2;
else if (CheckParm ("-com3"))
comport = 3;
else if (CheckParm ("-com4"))
comport = 4;
else
comport = 1;
regs.h.ah = 0xc0;
int86x( 0x15, ®s, ®s, &sregs );
if ( regs.x.cflag )
{
irq = ISA_IRQs[ comport-1 ];
uart = ISA_uarts[ comport-1 ];
return;
}
system_data = ( char far *) ( ( (long) sregs.es << 16 ) + regs.x.bx );
if ( system_data[ 5 ] & 0x02 )
{
irq = MCA_IRQs[ comport-1 ];
uart = MCA_uarts[ comport-1 ];
}
else
{
irq = ISA_IRQs[ comport-1 ];
uart = ISA_uarts[ comport-1 ];
}
p = CheckParm ("-port");
if (p)
scanf (_argv[p+1],"0x%x",&uart);
p = CheckParm ("-irq");
if (p)
scanf (_argv[p+1],"%i",&irq);
if (useextirq)
irq=useextirq;
if (useextport)
uart=useextport;
printf ("Looking for UART at port 0x%x, irq %i\n",uart,irq);
}
/*
===============
=
= InitPort
=
===============
*/
void InitPort (void)
{
int mcr;
int temp;
//
// find the irq and io address of the port
//
GetUart ();
accessTX=uart+TRANSMIT_HOLDING_REGISTER;
accessRX=uart+RECEIVE_BUFFER_REGISTER;
accessIIR=uart+INTERRUPT_ID_REGISTER;
accessLCR=uart+LINE_CONTROL_REGISTER;
accessMCR=uart+MODEM_CONTROL_REGISTER;
accessLSR=uart+LINE_STATUS_REGISTER;
accessMSR=uart+MODEM_STATUS_REGISTER;
//
// init com port settings
//
regs.x.ax = 0xf3; //f3= 9600 n 8 1
regs.x.dx = comport - 1;
int86 (0x14, ®s, ®s);
// Tony's add ons.
// We should be setting the baud rate to 38400 and raising DTR
// set speed to 38400
OUTPUT(uart + LINE_CONTROL_REGISTER,
INPUT(uart + LINE_CONTROL_REGISTER)|LCR_DLAB);
OUTPUT(uart + DIVISOR_LATCH_LOW,bauddivl);
OUTPUT(uart + DIVISOR_LATCH_HIGH,0x00);
OUTPUT(uart + LINE_CONTROL_REGISTER,
INPUT(uart + LINE_CONTROL_REGISTER)&~LCR_DLAB);
OUTPUT(uart + LINE_CONTROL_REGISTER,0x03); //set 8N1
// set DTR & RTS
OUTPUT(uart + MODEM_CONTROL_REGISTER,
INPUT(uart + MODEM_CONTROL_REGISTER) | MCR_DTR | MCR_RTS);
//
// check for a 16550
//
OUTPUT( uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE + FCR_TRIGGER_14 );
temp = INPUT( uart + INTERRUPT_ID_REGISTER );
if ( ( temp & 0xf8 ) == 0xc0 )
{
uart_type = UART_16550;
printf ("UART is a 16550\n\n");
}
else
{
uart_type = UART_8250;
OUTPUT( uart + FIFO_CONTROL_REGISTER, 0 );
printf ("UART is an 8250\n\n");
}
//
// prepare for interrupts
//
outque.head=0;
outque.tail=0;
inque.head=0;
inque.tail=0;
intTX=0;
intRX=0;
OUTPUT( uart + INTERRUPT_ENABLE_REGISTER, 0 );
mcr = INPUT( uart + MODEM_CONTROL_REGISTER );
mcr |= MCR_OUT2;
mcr &= ~MCR_LOOPBACK;
OUTPUT( uart + MODEM_CONTROL_REGISTER, mcr );
INPUT( uart ); // Clear any pending interrupts
INPUT( uart + INTERRUPT_ID_REGISTER );
//
// hook the irq vector
//
irqintnum = irq + 8;
oldirqvect = getvect (irqintnum);
if (uart_type == UART_16550)
setvect (irqintnum,isr_16550);
else
setvect (irqintnum,isr_8250);
OUTPUT( 0x20 + 1, INPUT( 0x20 + 1 ) & ~(1<<irq) );
CLI();
// enable RX and TX interrupts at the uart
OUTPUT( uart + INTERRUPT_ENABLE_REGISTER,
IER_RX_DATA_READY + IER_TX_HOLDING_REGISTER_EMPTY);
// enable interrupts through the interrupt controller
OUTPUT( 0x20, 0xc2 );
// set DTR
OUTPUT( uart + MODEM_CONTROL_REGISTER
, INPUT( uart + MODEM_CONTROL_REGISTER ) | MCR_DTR);
STI();
}
/*
=============
=
= ShutdownPort
=
=============
*/
void ShutdownPort ( void )
{
OUTPUT( uart + INTERRUPT_ENABLE_REGISTER, 0 );
OUTPUT( uart + MODEM_CONTROL_REGISTER, 0 );
OUTPUT( 0x20 + 1, INPUT( 0x20 + 1 ) | (1<<irq) );
OUTPUT( uart + FIFO_CONTROL_REGISTER, 0 );
setvect (irqintnum,oldirqvect);
//
// init com port settings to defaults
//
regs.x.ax = 0xf3; //f3= 9600 n 8 1
regs.x.dx = comport - 1;
int86 (0x14, ®s, ®s);
}
int read_byte( void )
{
int c;
// Tony's code again, raise RTS if buffer half empty
if ((inque.head-inque.tail)<(QUESIZE/2))
OUTPUT( accessMCR,INPUT(accessMCR) | MCR_RTS);
if (inque.tail >= inque.head)
return -1;
c = inque.data[inque.tail&(QUESIZE-1)];
inque.tail++;
return c;
}
void write_byte( int c )
{
outque.data[outque.head&(QUESIZE-1)] = c;
outque.head++;
}
//==========================================================================
/*
==============
=
= isr_16550
=
==============
*/
void interrupt isr_16550(void)
{
int count;
while (1)
{
switch( INPUT( accessIIR ) & 7 )
{
//
// receive
//
case IIR_RX_DATA_READY_INTERRUPT :
//I_ColorBlack (0,63,0);
intRX++;
do
{
inque.data[(inque.head++)&(QUESIZE-1)] = INPUT(accessRX);
}
while (INPUT(accessLSR) & LSR_DATA_READY );
if (((outque.head-outque.tail)>(QUESIZE-1000))&&usehardhand)
OUTPUT(accessMCR,INPUT(accessMCR) & ~MCR_RTS);
break;
//
// transmit
//
case IIR_TX_HOLDING_REGISTER_INTERRUPT :
//I_ColorBlack (63,0,0);
if ((outque.tail < outque.head)&&
((INPUT(accessMSR)&MSR_CTS)||!usehardhand))
{
intTX++;
count = 16;
do
{
OUTPUT( accessTX, outque.data[(outque.tail++)&(QUESIZE-1)]);
} while (--count && outque.tail < outque.head);
}
break;
// not enabled
case IIR_MODEM_STATUS_INTERRUPT :
modem_status = INPUT(accessMSR);
break;
// not enabled
case IIR_LINE_STATUS_INTERRUPT :
line_status = INPUT( accessLSR );
break;
//
// done
//
default :
OUTPUT( 0x20, 0x20 );
return;
}
}
}
void interrupt isr_8250(void)
{
while (1)
{
switch( INPUT(accessIIR) & 7 )
{
//
// receive
//
case IIR_RX_DATA_READY_INTERRUPT :
intRX++;
inque.data[inque.head++&(QUESIZE-1)] = INPUT(accessRX);
if (((outque.head-outque.tail)>(QUESIZE-1000))&&usehardhand)
OUTPUT(accessMCR,INPUT(accessMCR) & ~MCR_RTS);
break;
//
// transmit
//
case IIR_TX_HOLDING_REGISTER_INTERRUPT :
if ((outque.tail < outque.head)&&
((INPUT(accessMSR)&MSR_CTS)||!usehardhand))
{
intTX++;
OUTPUT( accessTX, outque.data[(outque.tail++)&(QUESIZE-1)]);
}
break;
// not enabled
case IIR_MODEM_STATUS_INTERRUPT :
modem_status = INPUT( accessMSR );
break;
// not enabled
case IIR_LINE_STATUS_INTERRUPT :
line_status = INPUT( accessLSR );
break;
//
// done
//
default :
OUTPUT( 0x20, 0x20 );
return;
}
}
}
/*
===============
=
= jump_start
=
= Start up the transmition interrupts by sending the first char
===============
*/
void jump_start( void )
{
int c;
if (outque.tail < outque.head)
{
c = outque.data [outque.tail&(QUESIZE-1)];
outque.tail++;
OUTPUT( uart, c );
}
}