home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / I8250.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  27KB  |  998 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * 16550A support plus some statistics added mah@hpuviea.at 15/7/89
  5.  *
  6.  * CTS hardware flow control from dkstevens@ucdavis,
  7.  * additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
  8.  * Feb '91      RLSD line control reorganized by Bill_Simpson@um.cc.umich.edu
  9.  * Sep '91      All control signals reorganized by Bill Simpson
  10.  * Jan '92      Added force 16550 fifo command
  11.  *
  12.  * Mods by PA0GRI
  13.  * NRS flow control by WZ2B
  14.  */
  15.  
  16. /* #define ALL_INTS            /* enable processing all port interrupts */
  17.  
  18. #include <dos.h>
  19. #include "global.h"
  20. #include "mbuf.h"
  21. #include "proc.h"
  22. #include "iface.h"
  23. #include "i8250.h"
  24. #include "asy.h"
  25. #include "devparam.h"
  26. #include "pc.h"
  27. #include "kisspoll.h"
  28.   
  29. static void asy_monitor __ARGS((int dev,void *p1,void *p2));
  30.   
  31. static void asy_output __ARGS((int dev,char *buf,unsigned short cnt));
  32. static int asyrxint __ARGS((struct asy *asyp));
  33. static void asytxint __ARGS((int dev));
  34. static void asymsint __ARGS((int dev));
  35.   
  36. static void asy_tx __ARGS((int dev,void *p1,void *p2));
  37.   
  38. struct asy Asy[ASY_MAX];
  39.   
  40. /* ASY interrupt handlers */
  41. static INTERRUPT (*Handle[])() = {
  42.     asy0vec,asy1vec,asy2vec,asy3vec,asy4vec,asy5vec
  43. };
  44. static unsigned char fifo_setup;
  45.   
  46.   
  47. /* Initialize asynch port "dev" */
  48. int
  49. asy_init(
  50. int dev,
  51. struct iface *ifp,
  52. char *arg1,
  53. char *arg2,
  54. int16 bufsize,
  55. int trigchar,
  56. char monitor,
  57. long speed,
  58. int force,
  59. int triglevel,
  60. int polled) {
  61.   
  62.     unsigned base;
  63.     struct fifo *fp;
  64.     struct asy *ap;
  65.     char *ifn;
  66.     int i_state;
  67.     long interval;
  68.   
  69.     ap = &Asy[dev];
  70.     ap->iface = ifp;
  71.     ap->addr = htoi(arg1);
  72.     ap->vec = htoi(arg2);      /* Note HEX, not DECIMAL! */
  73.     if(strstr(strupr(arg2), "_C") == NULL) ap->chain = 0;
  74.     else ap->chain = 1;   /* irq chained (4port card?). -- n5knx */
  75.   
  76. #ifdef POLLEDKISS
  77.     ap->poller = NULL;
  78. #endif
  79.   
  80.     /* Set up receiver FIFO */
  81.     fp = &ap->fifo;
  82.     fp->buf = mallocw(bufsize);
  83.     fp->bufsize = bufsize;
  84.     fp->wp = fp->rp = fp->buf;
  85.     fp->cnt = 0;
  86.     fp->hiwat = 0;
  87.     fp->overrun = 0;
  88.     base = ap->addr;
  89.     ap->trigchar = trigchar;
  90.   
  91.     /* Purge the receive data buffer */
  92.     (void)inportb(base+RBR);
  93.   
  94.     i_state = dirps();
  95.   
  96.     /* Save original interrupt vector, mask state, control bits */
  97.     ap->save.vec = getirq(ap->vec);
  98.     ap->save.mask = getmask(ap->vec);
  99.     ap->save.lcr = inportb(base+LCR);
  100.     ap->save.ier = inportb(base+IER);
  101.     ap->save.mcr = inportb(base+MCR);
  102.     ap->save.msr = inportb(base+MSR);
  103.     ap->save.iir = inportb(base+IIR);
  104.   
  105.     /* save speed bytes */
  106.     setbit(base+LCR,LCR_DLAB);
  107.     ap->save.divl = inportb(base+DLL);
  108.     ap->save.divh = inportb(base+DLM);
  109.     clrbit(base+LCR,LCR_DLAB);
  110.   
  111.     /* save some information on the starting state */
  112. #ifdef NRS
  113.     if(ap->nrs_cts) {  /* WZ2B */
  114.         ap->cts_flow_control = IGNORED;
  115.         ap->rlsd_line_control = IGNORED;
  116.         ap->dtr_usage = IGNORED;
  117.         ap->rts_usage = IGNORED;
  118.         monitor = 0;
  119.     } else {
  120. #endif
  121.     ap->cts_flow_control = (ap->save.msr & MSR_CTS) ? FOUND_UP : FOUND_DOWN;
  122.     ap->rlsd_line_control = (ap->save.msr & MSR_RLSD) ? FOUND_UP : FOUND_DOWN;
  123.     ap->dtr_usage = (ap->save.mcr & MCR_DTR) ? FOUND_UP : FOUND_DOWN;
  124.     ap->rts_usage = (ap->save.mcr & MCR_RTS) ? FOUND_UP : FOUND_DOWN;
  125. #ifdef NRS
  126.     }
  127. #endif
  128.  
  129.     /* Set interrupt vector to SIO handler */
  130.     setirq(ap->vec,Handle[dev]);
  131.   
  132.     /* Set line control register: 8 bits, no parity */
  133.     outportb(base+LCR,(char)LCR_8BITS);
  134.   
  135.     /* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
  136.     outportb(base+FCR,(char) FIFO_ENABLE);
  137.   
  138.     /* According to National ap note AN-493, the FIFO in the 16550 chip
  139.      * is broken and must not be used. To determine if this is a 16550A
  140.      * (which has a good FIFO implementation) check that both bits 7
  141.      * and 6 of the IIR are 1 after setting the fifo enable bit. If
  142.      * not, don't try to use the FIFO.
  143.      */
  144.     /* Set the fifo trigger level according to the user's wishes :-) - WG7J */
  145.     if(triglevel == 1)
  146.         fifo_setup = FIFO_SETUP1;
  147.     else if(triglevel == 4)
  148.         fifo_setup = FIFO_SETUP4;
  149.     else if(triglevel == 8)
  150.         fifo_setup = FIFO_SETUP8;
  151.     else if(triglevel == 14)
  152.         fifo_setup = FIFO_SETUP14;
  153.     else
  154.         fifo_setup = FIFO_SETUP4;    /* default to 4 */
  155.   
  156.     if (((inportb(base+IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED) || force) {
  157.         ap->is_16550a = TRUE;
  158.         outportb(base+FCR,fifo_setup);
  159.     } else {
  160.         /* Chip is not a 16550A. In case it's a 16550 (which
  161.          * has a broken FIFO), turn off the FIFO bit.
  162.          */
  163.         outportb(base+FCR,(char)0);
  164.         ap->is_16550a = FALSE;
  165.     }
  166.   
  167.     /* Turn on modem status and receive interrupts,
  168.      * leave transmit interrupts off for now.
  169.      */
  170. #ifdef NRS
  171.     if(ap->nrs_cts)   /* WZ2B */
  172.         outportb(base+IER, (char) IER_DAV);
  173.     else
  174. #endif
  175.     outportb(base+IER, (char)(IER_MS + IER_DAV));
  176.   
  177.     /* Turn on 8250 master interrupt enable (connected to OUT2) */
  178.     setbit(base+MCR,(MCR_OUT2));
  179.   
  180.     /* Enable interrupt */
  181.     maskon(ap->vec);
  182.     restore(i_state);
  183.   
  184.     asy_speed(dev,speed);
  185.   
  186.     if ( monitor ) {
  187.         /* set up to monitor line signals */
  188.         ap->monitor = newproc( ifn = if_name( ifp, " monitor" ),
  189.         256, asy_monitor, ifp->dev, ifp, NULL, 0);
  190.         free(ifn);
  191.         pwait(NULL);    /* let hooks get set up */
  192.     }
  193.   
  194.     ifp->txproc = newproc( ifn = if_name(ifp," tx"),
  195.     256, asy_tx, dev, ifp, NULL, 0);
  196.     free(ifn);
  197.   
  198. #ifdef NRS
  199.     if (! ap->nrs_cts) {
  200. #endif
  201.     if ( (ap->dtr_usage & FOUND_UP) &&
  202.         (ap->rlsd_line_control & FOUND_UP) || ap->monitor == NULL ) {
  203.         if ( ifp->iostatus != NULL ) {
  204.             (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  205.         }
  206.     }
  207. #ifdef NRS
  208.     }
  209. #endif
  210.   
  211. #ifdef POLLEDKISS
  212.     if(polled) {
  213.         /* Calculate the poll interval: some processing time +
  214.          * the packet duration for a mtu size packet.
  215.          */
  216.         interval = (((long)ifp->mtu * 10000L) / speed);
  217.         ap->poller = newproc(ifn=if_name(ifp," poller"),
  218.         384,kiss_poller,ifp->xdev,(void *)interval,NULL,0);
  219.         free(ifn);
  220.     }
  221. #endif
  222.   
  223.     return 0;
  224. }
  225.   
  226.   
  227. int
  228. asy_stop(ifp)
  229. struct iface *ifp;
  230. {
  231.     register unsigned base;
  232.     register struct asy *ap;
  233.     int i_state;
  234.   
  235.     ap = &Asy[ifp->dev];
  236.   
  237. #ifdef POLLEDKISS
  238.     if(ap->poller)
  239.         killproc(ap->poller);
  240. #endif
  241.   
  242.     if ( ap->monitor != NULL ) {
  243.         ap->rlsd_line_control = IGNORED;
  244.         killproc( ap->monitor );
  245.         ap->monitor = NULL;
  246.     }
  247.     ap->iface = NULLIF;
  248.   
  249.     base = ap->addr;
  250.   
  251.     /* Purge the receive data buffer */
  252.     (void)inportb(base+RBR);
  253.   
  254.     /* and hardware fifos if available */
  255.     if (ap->is_16550a) {
  256.         if((ap->save.iir & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
  257.             outportb(base+FCR,fifo_setup);
  258.         else
  259.             outportb(base+FCR,0);
  260.     }
  261.   
  262.     /* Restore original interrupt vector and 8259 mask state */
  263.     i_state = dirps();
  264.     setirq(ap->vec,ap->save.vec);
  265.     if(ap->save.mask)
  266.         maskon(ap->vec);
  267.     else
  268.         maskoff(ap->vec);
  269.   
  270.     /* Restore speed regs */
  271.     setbit(base+LCR,LCR_DLAB);
  272.     outportb(base+DLL,ap->save.divl);       /* Low byte */
  273.     outportb(base+DLM,ap->save.divh);       /* Hi byte */
  274.     clrbit(base+LCR,LCR_DLAB);
  275.   
  276.     /* Restore control regs */
  277.     /* except, leave DTR in current state {bsimpson} */
  278.     outportb(base+LCR,ap->save.lcr);
  279.     outportb(base+IER,ap->save.ier);
  280.     outportb(base+MCR,ap->save.mcr);
  281. #ifdef notdef
  282.     outportb(base+MCR,(ap->save.mcr &~ MCR_DTR)
  283.     | (inportb(base+MCR) & MCR_DTR) );
  284. #endif
  285.   
  286.     restore(i_state);
  287.     free(ap->fifo.buf);
  288.   
  289.     return 0;
  290. }
  291.   
  292.   
  293. /* Set asynch line speed */
  294. int
  295. asy_speed(dev,bps)
  296. int dev;
  297. long bps;
  298. {
  299.     register unsigned base;
  300.     register long divisor;
  301.     struct asy *asyp;
  302.     int i_state;
  303.   
  304.     if(bps <= 0 || dev >= ASY_MAX)
  305.         return -1;
  306.     asyp = &Asy[dev];
  307.     if(asyp->iface == NULLIF)
  308.         return -1;
  309.   
  310.     switch(bps) {
  311.         case 300L:
  312.         case 1200L:
  313.         case 2400L:
  314.         case 4800L:
  315.         case 9600L:
  316.         case 19200L:
  317.         case 38400L:
  318.         case 57600L:
  319.         case 115200L:
  320.         /* supported speed */
  321.             asyp->speed = bps;
  322.             break;
  323.         default:
  324.         /* unsupported speed */
  325.             return -1;
  326.     };
  327.   
  328.     base = asyp->addr;
  329.     divisor = BAUDCLK / bps;
  330.   
  331.     i_state = dirps();
  332.   
  333.     /* Purge the receive data buffer */
  334.     (void)inportb(base+RBR);
  335.     if (asyp->is_16550a)            /* clear tx+rx fifos */
  336.         outportb(base+FCR,fifo_setup);
  337.   
  338.     /* Turn on divisor latch access bit */
  339.     setbit(base+LCR,LCR_DLAB);
  340.   
  341.     /* Load the two bytes of the register */
  342.     outportb(base+DLL,(char)(divisor & 0xff));              /* Low byte */
  343.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));       /* Hi byte */
  344.   
  345.     /* Turn off divisor latch access bit */
  346.     clrbit(base+LCR,LCR_DLAB);
  347.   
  348.     restore(i_state);
  349.     return 0;
  350. }
  351.   
  352.   
  353. /* Asynchronous line I/O control */
  354. int32
  355. asy_ioctl(ifp,cmd,set,val)
  356. struct iface *ifp;
  357. int cmd;
  358. int set;
  359. int32 val;
  360. {
  361.     struct asy *ap = &Asy[ifp->dev];
  362.     int16 base = ap->addr;
  363.   
  364.     switch(cmd){
  365.         case PARAM_SPEED:
  366.             if(set)
  367.                 asy_speed(ifp->dev,val);
  368.             return ap->speed;
  369.         case PARAM_DTR:
  370.             if(set) {
  371.                 writebit(base+MCR,MCR_DTR,(int)val);
  372.                 ap->dtr_usage = (val) ? MOVED_UP : MOVED_DOWN;
  373.             }
  374.             return (inportb(base+MCR) & MCR_DTR) ? TRUE : FALSE;
  375.         case PARAM_RTS:
  376.             if(set) {
  377.                 writebit(base+MCR,MCR_RTS,(int)val);
  378.                 ap->rts_usage = (val) ? MOVED_UP : MOVED_DOWN;
  379.             }
  380.             return (inportb(base+MCR) & MCR_RTS) ? TRUE : FALSE;
  381.         case PARAM_DOWN:
  382. #ifdef NRS
  383.             if(! ap->nrs_cts) {    /* WZ2B */
  384. #endif
  385.             clrbit(base+IER,(char)IER_DAV);
  386.             clrbit(base+MCR,MCR_RTS);
  387.             clrbit(base+MCR,MCR_DTR);
  388.             ap->rts_usage = MOVED_DOWN;
  389.             ap->dtr_usage = MOVED_DOWN;
  390. #ifdef NRS
  391.             }
  392. #endif
  393.             return FALSE;
  394.         case PARAM_UP:
  395. #ifdef NRS
  396.             if(! ap->nrs_cts) {    /* WZ2B */
  397. #endif
  398.             setbit(base+IER,(char)IER_DAV);
  399.             setbit(base+MCR,MCR_RTS);
  400.             setbit(base+MCR,MCR_DTR);
  401.             ap->rts_usage = MOVED_UP;
  402.             ap->dtr_usage = MOVED_UP;
  403. #ifdef NRS
  404.             }
  405. #endif
  406.             return TRUE;
  407.         case PARAM_BLIND:
  408.             setbit(base+IER,(char)IER_DAV);
  409.             ap->rlsd_line_control = IGNORED;
  410.   
  411.             if ( ap->monitor != NULL ) {
  412.                 killproc( ap->monitor );
  413.                 ap->monitor = NULL;
  414.             }
  415.   
  416.         /* can't see what we are doing, so pretend we're up */
  417.             if ( ifp->iostatus != NULL ) {
  418.                 (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  419.             }
  420.             return TRUE;
  421.     };
  422.     return -1;
  423. }
  424.   
  425.   
  426. /* Start transmission of a buffer on the serial transmitter */
  427. static void
  428. asy_output(dev,buf,cnt)
  429. int dev;
  430. char *buf;
  431. unsigned short cnt;
  432. {
  433.     register struct dma *dp;
  434.     unsigned base;
  435.     int i_state;
  436.     char ier;
  437.     struct asy *asyp;
  438.   
  439.     if(dev < 0 || dev >= ASY_MAX)
  440.         return;
  441.     asyp = &Asy[dev];
  442.     if(asyp->iface == NULLIF)
  443.         return;
  444.   
  445.     base = asyp->addr;
  446.     dp = &asyp->dma;
  447.     i_state = dirps();
  448.   
  449.     if(dp->flags){
  450.         restore(i_state);
  451.         return; /* Already busy */
  452.     }
  453.     dp->data = buf;
  454.     dp->cnt = cnt;
  455.     dp->flags = 1;
  456.  
  457.     if(asyp->cts_flow_control & MOVED_DOWN){
  458.         /* CTS flow control is enabled; let the modem control
  459.          * interrupt enable transmit interrupts if CTS is off
  460.          */
  461.         ier = IER_MS;
  462.         if(inportb(base+MSR) & MSR_CTS)
  463.             ier |= IER_TxE;
  464.     } else {
  465.         /* Enable transmit interrupts; this will cause an immediate
  466.          * interrupt that will start things going
  467.          */
  468.         ier = IER_TxE;
  469.     }
  470.  
  471.     setbit(base+IER,ier);
  472.   
  473.     /* "Kick start" the transmitter interrupt routine, in case just
  474.      * setting the interrupt enable bit doesn't cause an interrupt
  475.      */
  476.     if(ier & IER_TxE)
  477.         asytxint(dev);
  478.     restore(i_state);
  479. }
  480.   
  481.   
  482. /* Blocking read from asynch line
  483.  * Returns character or -1 if aborting
  484.  */
  485. int
  486. get_asy(dev)
  487. int dev;
  488. {
  489.     int i_state;
  490.     register struct fifo *fp;
  491.     char c;
  492.   
  493.     fp = &Asy[dev].fifo;
  494.   
  495.     i_state = dirps();
  496.     while(fp->cnt == 0){
  497.         if(pwait(fp) != 0){
  498.             restore(i_state);
  499.             return -1;
  500.         }
  501.     }
  502.     fp->cnt--;
  503.     restore(i_state);
  504.   
  505.     c = *fp->rp++;
  506.     if(fp->rp >= &fp->buf[fp->bufsize])
  507.         fp->rp = fp->buf;
  508.   
  509.     return uchar(c);
  510. }
  511.   
  512.   
  513. /* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
  514. /* void asyint(dev)*/
  515. INTERRUPT (far *(asyint)(dev))()
  516. int dev;
  517. {
  518.     struct asy *asyp;
  519.     unsigned base;
  520.     char iir;
  521.   
  522. #ifdef ALL_INTS
  523.     unsigned startdev = dev;
  524.  
  525.     do {
  526. #endif
  527.         asyp = &Asy[dev];
  528. #ifdef ALL_INTS
  529.         if(asyp->iface) {
  530. #endif
  531.             base = asyp->addr;
  532.             while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  533.                 switch (iir & IIR_ID_MASK) {
  534.                 case IIR_RDA:   /* Receiver interrupt */
  535.                         asyrxint(asyp);
  536.                         break;
  537.                 case IIR_THRE:  /* Transmit interrupt */
  538.                         asytxint(dev);
  539.                         break;
  540.                 case IIR_MSTAT:  /* Modem status change */
  541.                         asymsint(dev);
  542.                         asyp->msint_count++;
  543.                         break;
  544.                 }
  545.                 /* should happen at end of a single packet */
  546.                 if(iir & IIR_FIFO_TIMEOUT)
  547.                     asyp->fifotimeouts++;
  548.             }
  549. #ifdef ALL_INTS
  550.         }
  551.         if(++dev >= ASY_MAX)
  552.             dev = 0;
  553.     } while(dev != startdev);
  554. #endif
  555. return asyp->chain ? asyp->save.vec : NULL;
  556. }
  557.   
  558.   
  559. /* Process 8250 receiver interrupts */
  560. static int
  561. asyrxint(asyp)
  562. struct asy *asyp;
  563. {
  564.     register struct fifo *fp;
  565.     unsigned base;
  566.     char c,lsr;
  567.     int cnt = 0;
  568.     int trigseen = FALSE;
  569.   
  570.     asyp->rxints++;
  571.     base = asyp->addr;
  572.     fp = &asyp->fifo;
  573.     for(;;){
  574.         lsr = inportb(base+LSR);
  575.         if(lsr & LSR_OE)
  576.             asyp->overrun++;
  577.   
  578.         if(lsr & LSR_DR){
  579.             asyp->rxchar++;
  580.             c = inportb(base+RBR);
  581.             if(asyp->trigchar == uchar(c))
  582.                 trigseen = TRUE;
  583.             /* If buffer is full, we have no choice but
  584.              * to drop the character
  585.              */
  586.             if(fp->cnt != fp->bufsize){
  587.                 *fp->wp++ = c;
  588.                 if(fp->wp >= &fp->buf[fp->bufsize])
  589.                     /* Wrap around */
  590.                     fp->wp = fp->buf;
  591.                 fp->cnt++;
  592.                 if(fp->cnt > fp->hiwat)
  593.                     fp->hiwat = fp->cnt;
  594.                 cnt++;
  595.             } else
  596.                 fp->overrun++;
  597.                 trigseen = TRUE;        /* @@@ */
  598.         } else
  599.             break;
  600.     }
  601.     if(cnt > asyp->rxhiwat)
  602.         asyp->rxhiwat = cnt;
  603.     if(trigseen)
  604.         psignal(fp,1);
  605.     return cnt;
  606. }
  607.   
  608.   
  609. /* Handle 8250 transmitter interrupts */
  610. static void
  611. asytxint(dev)
  612. int dev;
  613. {
  614.     register struct dma *dp;
  615.     register unsigned base;
  616.     register int count;
  617.     struct asy *asyp;
  618.   
  619.     asyp = &Asy[dev];
  620.     base = asyp->addr;
  621.     dp = &asyp->dma;
  622.     asyp->txints++;
  623.     if(!dp->flags) {
  624.         /* "Shouldn't happen", but disable transmit
  625.          * interrupts anyway
  626.          */
  627.         clrbit(base+IER,IER_TxE);
  628.         return; /* Nothing to send */
  629.     }
  630.     if(!(inportb(base+LSR) & LSR_THRE))
  631.         return; /* Not really ready */
  632.  
  633.     if(asyp->cts_flow_control & MOVED_DOWN   /* CTS flow control is enabled */
  634.          && !(inportb(base+MSR) & MSR_CTS))  /* but CTS is de-asserted */
  635.         return; /* nor is the modem ready */
  636.   
  637.     /* If it's a 16550A, load up to 16 chars into the tx hw fifo
  638.      * at once. With an 8250, it can be one char at most.
  639.      */
  640.     if(asyp->is_16550a){
  641.         count = min(dp->cnt,OUTPUT_FIFO_SIZE);
  642.   
  643.         /* 16550A: LSR_THRE will drop after the first char loaded
  644.          * so we can't look at this bit to determine if the hw fifo is
  645.          * full. There seems to be no way to determine if the tx fifo
  646.          * is full (any clues?). So we should never get here while the
  647.          * fifo isn't empty yet.
  648.          */
  649.         asyp->txchar += count;
  650.         dp->cnt -= count;
  651. #ifdef  notdef  /* This is apparently too fast for some chips */
  652.         dp->data = outbuf(base+THR,dp->data,count);
  653. #else
  654.         while(count-- != 0)
  655.             outportb(base+THR,*dp->data++);
  656. #endif
  657.         if(dp->cnt == 0){
  658.             dp->flags = 0;
  659.             /* Disable transmit interrupts */
  660.             clrbit(base+IER,IER_TxE);
  661.             psignal(asyp,1);
  662.         }
  663.     } else {        /* 8250 */
  664.         do {
  665.             asyp->txchar++;
  666.             outportb(base+THR,*dp->data++);
  667.   
  668.             if(--dp->cnt == 0){
  669.                 dp->flags = 0;
  670.                 /* Disable transmit interrupts */
  671.                 clrbit(base+IER,IER_TxE);
  672.                 psignal(asyp,1);
  673.                 break;
  674.             }
  675.         } while(inportb(base+LSR) & LSR_THRE);
  676.     }
  677. }
  678.   
  679.   
  680. /* Handle 8250 modem status change
  681.  *      If the signals are unchanging, we ignore them.
  682.  *      If they change, we use them to condition the line.
  683.  */
  684. static void
  685. asymsint(dev)
  686. int dev;
  687. {
  688.     struct asy *ap = &Asy[dev];
  689.     unsigned base = ap->addr;
  690.   
  691.     ap->msr = inportb(base+MSR);
  692.   
  693.     if ( ap->msr & MSR_CTS ) {
  694.         switch ( ap->cts_flow_control ) {
  695.             case FOUND_DOWN:
  696.             case MOVED_DOWN:
  697.                 ap->cts_flow_control = MOVED_UP;
  698.   
  699.             /* CTS now asserted, enable Transmit interrupts */
  700.                 if(ap->dma.flags) {
  701.                     setbit(base+IER,IER_TxE);
  702.                     asytxint(dev);              /* @@@ */
  703.                 }
  704.                 break;
  705.         };
  706.     } else {
  707.         switch ( ap->cts_flow_control ) {
  708.             case FOUND_UP:
  709.             case MOVED_UP:
  710.                 ap->cts_flow_control = MOVED_DOWN;
  711.   
  712.             /* CTS now dropped, disable Transmit interrupts */
  713.                 clrbit(base+IER,IER_TxE);
  714.                 break;
  715.         };
  716.     }
  717.   
  718.     if ( ap->msr & MSR_RLSD ) {
  719.         switch ( ap->rlsd_line_control ) {
  720.             case FOUND_DOWN:
  721.             case MOVED_DOWN:
  722.                 ap->rlsd_line_control = MOVED_UP;
  723.   
  724.             /* RLSD just went up */
  725.                 psignal( &(ap->rlsd_line_control), 1 );
  726.                 break;
  727.         };
  728.     } else {
  729.         switch ( ap->rlsd_line_control ) {
  730.             case FOUND_UP:
  731.             case MOVED_UP:
  732.                 ap->rlsd_line_control = MOVED_DOWN;
  733.   
  734.             /* RLSD just went down */
  735.                 psignal( &(ap->rlsd_line_control), 1 );
  736.                 break;
  737.         };
  738.     }
  739.   
  740.     if ( ap->msr & (MSR_TERI | MSR_RI) ) {
  741.         asy_ioctl( ap->iface, PARAM_UP, TRUE, 0L );
  742.     }
  743. }
  744.   
  745.   
  746. /* Wait for a signal that the RLSD modem status has changed */
  747. int
  748. get_rlsd_asy(dev, new_rlsd)
  749. int dev;
  750. int new_rlsd;
  751. {
  752.     struct asy *ap = &Asy[dev];
  753.     struct iface *ifp = ap->iface;
  754.     int result;
  755.   
  756.     if ( ap->rlsd_line_control & IGNORED ) {
  757.         return IGNORED;
  758.     }
  759.   
  760.     switch ( new_rlsd ) {
  761.         case IGNORED:
  762.         /* Just return the current value */
  763.             return(ap->rlsd_line_control);
  764.   
  765.         case MOVED_DOWN:
  766.             if ( !(ap->rlsd_line_control & FOUND_UP) ) {
  767.             /* Already at requested value */
  768.                 return(new_rlsd);
  769.             }
  770.             break;
  771.         case MOVED_UP:
  772.             if ( ap->rlsd_line_control & FOUND_UP ) {
  773.             /* Already at requested value */
  774.                 return(new_rlsd);
  775.             }
  776.             break;
  777.     };
  778.   
  779.     /* Wait for state change to requested value */
  780.     while (ap->rlsd_line_control != new_rlsd) {
  781.         pause(2L);
  782.         pwait( &(ap->rlsd_line_control) );
  783.     }
  784.   
  785.     if ( ap->rlsd_line_control & FOUND_UP )
  786.         result = PARAM_UP;
  787.     else /* DOWN or IGNORED */
  788.         result = PARAM_DOWN;
  789.   
  790.     /* set our control signals to follow RLSD */
  791.     if ( ifp->ioctl != NULL )
  792.         (*ifp->ioctl)( ifp, result, TRUE, 0L );
  793.  
  794.         if (result == IGNORED)
  795.                 result = PARAM_DOWN;    /* give correct status @@@ */
  796.  
  797.     if ( ifp->iostatus != NULL )
  798.         (*ifp->iostatus)( ifp, result, 0L );
  799.     return(ap->rlsd_line_control);
  800. }
  801.   
  802.   
  803. /* Monitor RLSD signal, and report status changes */
  804. static void
  805. asy_monitor( dev, p1, p2 )
  806. int dev;
  807. void *p1;
  808. void *p2;
  809. {
  810.     int save_rlsd = Asy[dev].rlsd_line_control;
  811.   
  812.     while ( save_rlsd != IGNORED ) {
  813.         save_rlsd = get_rlsd_asy( dev,
  814.         ( save_rlsd ^ FOUND_UP ) | MOVED_DOWN );
  815.     }
  816.     Asy[dev].monitor = NULL;
  817. }
  818.   
  819.   
  820. /* Poll the asynch input queues; called on every clock tick.
  821.  * This helps limit the interrupt ring buffer occupancy when long
  822.  * packets are being received.
  823.  */
  824. void
  825. asytimer()
  826. {
  827.     register struct asy *asyp;
  828.     register struct fifo *fp;
  829.     register int i;
  830.   
  831.     for(i=0;i<ASY_MAX;i++){
  832.         asyp = &Asy[i];
  833.         fp = &asyp->fifo;
  834.         if(fp->cnt != 0)
  835.             psignal(fp,1);
  836.         if(asyp->dma.flags != 0 && (inportb(asyp->addr+LSR) & LSR_THRE)) {
  837.             /* data waiting and uart buffer empty ... did we miss an interrupt? */
  838.             /* && (inportb(asyp->addr+IER) & IER_TxE) */ /* this doesn't help! N5KNX */
  839.  
  840.             if(asyp->cts_flow_control & MOVED_DOWN   /* CTS flow control is enabled */
  841.                && !(inportb(asyp->addr+MSR) & MSR_CTS))    /* but CTS is de-asserted */
  842.                 continue;    /* this is done in asytxint() but here, we avoid a false txto++ */
  843.             asyp->txto++;
  844.             asytxint(asyp->iface->dev);
  845.         }
  846.     }
  847. }
  848. int
  849. doasystat(argc,argv,p)
  850. int argc;
  851. char *argv[];
  852. void *p;
  853. {
  854.     register struct asy *asyp;
  855.   
  856.     for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  857.         if(asyp->iface == NULLIF)
  858.             continue;
  859.   
  860.         tprintf("%s:",asyp->iface->name);
  861.         if(asyp->is_16550a)
  862.             tputs(" [NS16550A]");
  863.         if(asyp->trigchar != -1)
  864.             tprintf(" [trigger 0x%02x]",asyp->trigchar);
  865.         switch (asyp->cts_flow_control) {
  866.             case MOVED_DOWN:
  867.             case MOVED_UP:
  868.                 tputs(" [cts flow control]");
  869.                 break;
  870.         };
  871.         switch (asyp->rlsd_line_control) {
  872.             case MOVED_DOWN:
  873.             case MOVED_UP:
  874.                 tputs(" [rlsd line control]");
  875.                 break;
  876.             case IGNORED:
  877.                 tputs(" [rlsd blind]");
  878.                 break;
  879.         };
  880. #ifdef NRS
  881.         if(asyp->nrs_cts)   /* WZ2B */
  882.             tputs(" [NRS flow control]");
  883. #endif
  884.         tprintf(" %lu bps [@ %x,%x%s]\n",asyp->speed, asyp->addr, asyp->vec, (asyp->chain? "_C" : ""));
  885.   
  886.         tprintf(" RX: %lu int, %lu chr, %lu hw over, %lu hw hi,",
  887.         asyp->rxints,
  888.         asyp->rxchar,
  889.         asyp->overrun,
  890.         asyp->rxhiwat);
  891.         asyp->rxhiwat = 0;
  892.         if(asyp->is_16550a)
  893.             tprintf(" %lu fifo TO,",asyp->fifotimeouts);
  894.         tprintf(" %lu sw over, %u sw hi\n",
  895.         asyp->fifo.overrun,
  896.         asyp->fifo.hiwat);
  897.         asyp->fifo.hiwat = 0;
  898.   
  899.         if(tprintf(" TX: %lu int, %lu chr, %u q, %lu MS int, %lu THRE TO\n",
  900.             asyp->txints,
  901.             asyp->txchar,
  902.             len_q(asyp->sndq),
  903.             asyp->msint_count,
  904.             asyp->txto) == EOF)
  905.             break;
  906.     }
  907.     return 0;
  908. }
  909.   
  910. /* Send a message on the specified serial line */
  911. int
  912. asy_send(dev,bp)
  913. int dev;
  914. struct mbuf *bp;
  915. {
  916.     if(dev < 0 || dev >= ASY_MAX)
  917.         return -1;
  918.     enqueue(&Asy[dev].sndq,bp);
  919.   /*      while (len_p((struct mbuf*)&Asy[dev].sndq)){
  920.         pwait(NULL);
  921.     }
  922.   */
  923.     return 0;
  924. }
  925.   
  926. /* Serial transmit process, common to all protocols */
  927. static void
  928. asy_tx(dev,p1,p2)
  929. int dev;
  930. void *p1;
  931. void *p2;
  932. {
  933.     register struct mbuf *bp;
  934.     struct asy *asyp;
  935.     struct dma *dp;
  936.     int i_state;
  937.   
  938.     asyp = &Asy[dev];
  939.     dp = &asyp->dma;
  940.   
  941.     for(;;){
  942.         /* Fetch a buffer for transmission */
  943.         while(asyp->sndq == NULLBUF)
  944.             pwait(&asyp->sndq);
  945.   
  946.         bp = dequeue(&asyp->sndq);
  947.   
  948.         while(bp != NULLBUF){
  949. #ifdef NRS
  950.             if(asyp->nrs_cts) { /* WZ2B */
  951.                 while(!(inportb((asyp->addr)+MSR)&MSR_CTS))
  952.                     pwait(NULL);
  953.                 clrbit((asyp->addr)+MCR,MCR_RTS);
  954.             }
  955. #endif
  956.             /* Start the transmitter */
  957.             asy_output(dev,bp->data,bp->cnt);
  958.   
  959.             /* Wait for completion */
  960.             i_state = dirps();
  961.             while(dp->flags == 1)
  962.                 pwait(asyp);
  963. #ifdef NRS
  964.             if(asyp->nrs_cts) { /* WZ2B */
  965.                 while(!(inportb((asyp->addr)+LSR)&LSR_THRE))
  966.                     pwait(NULL);
  967.                 while(!(inportb((asyp->addr)+LSR)&LSR_TSRE))
  968.                     pwait(NULL);
  969.                 setbit((asyp->addr)+MCR,MCR_RTS);
  970.             }
  971. #endif
  972.             restore(i_state);
  973.   
  974.             /* Now do next buffer on chain */
  975.             bp = free_mbuf(bp);
  976.         }
  977.     }
  978. }
  979.   
  980. #ifdef TIPSERVER
  981. int
  982. carrier_detect(int dev)
  983. {
  984.     struct asy *ap = &Asy[dev];
  985.     unsigned base = ap->addr;
  986.   
  987.     ap->msr = inportb(base+MSR);
  988.     if ( ap->msr & MSR_RLSD ) {
  989.         return 1;
  990.     } else {
  991.         return 0;
  992.     }
  993. }
  994.   
  995. #endif
  996.   
  997.   
  998.