home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / C / COMM.ZIP / COMM.C next >
Encoding:
C/C++ Source or Header  |  1990-04-17  |  6.1 KB  |  249 lines

  1. /*
  2.  *    comm.c
  3.  *
  4.  *    These functions perform serial I/O action on IBM PC
  5.  *    Public Domain (p) By Pete Gontier, for Turbo-C
  6.  */
  7.  
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <time.h>
  11.  
  12. #include "comm.h"
  13.  
  14. /* Globals */
  15.  
  16. static void interrupt (far *oldvec)();
  17. static uint    intv;        /* interrupt number to usurp */
  18.  
  19. static int
  20.     dat8250,        /* 8250 data register */
  21.     stat8250,        /* 8250 line-status register */
  22.     com8250,        /* 8250 line-control register */
  23.     c_in_buf = 0,        /* count of characters received */
  24.     xoffpt,            /* amount of buffer that forces XOFF */
  25.     xonpt,            /* amount of buffer that unXOFFs */
  26.     xonxoff = 0,        /* auto xon/xoff support flag */
  27.     xofsnt  = 0,        /* XOFF transmitted flag */
  28.     xofrcv  = 0;        /* XOFF received flag */
  29.  
  30. static char
  31.     en8259,            /* 8259 IRQ enable mask */
  32.     dis8259,        /* 8259 IRQ disable mask */
  33.     buffer[CBS],        /* Communications circular buffer */
  34.     *inptr = buffer,    /* input address of circular buffer */
  35.     *outptr = buffer;    /* output address of circular buffer */
  36.  
  37. /* Functions */
  38.  
  39. void interrupt serint()
  40. {
  41.     *inptr++ = inportb(dat8250);    /* Store character in buffer */
  42.     c_in_buf++;            /* and increment count */
  43.  
  44.     if (xonxoff)  {            /* if xon/xoff auto-support is on */
  45.         if (c_in_buf > xoffpt && !xofsnt)  {
  46.  
  47.             /* buffer nearly full */
  48.  
  49.             comm_putc(XOFF);    /* send an XOFF */
  50.             xofsnt = 1;        /* and say so */
  51.         }
  52.     }
  53.  
  54.     disable();            /* ints off for ptr change */
  55.     if (inptr == &buffer[CBS])    /* wrap buffer input pointer if end */
  56.         inptr = buffer;
  57.  
  58.     enable();
  59.     outportb(0x20, 0x20);        /* Generic EOI to 8259 */
  60. }
  61.  
  62. /* installs comm interrupts */
  63.  
  64. int comm_open(portid, speed)
  65. int    portid;
  66. uint    speed;
  67. {
  68.     uint    be = biosequip();    /* to get # installed serial ports */
  69.  
  70.     be <<= 4;            /* shift-wrap high bits off */
  71.     be >>= 13;            /* shift down to low bits */
  72.  
  73.     if (be >= portid)  {
  74.         if (portid == 1)  {
  75.             dat8250  = MDMDAT1;
  76.             stat8250 = MDMSTS1;
  77.             com8250  = MDMCOM1;
  78.             dis8259  = MDMINTC;
  79.             en8259   = MDMINTO;
  80.             intv     = MDMINTV;
  81.         }
  82.         else if (portid == 2)  {
  83.             dat8250  = MDMDAT2;
  84.             stat8250 = MDMSTS2;
  85.             com8250  = MDMCOM2;
  86.             dis8259  = MDINTC2;
  87.             en8259   = MDINTO2;
  88.             intv     = MDINTV2;
  89.         }
  90.         else
  91.             return(0);
  92.  
  93.         dobaud(speed);        /* set baud */
  94.  
  95.         inptr = outptr = buffer;  /* set circular buffer values */
  96.         c_in_buf = 0;
  97.  
  98.         oldvec = getvect(intv);    /* Save old int vector */
  99.         setvect(intv, serint);    /* Set up SERINT as com ISR */
  100.  
  101.         outportb(com8250, 0x03); /* 8 bits no parity, 1 stop */
  102.         outportb(com8250+1, 0x0B); /* Assert OUT2, RTS, and DTR */
  103.  
  104.         inportb(dat8250);
  105.         outportb(dat8250+1, 0x01); /* Receiver-Data-Ready int */
  106.  
  107.         /* Enable 8259 interrupts */
  108.  
  109.         outportb(INTCONT, en8259 & inportb(INTCONT));
  110.  
  111.         xoffpt = CBS / 50 * 49;    /* chars in buff to send XOFF */
  112.         xonpt  = CBS - xoffpt;    /* chars in buff to send XON */
  113.     }
  114.     else
  115.         be = 0;
  116.  
  117.     return((int)be);
  118. }
  119.  
  120. static void dobaud(baudrate)
  121. uint    baudrate;
  122. {
  123.     uchar    portval, blo, bhi;
  124.  
  125.     switch (baudrate)  {    /* Baud rate LSB's and MSB's */
  126.     case 50:     bhi = 0x9;  blo = 0x00;  break;
  127.     case 75:     bhi = 0x6;  blo = 0x00;  break;
  128.     case 110:    bhi = 0x4;  blo = 0x17;  break;
  129.     case 150:    bhi = 0x3;  blo = 0x00;  break;
  130.     case 300:    bhi = 0x1;  blo = 0x80;  break;
  131.     case 600:    bhi = 0x0;  blo = 0xC0;  break;
  132.     case 1200:   bhi = 0x0;  blo = 0x60;  break;
  133.     case 1800:   bhi = 0x0;  blo = 0x40;  break;
  134.     case 2000:   bhi = 0x0;  blo = 0x3A;  break;
  135.     case 2400:   bhi = 0x0;  blo = 0x30;  break;
  136.     case 4800:   bhi = 0x0;  blo = 0x18;  break;
  137.     case 9600:   bhi = 0x0;  blo = 0x0C;  break;
  138.     case 19200:  bhi = 0x0;  blo = 0x06;  break;
  139.     default:
  140.         return;
  141.     }
  142.  
  143.     portval = inportb(com8250);         /* read Line-Control Reg val */
  144.     outportb(com8250, portval | 0x80);  /* set high bit for baud init */
  145.     outportb(dat8250, blo);             /* Send LSB for baud rate */
  146.     outportb(dat8250+1, bhi);           /* Send MSB for baud rate */
  147.     outportb(com8250, portval);         /* Reset initial value at LCR */
  148. }
  149.  
  150. /* restore previous settings of 8259 */
  151.  
  152. void comm_close()
  153.     /* Disable com interrupt at 8259 */
  154.  
  155.     outportb(INTCONT, dis8259 | inportb(INTCONT));
  156.     setvect(intv, oldvec);    /* Reset original interrupt vector */
  157. }
  158.  
  159. /* returns # characters available in buffer */
  160.  
  161. int comm_avail()
  162. {                        
  163.     return(c_in_buf);
  164. }
  165.  
  166. /* send a char out port */
  167.  
  168. void comm_putc(c)
  169. uchar    c;
  170. {
  171.     while ((inportb(stat8250) & 0x20) == 0)
  172.         ;        /* Wait until transmitter is ready */
  173.  
  174.     outportb(dat8250, c);    /* then send it */
  175. }
  176.  
  177. /* get a char from buffer */
  178.  
  179. int comm_getc()
  180. {                       
  181.     register char    *ptr;
  182.     int        c;
  183.  
  184.     if (c_in_buf < xonpt && xofsnt)  {    /* Check if we need to send */
  185.         xofsnt = 0;            /* an XON to the host after */
  186.         comm_putc(XON);            /* we had to send an XOFF */
  187.     }
  188.  
  189.     while (c_in_buf == 0)            /* If character not ready */
  190.         ;                /* then wait til one is   */
  191.  
  192.     ptr = outptr;
  193.     c = *ptr++;        /* Get next character in circular buff */
  194.  
  195.     if (ptr == &buffer[CBS])    /* Check for end of circular buffer */
  196.         ptr = buffer;        /* start from bottom of buff */
  197.  
  198.     disable();        /* no interrupts during pointer manips */
  199.     outptr = ptr;        /* set character output pointer */
  200.     c_in_buf--;        /* and decrement the character count */
  201.     enable();        /* then allow interrupts to continue */
  202.  
  203.     return(c);        /* Return the character */
  204. }
  205.  
  206. /* flush all chars out of buffer */
  207.  
  208. void comm_flush()
  209. {
  210.     if (xofsnt)  {        /* Check if XON needs to be sent */
  211.         xofsnt = 0;
  212.         comm_putc(XON);
  213.     }
  214.  
  215.     disable();        /* no interrupts during pointer manips */
  216.     inptr = outptr = buffer; /* reset buffer pointers */
  217.     c_in_buf = 0;        /* and indicate no chars received */
  218.     enable();
  219. }
  220.  
  221. /*
  222.  *    data read (dread), read data from the circular buffer
  223.  */
  224.  
  225. int dread(buffer, wanted, seconds)
  226. uchar    *buffer;
  227. int    wanted, seconds;
  228. {
  229.     register int    i;
  230.     long        start;
  231.     int        pending, elapsed;
  232.  
  233.     start = time((long *)NULL);
  234.     for (;;)  {
  235.         pending = comm_avail();
  236.         if (pending >= wanted)  {    /* got enough in the buffer? */
  237.             for (i = 0; i < wanted; i++)
  238.                 *buffer++ = comm_getc();
  239.             return TRUE;
  240.         } else  {
  241.             elapsed = time((long *)NULL) - start;
  242.  
  243.             if (elapsed >= seconds)
  244.                 return FALSE;
  245.         }
  246.     }
  247. }
  248.