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