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