Listing 2
/* ---------- uartdvr.c ---------- */
/*      Uart Driver Program  for NS16550
	written by: Charles B. Allison, ATS
	Last Change: 5-8-92 09:30           */
/* *********************************** */
#include <conio.h>
#include <stdio.h>
#include <dos.h>
#include <bios.h>
#include "serialc.h"
#pragma intrinsic (inp,outp/*,enable,disable*/)
/* ----------- defines ------------- */
#define RBSIZE 4100
#define TBSIZE 3256
#define TESTFIFO 1
#pragma pack(1)
static COM com_ch;
CQUEUE tx;            /* transmit queue ptrs */
char tbuffer[TBSIZE];
CQUEUE rx;           /* rx queue ptrs */
char rbuffer[RBSIZE];
/* ------- serial port parameters -------- */
int port_addr[6] = {0,COM1,COM2,COM3,COM4,0 };
int port_int[6] = {0,IRQ4,IRQ3,IRQ4,IRQ3,0 };
/* ----------- prototypes ---------------- */
static void interrupt far comint(void); /*int rtne */
/* prototypes for interrupt sub functions */
static void irs232(int base); /* ctl line change */
static void itxrdy(int base); /* tx intr 1 */
static void irxrdy(int base); /* rx intr 2 */
static void  iserr(int base); /* break or error 3 */
char ser_mode(int sel,long baud,char chr_len,
		      char num_stops,char parity);
void init_com_bufs(void);
int ser_read(char *destbf,int rcount);
int ser_write(char *srcbf,int rcount);
int ser_stat(COM_STAT* st);
#ifdef TESTFIFO
static int maxfifo=1,fifocnt=0;
#endif
/* ************Communications Interrupt************ */
static void interrupt far comint(void)
{
int intflag;
int base = com_ch.abase;
static void (*isr[4]) (int base) =  /*array of
		pointers to interrupt type handlers */
       {                 
       irs232,  /* rs232 input change IIR = 0 */
       itxrdy,   /* transmit interrupt = 1 */
       irxrdy,   /* receive interrupt = 2 */
       iserr,    /* break or error = 3 */
       };
#ifdef TESTFIFO
fifocnt = 0;
#endif
while( ((intflag = inp(INTID) & 0x07 ) & 0x01) == 0 )
    {              /* loop thru all pending 
			interrupts (bit 1 = 0) */
      intflag >>= 1; /* get bits 0x02 and 0x04
		       bit 3 for ns16550 don't care*/
      (*isr[intflag]) (com_ch.abase);
			/* call routine handler */
    }  /* end of while */
    outp(PIC00,EOI);    /* eoi clear int mask for 
			 PIC 0 1st int  */

#ifdef TESTFIFO
if(fifocnt>maxfifo) maxfifo = fifocnt;
#endif

}
/* ** Communications Interrupt subfunctions ** */

/* -------- rs232 changes --------- */
static void irs232(int base)   
		/* rs232 input change IIR = 0 */
{
int tmp;
com_ch.modem =(char) inp(MODMSTAT);
		  /* get modem flags dcts,ddsr,
			dri,dcd cts,dsr,ri,cd */
}
/* ********************************** */
void itxrdy(int base)  /* transmit interrupt = 1 */
{
int cnt = com_ch.fifo;  /* get fifo size */
if(tx.buff_cnt)
 {
  while((cnt--) && (tx.buff_cnt))
   {
     tx.buff_cnt--;
     outp(TXD,*tx.next_out);
     if((++tx.next_out) >= tx.end_que)
	tx.next_out = tx.buffer;
   } /* end of while */
 } /* end of if */
}
/* *********************************** */
void irxrdy(int base)   /* receive interrupt = 2 */
{
com_ch.line|= (char)inp(LINESTAT) & 0x9e; /* error
				flags oe pe fe */
*rx.next_in = com_ch.datin =(char) inp(RXD);
if(rx.buff_cnt < RBSIZE)
  {
  rx.buff_cnt++; /* another char to buffer cnt */
  } else {
  rx.overflow++; /* rx buffer overflow error */
  }
if((++rx.next_in) >= rx.end_que )
	rx.next_in = rx.buffer; /* set to begin que*/
#ifdef TESTFIFO
fifocnt++;
#endif

}
/* -----------line errors -------------- */
static void iserr(int base) /* errors IIR = 3 */
{
com_ch.line |=(char) inp(LINESTAT) & 0x9e;
}
/* ********************* */
/* ------------ set mode ------------- */
char ser_mode(int sel,long baud,char chr_len,
		      char num_stops,char parity)
{
char tmp,line;
int divisor;
unsigned base = port_addr[sel];
com_ch.abase = base;
com_ch.line = (chr_len-5)|((num_stops-1) <<2); 
	       /* now add stopbits*/
tmp = 0;
switch(parity)
  {
    case 'S':
    tmp++;
    case 'M':
    tmp++;
    case 'E':
    tmp++;
    case 'O':
    tmp++;
    case 'N':
    default :
    break;
  }        /* end of switch */
if(tmp) tmp = ((--tmp << 1) | 1) << 3;  
	       /* lsb set if any parity*/
com_ch.line |= tmp;  /* put in parity */
com_ch.divisor = (unsigned)(MAX_BAUD/baud);
_disable();
outp(FIFOC,0x07); /* enable FIFOs, reset, trigger
		    on 1 byte in receive buffer */
if((inp(INTID) & 0xf0) == 0xc0)
  {
   com_ch.fifo = 16; /*yes UART is NS16550*/
  } else {
   com_ch.fifo = 1;
  }
outp(LINECTL,(DLAB|com_ch.line));
		  /* enable divisor latch */
outp(DIVLSB,(char)((com_ch.divisor) & 255));
outp(DIVMSB,(char)((com_ch.divisor) >> 8));
outp(LINECTL,com_ch.line); /* set line */
outp(MODEMCTL,(inp(MODEMCTL))| DTR| GPOUT2);
inp(RXD);     /* clear out existing ints */
inp(INTID);
inp(LINESTAT);
inp(MODMSTAT);
_enable();
return com_ch.line;
}
static void (interrupt far *oldint)(void);
static char irqmask;
/* ********* set_int ******* */
void set_int(int sel)
{
unsigned base = port_addr[sel];
oldint = _dos_getvect(IRQ_OFF+port_int[sel]);
_dos_setvect((IRQ_OFF+port_int[sel]),comint);
irqmask = (char)( inp(PIC01) & (1<<port_int[sel]));
_disable();
outp(PIC01,(inp(PIC01)& ~((char)(1<<port_int[sel]))));
		       /* unmask int c */
outp(INTEN,0x0f);   /* enable all sources */
inp(RXD);  /* clear out any existing intreqs */
inp(INTID);
inp(LINESTAT);
inp(MODMSTAT);
outp(PIC00,EOI); /*clear any 8259A request*/
_enable();
}
/* ********* clr_int ******* */
void clr_int(int sel)
{
unsigned base = port_addr[sel];
outp(MODEMCTL,0x00); /* clear DTR, card interrupts */
outp(PIC01,(inp(PIC01)| (char) irqmask ) );
_dos_setvect((IRQ_OFF+port_int[sel]),oldint);
}
/* -------- init_com_bufs -------- */
void init_com_bufs(void)
{
/* setup and clear out circular buffers */
tx.buffer = tbuffer;    /* transmit buffer */
tx.end_que = &tbuffer[TBSIZE];
tx.next_out =tx.next_in = tbuffer;/* tx buf ptrs */
tx.buff_cnt = rx.buff_cnt = 0; /* num chars in bufs */
rx.buffer = rbuffer;    /* receive buffer */
rx.end_que = &rbuffer[RBSIZE];
rx.next_out = rx.next_in = rbuffer; /* rx buf ptrs */
rx.overflow = 0; /* receive buffer over flow*/
}
/* ---------- read rx buffer ---------- */
int ser_read(char *destbf,int rcount)
{
int cnt_read = 0;
int tmp_buf_cnt = rx.buff_cnt;
while( (rcount-- ) && (tmp_buf_cnt--))
 {
  *destbf++ = *rx.next_out++;
if((rx.next_out) >= rx.end_que )
	rx.next_out = rx.buffer; /* set to begin que*/
  
  cnt_read++;
 }
_disable(); /* must not risk change in intrpt too */
rx.buff_cnt -= cnt_read; /* adjust buffer*/
_enable();
return cnt_read;
}
/* ---------- write tx buffer ---------- */
int ser_write(char *srcbuf,int tcount)
{
int wrt_cnt = 0;  /* number written */
int tmp_buf_cnt = tx.buff_cnt;
int base = com_ch.abase;
while((tcount--) && ((tmp_buf_cnt++) < TBSIZE) )
  {
   *tx.next_in++ = *srcbuf++;
   if((tx.next_in) >= tx.end_que)
	tx.next_in = tx.buffer;
   
   wrt_cnt++;
  }
_disable(); /* must not risk change in intrpt too */
tx.buff_cnt += wrt_cnt;
if(inp(LINESTAT) & 0x60) itxrdy(com_ch.abase);
_enable();
return wrt_cnt;
}
/* ---------- get status ---------- */
int ser_stat(COM_STAT* st)
{
st->line = com_ch.line;
st->modem = com_ch.modem;
st->inbufc = rx.buff_cnt;
st->outbufc = tx.buff_cnt;
st->overflow =  rx.overflow;
rx.overflow = com_ch.line = 0;/* clear errors */
return rx.buff_cnt;
}
/* --------- set modem controls ----------- */
int ser_con(int states,int masks)
{
int base = com_ch.abase;
int tmp = 0;
/* masks enables changes for bits
GPOUT2  should be high, - enables card interrupts
DTR, RTS, user modifiable
LOOPS, GPOUT1 should be low for normal operation */
outp(MODEMCTL,tmp =((inp(MODEMCTL) & ~masks) |
				 (states & masks)));
return tmp;
}
#define LINEL 3128
char linebuf[LINEL + 1];  /* output line buffer */
char inbuf[LINEL+1];
/* set PORT = COM2 */
#define PORT 2
/* ************* main ******************* */
/* dumb terminal example use */
int main(void)
{
char tmp;
int dline = 0,itmp,incnt,outcnt=0;
COM_STAT cst;
printf("FIFO Usart Example\n ESCape to exit \n");
init_com_bufs();  /* initialize buffers */
ser_mode(PORT,115200L,8,1,'N');
set_int(PORT);           /* setup int vectors */
itmp =GPOUT2+DTR+RTS;  /* set line control reg. */
ser_con(itmp,(itmp+GPOUT1)| LOOPS);
for(;;)     /* main loop */
  {
  if(_bios_keybrd(_KEYBRD_READY))
    {        /* output a line at a time */
     tmp = (char)_bios_keybrd(_KEYBRD_READ);
     if(tmp != 0)
      {
       putch(tmp);
       if(tmp == '\x1b') break; /*break on ESC */
       if((tmp == '\r') || (outcnt >= (LINEL-1) ))
	 {
	  printf("\n");
	  linebuf[outcnt++] = '\n';
	  linebuf[outcnt] = '\0';
	  ser_write(linebuf,outcnt);
	  outcnt = 0;
	 } else {
	  linebuf[outcnt++] = tmp;
	  linebuf[outcnt] = '\0';
	 }
       }
    }
  if( (incnt = ser_stat(&cst)) )
    {
     itmp = (incnt < LINEL)? incnt:LINEL;
     ser_read(inbuf,itmp);
     inbuf[itmp] = '\0';
     printf("%s",inbuf);
     inbuf[0] = '\0';
     dline = 0;
     incnt = 0;
    }
  } /*end of loop */
/* clean up for exit */
clr_int(PORT);  /* restore int vector */
#ifdef TESTFIFO
printf("\nfifo buffer size = %d\n \
 max char count (in a single interrupt) = %d\n"
			       ,com_ch.fifo,maxfifo);
#endif
exit (com_ch.fifo);
}/* end of main */



able FIFOs, reset, tr

