Category : C Source Code
Archive   : INTSER.ZIP
Filename : INTSER.C
Output of file : INTSER.C contained in archive : INTSER.ZIP
/* */
/* Minimal Function, All C interrupt serial routine */
/* */
/* Supports buffered input, output */
/* */
/* Charles McGuinness [76701,11] */
/* */
/* This code is donated to the public domain */
/* */
/************************************************************************/
#include
#include
#include
/************************************************************************/
/* Definitions of the 8250's registers */
/************************************************************************/
#define DataPort 0x3f8 /* Data register */
#define IER 0x3f9 /* Interrupt enable register */
#define IIR 0x3fa /* Interrupt ID register */
#define LCR 0x3fb /* Line control register */
#define MControl 0x3fc /* Modem control register */
#define LStatus 0x3fd /* Line Status */
#define MStatus 0x3fe /* Modem status */
#define IntControl 0x21 /* For 8259 interrupt controller */
#define EnableIRQ4 0xef /* Enable interrupt 4 */
#define DisableIRQ4 0x10 /* Disable interrupt 4 */
#define RS8259 0x20
#define EOI 0x20
#define TxReady 0x20 /* Transmit buffer empty */
/************************************************************************/
/* Definitions of the interrupt enable register */
/************************************************************************/
#define IER_RX 0x01 /* Enable Data Ready interrupts */
#define IER_TX 0x02 /* Enable Transmit Empty Interrupts */
#define IER_LS 0x04 /* Enable line status interrupts */
#define IER_MS 0x08 /* Enable modem status interrupts */
/************************************************************************/
/* Definitions of the interrupt ID register */
/************************************************************************/
#define IIR_IPending 0x01 /* Interrupt is pending */
#define IIR_Mask 0x06 /* Mask to get Interrupt type */
#define IIR_MS 0x00 /* Modem status interrupt */
#define IIR_TX 0x02 /* Transmit empty interrupt */
#define IIR_RX 0x04 /* Data available interrupt */
#define IIR_LS 0x06 /* Line status interrupt */
#define BUFSIZE 8192 /* How many characters in the buffer? */
#define XOFF_SIZE 7000 /* How full do we get before XOFFing */
#define XON_SIZE 1000 /* How empty to we get before XONing */
#define XOFF 19 /* value of the XOFF character */
#define XON 17 /* value of the XON character */
/*************************************************************************
Definitions for the input buffer. We make it a 'far' array so
as not to eat up valuable data space in the small and medium
models.
The buffers are simple circular buffers, where there is one pointer
to fill the buffer and another to empty it. A count variable
keeps track of the size of the buffer (although it could be determined
by computing (fill-empty)%BUFSIZE).
*************************************************************************/
static unsigned char far in_buf[BUFSIZE];
static int in_fill =0; /* Where to place the next char */
static int in_empty =0; /* Where to get the next char */
static int in_count =0; /* How much data is in buffer */
static int xoff_sent =0; /* Did we send an XOFF? */
/*************************************************************************
Definitions for the output buffer
*************************************************************************/
static unsigned char far out_buf[BUFSIZE];
static int out_fill =0;
static int out_empty =0;
static int out_count =0;
static int tx_off =1; /* These means the interrupts */
/* for the transmitter are now */
/* off (since we have nothing */
/* to send right now). */
/*************************************************************************
ser_int_icount: Return the number of bytes in the input
buffer. 0 means no data available.
*************************************************************************/
int ser_int_icount()
{
return(in_count);
}
/*************************************************************************
ser_int_ocount: Returns the number of bytes in the output
buffer. This information is useful if you
are uploading a large block of data and do
not want to hand this library data quicker
than it can be transmitted. E.g.,
while (more data)
{
while (ser_int_ocount())
;
send_data();
}
*************************************************************************/
int ser_int_ocount()
{
return(out_count);
}
/*************************************************************************
ser_int_ofree: Returns the amount of free space left in
the output buffer. Useful in preventing
data loss if you're sending a large block
of data. E.g.,
while (more_data)
{
while (ser_int_ofree() == 0)
;
send_data();
}
*************************************************************************/
int ser_int_ofree()
{
return(BUFSIZE-out_count);
}
/************************************************************************
ser_int_iflush: Throw away any data in the input buffer
************************************************************************/
void ser_int_iflush()
{
_disable();
/*****************************************/
in_fill = 0;
in_empty = 0;
in_count = 0;
/*****************************************/
_enable();
}
/************************************************************************
int_handler: This routine catches the serial port
interrupts.
************************************************************************/
static void interrupt far int_handler()
{
int ax;
static int send_now = 0;
/* While there is more work to do... */
while (0 == ((ax = inp(IIR)) & IIR_IPending))
{
switch (ax & IIR_Mask)
{
case IIR_RX: /* New data has arrived */
ax =inp(DataPort);
if (in_count != BUFSIZE)
{
in_buf[in_fill] = (unsigned char) ax;
in_fill = (in_fill+1) & (BUFSIZE-1);
in_count++;
/* Check for the buffer filling up... */
if ((in_count == XOFF_SIZE) && (!xoff_sent))
{
if (tx_off)
{
outp(DataPort,XOFF);
tx_off = 0;
}
else
{
send_now = XOFF;
}
xoff_sent = 1;
}
}
break;
case IIR_TX: /* Ready to transmit another */
if (send_now)
{
outp(DataPort,send_now);
send_now = 0;
}
else if (out_count)
{
outp(DataPort,out_buf[out_empty]);
out_empty = (out_empty+1) & (BUFSIZE-1);
out_count--;
}
else
{
/* Since we aren't feeding it another */
/* byte, it won't interrupt again */
tx_off = 1;
}
break;
default:
break;
}
}
outp(RS8259,EOI);
}
/************************************************************************
ser_int_init: Initialize the serial port handler.
Note that if you change the baud rate,
for example, you need to call this routine
again to restart the interrupts.
************************************************************************/
void ser_int_init()
{
register int ax;
register int i;
_disable();
_dos_setvect(0xc,int_handler);
_disable();
/*****************************************/
ax =inp(IntControl);
ax =ax & EnableIRQ4;
outp(IntControl,ax);
outp(IER,IER_RX | IER_TX);
for (i=0;i<6;i++)
inp(DataPort+i);
ax =inp(LCR);
ax =ax & 0x3f;
outp(LCR,ax);
outp(MControl,0xb);
outp(RS8259,EOI);
/*****************************************/
_enable();
}
/************************************************************************
ser_int_term: Turn off the interrrupts to make the world
safe for us to exit...
************************************************************************/
void ser_int_term()
{
/* Wait for all data in the buffer to be transmitted */
while (out_count)
{}
/* Wait for the UART to drain out */
while ((inp(LStatus) & 0x60) != 0x60)
{}
_disable();
/*****************************************/
outp(IntControl,inp(IntControl) & DisableIRQ4);
outp(LCR,inp(LCR) & 0x7f);
outp(IER,0);
outp(MControl,0);
/*****************************************/
_enable();
}
/************************************************************************
ser_int_putc: Transmit a character out the UART
************************************************************************/
void ser_int_putc(int c)
{
_disable();
/*****************************************/
if (tx_off)
{
outp(DataPort,c);
tx_off = 0;
}
else
{
if (out_count == BUFSIZE)
{
_enable();
/*****************************************/
while (out_count == BUFSIZE)
;
/*****************************************/
_disable();
}
out_buf[out_fill] = (unsigned char) c;
out_fill = (out_fill + 1) & (BUFSIZE-1);
out_count++;
}
/*****************************************/
_enable();
}
/************************************************************************
ser_int_getc: Get a character from the input buffer.
Returns character or -1 if no data available
/************************************************************************/
int ser_int_getc()
{
int b;
if (in_count == 0)
return(-1);
b =in_buf[in_empty];
in_empty = (in_empty+1) & (BUFSIZE-1);
_disable();
/*****************************************/
in_count--;
/*****************************************/
_enable();
if ((in_count == XON_SIZE) && xoff_sent)
{
ser_int_putc(XON);
xoff_sent = 0;
}
return(b);
}
/************************************************************************
ser_int_puts: Transmit a string of characters
/************************************************************************/
void ser_int_puts(char *s)
{
while (*s)
ser_int_putc(*s++);
}
/************************************************************************
ser_int_break: Raise BREAK for 200 ms, then turn it off
for 200 ms.
************************************************************************/
void ser_int_break()
{
int ax;
clock_t start, cur;
start =clock();
_disable();
ax =inp(LCR);
ax |= 0x40;
outp(LCR,ax);
_enable();
while (1)
{
cur =clock();
if ((cur-start) > (CLK_TCK/5))
break;
}
_disable();
ax =inp(LCR);
ax &= ~0x40;
outp(LCR,ax);
_enable();
start =clock();
while (1)
{
cur =clock();
if ((cur-start) > (CLK_TCK/5))
break;
}
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/