/* From CompuServe's BPROGB Borland Int'l forum * * #: 11879 S4/Turbo C * 02-Jun-88 18:54:50 * Sb: #11817-VT100 * Fm: Jerry Joplin 70441,2627 * To: Pete Gontier 72261,1754 (X) * * Pete, here are the communication ISR's I've been using. Hope these * don't overflow the message data base for BPROGB. :-) * I think all is included to set up COM1/COM2 for receiver interrupts. * * Also, these are straight ports from routines in MSKERMIT 2.30 and CKERMIT * for UNIX, which are public domain but copyrighted (c) by Columbia * University. */ /* Last modification, to support other compiler(s): * Pete Gontier, July 20th, 1988 * This code is no longer portable to the UNIX systems mentioned. * The function names were in accordance with the TT teletype conventions, * and I couldn't stand for it. So sue me. */ /* Modified by Paul Guertin, Oct. 6, 1994 * Added longjmps, removed debug code, changed dobaud to report errors. * Dec. 4 1995: changed "be" from int to unsigned in comm_open() */ #include #define TCICOMM /* avoid extern declaration in... */ #include "comm.h" /* comm prototypes */ /** macros for absolute data ************************************************/ #define MDMDAT1 0x03F8 /* Address of modem port 1 data */ #define MDMSTS1 0x03FD /* Address of modem port 1 status */ #define MDMCOM1 0x03FB /* Address of modem port 1 command */ #define MDMDAT2 0x02F8 /* Address of modem port 2 data */ #define MDMSTS2 0x02FD /* Address of modem port 2 status */ #define MDMCOM2 0x02FB /* Address of modem port 2 command */ #define MDMINTV 0x000C /* Com 1 interrupt vector */ #define MDINTV2 0x000B /* Com 2 interrupt vector */ #define MDMINTO 0x0EF /* Mask to enable IRQ3 for port 1 */ #define MDINTO2 0x0F7 /* Mask to enable IRQ4 for port 2 */ #define MDMINTC 0x010 /* Mask to Disable IRQ4 for port 1 */ #define MDINTC2 0x008 /* Mask to Disable IRQ3 for port 2 */ #define INTCONT 0x0021 /* 8259 interrupt controller ICW2-3 */ #define INTCON1 0x0020 /* Address of 8259 ICW1 */ #define CBS 5000 /* Communications port buffer size */ #define XOFF 0x13 /* XON/XOFF */ #define XON 0x11 /** globals not externally accessible ***************************************/ static int dat8250; /* 8250 data register */ static int stat8250; /* 8250 line-status register */ static int com8250; /* 8250 line-control register */ static char en8259; /* 8259 IRQ enable mask */ static char dis8259; /* 8259 IRQ disable mask */ static unsigned int intv; /* interrupt number to usurp */ static char buffer[CBS]; /* Communications circular buffer */ static char *inptr; /* input address of circular buffer */ static char *outptr; /* output address of circular buffer */ static int c_in_buf = 0; /* count of characters received */ static int xoffpt; /* amount of buffer that forces XOFF */ static int xonpt; /* amount of buffer that unXOFFs */ static void interrupt ( far *oldvec ) ( ); /* vector of previous comm interrupt */ int xonxoff = 0; /* auto xon/xoff support flag */ int xofsnt = 0; /* XOFF transmitted flag */ int xofrcv = 0; /* XOFF received flag */ void interrupt serint ( void ) { /* ISR to receive character */ *inptr++ = inportb ( dat8250 ); /* Store character in buffer */ c_in_buf++; /* and increment count */ if ( xonxoff ) { /* if xon/xoff auto-support is on */ if ( c_in_buf > xoffpt && ! xofsnt ) { /* then if buf nearly full */ comm_putc ( XOFF ); /* send an XOFF */ xofsnt = 1; /* and say so */ } } disable ( ); /* ints off for ptr change */ if ( inptr == &buffer[CBS] ) /* Set buffer input pointer */ inptr = buffer; enable ( ); outportb ( 0x20, 0x20 ); /* Generic EOI to 8259 */ } void comm_close ( void ) { /* restore previous settings of 8259 */ outportb ( INTCONT, dis8259 | inportb ( INTCONT ) ); /* Disable com interrupt at 8259 */ setvect ( intv, oldvec ); /* Reset original interrupt vector */ } int dobaud ( unsigned int baudrate ) { /* parses baud integer to mask, * re-inits port accordingly */ unsigned char portval; unsigned char blo, bhi; switch ( baudrate ) { /* Baud rate LSB's and MSB's */ /* case 50: bhi = 0x9; blo = 0x00; break; */ /* case 75: bhi = 0x6; blo = 0x00; break; */ /* case 110: bhi = 0x4; blo = 0x17; break; */ /* case 150: bhi = 0x3; blo = 0x00; break; */ case 300: bhi = 0x1; blo = 0x80; break; /* case 600: bhi = 0x0; blo = 0xC0; break; */ case 1200: bhi = 0x0; blo = 0x60; break; /* case 1800: bhi = 0x0; blo = 0x40; break; */ /* case 2000: bhi = 0x0; blo = 0x3A; break; */ case 2400: bhi = 0x0; blo = 0x30; break; case 4800: bhi = 0x0; blo = 0x18; break; case 9600: bhi = 0x0; blo = 0x0C; break; case 19200: bhi = 0x0; blo = 0x06; break; default: return -1; } portval = inportb ( com8250 ); /* read Line-Control Reg val */ outportb ( com8250, portval | 0x80 ); /* set high bit for baud init */ outportb ( dat8250, blo ); /* Send LSB for baud rate */ outportb ( dat8250 + 1, bhi ); /* Send MSB for baud rate */ outportb ( com8250, portval ); /* Reset initial value at LCR */ return 0; } /*************************************************************************/ #include #include #include extern jmp_buf beginning; /* installs comm interrupts */ int comm_open ( int portid, unsigned speed ) { unsigned be = biosequip ( ); /* to get # installed serial ports */ be <<= 4; /* shift-wrap high bits off */ be >>= 13; /* shift down to low bits */ if ( be >= portid ) { if ( portid == 1 ) { dat8250 = MDMDAT1; stat8250 = MDMSTS1; com8250 = MDMCOM1; dis8259 = MDMINTC; en8259 = MDMINTO; intv = MDMINTV; } else if ( portid == 2 ) { dat8250 = MDMDAT2; stat8250 = MDMSTS2; com8250 = MDMCOM2; dis8259 = MDINTC2; en8259 = MDINTO2; intv = MDINTV2; } else return ( 0 ); if( dobaud ( speed ) ) /* set baud */ return 0; inptr = outptr = buffer; /* set circular buffer values */ c_in_buf = 0; oldvec = getvect ( intv ); /* Save old int vector */ setvect ( intv, serint ); /* Set up SERINT as com ISR */ outportb ( com8250, 0x3 ); /* 8 bits no parity */ outportb ( com8250 + 1, 0xb ); /* Assert OUT2, RTS, and DTR */ inportb ( dat8250 ); outportb ( dat8250 + 1, 0x1 ); /* Receiver-Data-Ready int */ outportb ( INTCONT, en8259 & inportb ( INTCONT ) ); /* Enable 8259 interrupts */ xoffpt = CBS / 50 * 49; /* chars in buff to send XOFF */ xonpt = CBS - xoffpt; /* chars in buff to send XON */ } else be = 0; return ( be ); } int comm_avail ( ) /* returns # characters available in buffer */ { return ( c_in_buf ); } void comm_putc ( unsigned char c ) /* sends char out port */ { while ( ( inportb ( stat8250 ) & 0x20 ) == 0 ) if( kbhit() && getch() == 0x1B ) longjmp( beginning, 1 ); /* Wait til transmitter is ready */ outportb ( dat8250, c ); /* then send it */ } int comm_getc ( ) /* gets char from buffer */ { int c; register char * ptr; if ( c_in_buf < xonpt && xofsnt ) { /* Check if we need to send */ xofsnt = 0; /* an XON to the host after */ comm_putc ( XON ); /* we had to send an XOFF */ } while ( c_in_buf == 0 ) /* If character not ready */ if( kbhit() && getch() == 0x1B ) longjmp( beginning, 2 ); /* then wait til one is */ ptr = outptr; c = *ptr++; /* Get next character in circular buff */ if ( ptr == &buffer[CBS] ) /* Check for end of circular buffer */ ptr = buffer; /* start from bottom of buff */ disable ( ); /* no interrupts during pointer manips */ outptr = ptr; /* set character output pointer */ c_in_buf--; /* and decrement the character count */ enable ( ); /* then allow interrupts to continue */ return ( c ); /* Return the character */} void comm_flush ( ) /* flushes all chars out of buffer */ { if ( xofsnt ) { /* Check if XON needs to be sent */ xofsnt = 0; comm_putc ( XON ); } disable ( ); /* no interrupts during pointer manips */ inptr = outptr = buffer; /* reset buffer pointers */ c_in_buf = 0; /* and indicate no chars received */ enable ( ); }