The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/rc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia.
    3  * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  *
   29  */
   30 
   31 /*
   32  * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver
   33  *
   34  */
   35 
   36 #include "rc.h"
   37 
   38 /*#define RCDEBUG*/
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/tty.h>
   43 #include <sys/proc.h>
   44 #include <sys/conf.h>
   45 #include <sys/dkstat.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/interrupt.h>
   48 #include <sys/kernel.h>
   49 #include <machine/clock.h>
   50 #include <machine/ipl.h>
   51 
   52 #include <i386/isa/isa_device.h>
   53 
   54 #include <i386/isa/ic/cd180.h>
   55 #include <i386/isa/rcreg.h>
   56 
   57 /* Prototypes */
   58 static int     rcprobe         __P((struct isa_device *));
   59 static int     rcattach        __P((struct isa_device *));
   60 
   61 #define rcin(port)      RC_IN  (nec, port)
   62 #define rcout(port,v)   RC_OUT (nec, port, v)
   63 
   64 #define WAITFORCCR(u,c) rc_wait0(nec, (u), (c), __LINE__)
   65 #define CCRCMD(u,c,cmd) WAITFORCCR((u), (c)); rcout(CD180_CCR, (cmd))
   66 
   67 #define RC_IBUFSIZE     256
   68 #define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE)
   69 #define RC_OBUFSIZE     512
   70 #define RC_IHIGHWATER   (3 * RC_IBUFSIZE / 4)
   71 #define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE)
   72 #define LOTS_OF_EVENTS  64
   73 
   74 #define RC_FAKEID       0x10
   75 
   76 #define RC_PROBED 1
   77 #define RC_ATTACHED 2
   78 
   79 #define GET_UNIT(dev)   (minor(dev) & 0x3F)
   80 #define CALLOUT(dev)    (minor(dev) & 0x80)
   81 
   82 /* For isa routines */
   83 struct isa_driver rcdriver = {
   84         rcprobe, rcattach, "rc"
   85 };
   86 
   87 static  d_open_t        rcopen;
   88 static  d_close_t       rcclose;
   89 static  d_ioctl_t       rcioctl;
   90 
   91 #define CDEV_MAJOR      63
   92 static struct cdevsw rc_cdevsw = {
   93         /* open */      rcopen,
   94         /* close */     rcclose,
   95         /* read */      ttyread,
   96         /* write */     ttywrite,
   97         /* ioctl */     rcioctl,
   98         /* poll */      ttypoll,
   99         /* mmap */      nommap,
  100         /* strategy */  nostrategy,
  101         /* name */      "rc",
  102         /* maj */       CDEV_MAJOR,
  103         /* dump */      nodump,
  104         /* psize */     nopsize,
  105         /* flags */     D_TTY | D_KQFILTER,
  106         /* bmaj */      -1,
  107         /* kqfilter */  ttykqfilter,
  108 };
  109 
  110 /* Per-board structure */
  111 static struct rc_softc {
  112         u_int           rcb_probed;     /* 1 - probed, 2 - attached */
  113         u_int           rcb_addr;       /* Base I/O addr        */
  114         u_int           rcb_unit;       /* unit #               */
  115         u_char          rcb_dtr;        /* DTR status           */
  116         struct rc_chans *rcb_baserc;    /* base rc ptr          */
  117 } rc_softc[NRC];
  118 
  119 /* Per-channel structure */
  120 static struct rc_chans  {
  121         struct rc_softc *rc_rcb;                /* back ptr             */
  122         u_short          rc_flags;              /* Misc. flags          */
  123         int              rc_chan;               /* Channel #            */
  124         u_char           rc_ier;                /* intr. enable reg     */
  125         u_char           rc_msvr;               /* modem sig. status    */
  126         u_char           rc_cor2;               /* options reg          */
  127         u_char           rc_pendcmd;            /* special cmd pending  */
  128         u_int            rc_dtrwait;            /* dtr timeout          */
  129         u_int            rc_dcdwaits;           /* how many waits DCD in open */
  130         u_char           rc_hotchar;            /* end packed optimize */
  131         struct tty      *rc_tp;                 /* tty struct           */
  132         u_char          *rc_iptr;               /* Chars input buffer         */
  133         u_char          *rc_hiwat;              /* hi-water mark        */
  134         u_char          *rc_bufend;             /* end of buffer        */
  135         u_char          *rc_optr;               /* ptr in output buf    */
  136         u_char          *rc_obufend;            /* end of output buf    */
  137         u_char           rc_ibuf[4 * RC_IBUFSIZE];  /* input buffer         */
  138         u_char           rc_obuf[RC_OBUFSIZE];  /* output buffer        */
  139 } rc_chans[NRC * CD180_NCHAN];
  140 
  141 static int rc_scheduled_event = 0;
  142 
  143 /* for pstat -t */
  144 static struct tty rc_tty[NRC * CD180_NCHAN];
  145 static const int  nrc_tty = NRC * CD180_NCHAN;
  146 
  147 /* Flags */
  148 #define RC_DTR_OFF      0x0001          /* DTR wait, for close/open     */
  149 #define RC_ACTOUT       0x0002          /* Dial-out port active         */
  150 #define RC_RTSFLOW      0x0004          /* RTS flow ctl enabled         */
  151 #define RC_CTSFLOW      0x0008          /* CTS flow ctl enabled         */
  152 #define RC_DORXFER      0x0010          /* RXFER event planned          */
  153 #define RC_DOXXFER      0x0020          /* XXFER event planned          */
  154 #define RC_MODCHG       0x0040          /* Modem status changed         */
  155 #define RC_OSUSP        0x0080          /* Output suspended             */
  156 #define RC_OSBUSY       0x0100          /* start() routine in progress  */
  157 #define RC_WAS_BUFOVFL  0x0200          /* low-level buffer ovferflow   */
  158 #define RC_WAS_SILOVFL  0x0400          /* silo buffer overflow         */
  159 #define RC_SEND_RDY     0x0800          /* ready to send */
  160 
  161 /* Table for translation of RCSR status bits to internal form */
  162 static int rc_rcsrt[16] = {
  163         0,             TTY_OE,               TTY_FE,
  164         TTY_FE|TTY_OE, TTY_PE,               TTY_PE|TTY_OE,
  165         TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI,
  166         TTY_BI|TTY_OE, TTY_BI|TTY_FE,        TTY_BI|TTY_FE|TTY_OE,
  167         TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE,
  168         TTY_BI|TTY_PE|TTY_FE|TTY_OE
  169 };
  170 
  171 /* Static prototypes */
  172 static ointhand2_t rcintr;
  173 static void rc_hwreset          __P((int, int, unsigned int));
  174 static int  rc_test             __P((int, int));
  175 static void rc_discard_output   __P((struct rc_chans *));
  176 static void rc_hardclose        __P((struct rc_chans *));
  177 static int  rc_modctl           __P((struct rc_chans *, int, int));
  178 static void rc_start            __P((struct tty *));
  179 static void rc_stop              __P((struct tty *, int rw));
  180 static int  rc_param            __P((struct tty *, struct termios *));
  181 static swihand_t rcpoll;
  182 static void rc_reinit           __P((struct rc_softc *));
  183 #ifdef RCDEBUG
  184 static void printrcflags();
  185 #endif
  186 static timeout_t rc_dtrwakeup;
  187 static timeout_t rc_wakeup;
  188 static void disc_optim          __P((struct tty *tp, struct termios *t, struct rc_chans *));
  189 static void rc_wait0            __P((int nec, int unit, int chan, int line));
  190 
  191 /**********************************************/
  192 
  193 /* Quick device probing */
  194 static int
  195 rcprobe(dvp)
  196         struct  isa_device      *dvp;
  197 {
  198         int             irq = ffs(dvp->id_irq) - 1;
  199         register int    nec = dvp->id_iobase;
  200 
  201         if (dvp->id_unit > NRC)
  202                 return 0;
  203         if (!RC_VALIDADDR(nec)) {
  204                 printf("rc%d: illegal base address %x\n", dvp->id_unit, nec);
  205                 return 0;
  206         }
  207         if (!RC_VALIDIRQ(irq)) {
  208                 printf("rc%d: illegal IRQ value %d\n", dvp->id_unit, irq);
  209                 return 0;
  210         }
  211         rcout(CD180_PPRL, 0x22); /* Random values to Prescale reg. */
  212         rcout(CD180_PPRH, 0x11);
  213         if (rcin(CD180_PPRL) != 0x22 || rcin(CD180_PPRH) != 0x11)
  214                 return 0;
  215         /* Now, test the board more thoroughly, with diagnostic */
  216         if (rc_test(nec, dvp->id_unit))
  217                 return 0;
  218         rc_softc[dvp->id_unit].rcb_probed = RC_PROBED;
  219 
  220         return 0xF;
  221 }
  222 
  223 static int
  224 rcattach(dvp)
  225         struct  isa_device      *dvp;
  226 {
  227         register int            chan, nec = dvp->id_iobase;
  228         struct rc_softc         *rcb = &rc_softc[dvp->id_unit];
  229         struct rc_chans         *rc  = &rc_chans[dvp->id_unit * CD180_NCHAN];
  230         static int              rc_started = 0;
  231         struct tty              *tp;
  232 
  233         dvp->id_ointr = rcintr;
  234 
  235         /* Thorooughly test the device */
  236         if (rcb->rcb_probed != RC_PROBED)
  237                 return 0;
  238         rcb->rcb_addr   = nec;
  239         rcb->rcb_dtr    = 0;
  240         rcb->rcb_baserc = rc;
  241         rcb->rcb_unit   = dvp->id_unit;
  242         /*rcb->rcb_chipid = 0x10 + dvp->id_unit;*/
  243         printf("rc%d: %d chans, firmware rev. %c\n", rcb->rcb_unit,
  244                 CD180_NCHAN, (rcin(CD180_GFRCR) & 0xF) + 'A');
  245 
  246         for (chan = 0; chan < CD180_NCHAN; chan++, rc++) {
  247                 rc->rc_rcb     = rcb;
  248                 rc->rc_chan    = chan;
  249                 rc->rc_iptr    = rc->rc_ibuf;
  250                 rc->rc_bufend  = &rc->rc_ibuf[RC_IBUFSIZE];
  251                 rc->rc_hiwat   = &rc->rc_ibuf[RC_IHIGHWATER];
  252                 rc->rc_flags   = rc->rc_ier = rc->rc_msvr = 0;
  253                 rc->rc_cor2    = rc->rc_pendcmd = 0;
  254                 rc->rc_optr    = rc->rc_obufend  = rc->rc_obuf;
  255                 rc->rc_dtrwait = 3 * hz;
  256                 rc->rc_dcdwaits= 0;
  257                 rc->rc_hotchar = 0;
  258                 tp = rc->rc_tp = &rc_tty[chan + (dvp->id_unit * CD180_NCHAN)];
  259                 ttychars(tp);
  260                 tp->t_lflag = tp->t_iflag = tp->t_oflag = 0;
  261                 tp->t_cflag = TTYDEF_CFLAG;
  262                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  263         }
  264         rcb->rcb_probed = RC_ATTACHED;
  265         if (!rc_started) {
  266                 cdevsw_add(&rc_cdevsw);
  267                 register_swi(SWI_TTY, rcpoll);
  268                 rc_wakeup((void *)NULL);
  269                 rc_started = 1;
  270         }
  271         return 1;
  272 }
  273 
  274 /* RC interrupt handling */
  275 static void
  276 rcintr(unit)
  277         int             unit;
  278 {
  279         register struct rc_softc        *rcb = &rc_softc[unit];
  280         register struct rc_chans        *rc;
  281         register int                    nec, resid;
  282         register u_char                 val, iack, bsr, ucnt, *optr;
  283         int                             good_data, t_state;
  284 
  285         if (rcb->rcb_probed != RC_ATTACHED) {
  286                 printf("rc%d: bogus interrupt\n", unit);
  287                 return;
  288         }
  289         nec = rcb->rcb_addr;
  290 
  291         bsr = ~(rcin(RC_BSR));
  292 
  293         if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) {
  294                 printf("rc%d: extra interrupt\n", unit);
  295                 rcout(CD180_EOIR, 0);
  296                 return;
  297         }
  298 
  299         while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) {
  300 #ifdef RCDEBUG_DETAILED
  301                 printf("rc%d: intr (%02x) %s%s%s%s\n", unit, bsr,
  302                         (bsr & RC_BSR_TOUT)?"TOUT ":"",
  303                         (bsr & RC_BSR_RXINT)?"RXINT ":"",
  304                         (bsr & RC_BSR_TXINT)?"TXINT ":"",
  305                         (bsr & RC_BSR_MOINT)?"MOINT":"");
  306 #endif
  307                 if (bsr & RC_BSR_TOUT) {
  308                         printf("rc%d: hardware failure, reset board\n", unit);
  309                         rcout(RC_CTOUT, 0);
  310                         rc_reinit(rcb);
  311                         return;
  312                 }
  313                 if (bsr & RC_BSR_RXINT) {
  314                         iack = rcin(RC_PILR_RX);
  315                         good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID));
  316                         if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) {
  317                                 printf("rc%d: fake rxint: %02x\n", unit, iack);
  318                                 goto more_intrs;
  319                         }
  320                         rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
  321                         t_state = rc->rc_tp->t_state;
  322                         /* Do RTS flow control stuff */
  323                         if (  (rc->rc_flags & RC_RTSFLOW)
  324                             || !(t_state & TS_ISOPEN)
  325                            ) {
  326                                 if (  (   !(t_state & TS_ISOPEN)
  327                                        || (t_state & TS_TBLOCK)
  328                                       )
  329                                     && (rc->rc_msvr & MSVR_RTS)
  330                                    )
  331                                         rcout(CD180_MSVR,
  332                                                 rc->rc_msvr &= ~MSVR_RTS);
  333                                 else if (!(rc->rc_msvr & MSVR_RTS))
  334                                         rcout(CD180_MSVR,
  335                                                 rc->rc_msvr |= MSVR_RTS);
  336                         }
  337                         ucnt  = rcin(CD180_RDCR) & 0xF;
  338                         resid = 0;
  339 
  340                         if (t_state & TS_ISOPEN) {
  341                                 /* check for input buffer overflow */
  342                                 if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) {
  343                                         resid  = ucnt;
  344                                         ucnt   = rc->rc_bufend - rc->rc_iptr;
  345                                         resid -= ucnt;
  346                                         if (!(rc->rc_flags & RC_WAS_BUFOVFL)) {
  347                                                 rc->rc_flags |= RC_WAS_BUFOVFL;
  348                                                 rc_scheduled_event++;
  349                                         }
  350                                 }
  351                                 optr = rc->rc_iptr;
  352                                 /* check foor good data */
  353                                 if (good_data) {
  354                                         while (ucnt-- > 0) {
  355                                                 val = rcin(CD180_RDR);
  356                                                 optr[0] = val;
  357                                                 optr[INPUT_FLAGS_SHIFT] = 0;
  358                                                 optr++;
  359                                                 rc_scheduled_event++;
  360                                                 if (val != 0 && val == rc->rc_hotchar)
  361                                                         setsofttty();
  362                                         }
  363                                 } else {
  364                                         /* Store also status data */
  365                                         while (ucnt-- > 0) {
  366                                                 iack = rcin(CD180_RCSR);
  367                                                 if (iack & RCSR_Timeout)
  368                                                         break;
  369                                                 if (   (iack & RCSR_OE)
  370                                                     && !(rc->rc_flags & RC_WAS_SILOVFL)) {
  371                                                         rc->rc_flags |= RC_WAS_SILOVFL;
  372                                                         rc_scheduled_event++;
  373                                                 }
  374                                                 val = rcin(CD180_RDR);
  375                                                 /*
  376                                                   Don't store PE if IGNPAR and BREAK if IGNBRK,
  377                                                   this hack allows "raw" tty optimization
  378                                                   works even if IGN* is set.
  379                                                 */
  380                                                 if (   !(iack & (RCSR_PE|RCSR_FE|RCSR_Break))
  381                                                     || ((!(iack & (RCSR_PE|RCSR_FE))
  382                                                     ||  !(rc->rc_tp->t_iflag & IGNPAR))
  383                                                     && (!(iack & RCSR_Break)
  384                                                     ||  !(rc->rc_tp->t_iflag & IGNBRK)))) {
  385                                                         if (   (iack & (RCSR_PE|RCSR_FE))
  386                                                             && (t_state & TS_CAN_BYPASS_L_RINT)
  387                                                             && ((iack & RCSR_FE)
  388                                                             ||  ((iack & RCSR_PE)
  389                                                             &&  (rc->rc_tp->t_iflag & INPCK))))
  390                                                                 val = 0;
  391                                                         else if (val != 0 && val == rc->rc_hotchar)
  392                                                                 setsofttty();
  393                                                         optr[0] = val;
  394                                                         optr[INPUT_FLAGS_SHIFT] = iack;
  395                                                         optr++;
  396                                                         rc_scheduled_event++;
  397                                                 }
  398                                         }
  399                                 }
  400                                 rc->rc_iptr = optr;
  401                                 rc->rc_flags |= RC_DORXFER;
  402                         } else
  403                                 resid = ucnt;
  404                         /* Clear FIFO if necessary */
  405                         while (resid-- > 0) {
  406                                 if (!good_data)
  407                                         iack = rcin(CD180_RCSR);
  408                                 else
  409                                         iack = 0;
  410                                 if (iack & RCSR_Timeout)
  411                                         break;
  412                                 (void) rcin(CD180_RDR);
  413                         }
  414                         goto more_intrs;
  415                 }
  416                 if (bsr & RC_BSR_MOINT) {
  417                         iack = rcin(RC_PILR_MODEM);
  418                         if (iack != (GIVR_IT_MSCI | RC_FAKEID)) {
  419                                 printf("rc%d: fake moint: %02x\n", unit, iack);
  420                                 goto more_intrs;
  421                         }
  422                         rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
  423                         iack = rcin(CD180_MCR);
  424                         rc->rc_msvr = rcin(CD180_MSVR);
  425                         rcout(CD180_MCR, 0);
  426 #ifdef RCDEBUG
  427                         printrcflags(rc, "moint");
  428 #endif
  429                         if (rc->rc_flags & RC_CTSFLOW) {
  430                                 if (rc->rc_msvr & MSVR_CTS)
  431                                         rc->rc_flags |= RC_SEND_RDY;
  432                                 else
  433                                         rc->rc_flags &= ~RC_SEND_RDY;
  434                         } else
  435                                 rc->rc_flags |= RC_SEND_RDY;
  436                         if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) {
  437                                 rc_scheduled_event += LOTS_OF_EVENTS;
  438                                 rc->rc_flags |= RC_MODCHG;
  439                                 setsofttty();
  440                         }
  441                         goto more_intrs;
  442                 }
  443                 if (bsr & RC_BSR_TXINT) {
  444                         iack = rcin(RC_PILR_TX);
  445                         if (iack != (GIVR_IT_TDI | RC_FAKEID)) {
  446                                 printf("rc%d: fake txint: %02x\n", unit, iack);
  447                                 goto more_intrs;
  448                         }
  449                         rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
  450                         if (    (rc->rc_flags & RC_OSUSP)
  451                             || !(rc->rc_flags & RC_SEND_RDY)
  452                            )
  453                                 goto more_intrs;
  454                         /* Handle breaks and other stuff */
  455                         if (rc->rc_pendcmd) {
  456                                 rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC);
  457                                 rcout(CD180_TDR,  CD180_C_ESC);
  458                                 rcout(CD180_TDR,  rc->rc_pendcmd);
  459                                 rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC);
  460                                 rc->rc_pendcmd = 0;
  461                                 goto more_intrs;
  462                         }
  463                         optr = rc->rc_optr;
  464                         resid = rc->rc_obufend - optr;
  465                         if (resid > CD180_NFIFO)
  466                                 resid = CD180_NFIFO;
  467                         while (resid-- > 0)
  468                                 rcout(CD180_TDR, *optr++);
  469                         rc->rc_optr = optr;
  470 
  471                         /* output completed? */
  472                         if (optr >= rc->rc_obufend) {
  473                                 rcout(CD180_IER, rc->rc_ier &= ~IER_TxRdy);
  474 #ifdef RCDEBUG
  475                                 printf("rc%d/%d: output completed\n", unit, rc->rc_chan);
  476 #endif
  477                                 if (!(rc->rc_flags & RC_DOXXFER)) {
  478                                         rc_scheduled_event += LOTS_OF_EVENTS;
  479                                         rc->rc_flags |= RC_DOXXFER;
  480                                         setsofttty();
  481                                 }
  482                         }
  483                 }
  484         more_intrs:
  485                 rcout(CD180_EOIR, 0);   /* end of interrupt */
  486                 rcout(RC_CTOUT, 0);
  487                 bsr = ~(rcin(RC_BSR));
  488         }
  489 }
  490 
  491 /* Feed characters to output buffer */
  492 static void rc_start(tp)
  493 register struct tty *tp;
  494 {
  495         register struct rc_chans       *rc = &rc_chans[GET_UNIT(tp->t_dev)];
  496         register int                    nec = rc->rc_rcb->rcb_addr, s;
  497 
  498         if (rc->rc_flags & RC_OSBUSY)
  499                 return;
  500         s = spltty();
  501         rc->rc_flags |= RC_OSBUSY;
  502         disable_intr();
  503         if (tp->t_state & TS_TTSTOP)
  504                 rc->rc_flags |= RC_OSUSP;
  505         else
  506                 rc->rc_flags &= ~RC_OSUSP;
  507         /* Do RTS flow control stuff */
  508         if (   (rc->rc_flags & RC_RTSFLOW)
  509             && (tp->t_state & TS_TBLOCK)
  510             && (rc->rc_msvr & MSVR_RTS)
  511            ) {
  512                 rcout(CD180_CAR, rc->rc_chan);
  513                 rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS);
  514         } else if (!(rc->rc_msvr & MSVR_RTS)) {
  515                 rcout(CD180_CAR, rc->rc_chan);
  516                 rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS);
  517         }
  518         enable_intr();
  519         if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
  520                 goto out;
  521 #ifdef RCDEBUG
  522         printrcflags(rc, "rcstart");
  523 #endif
  524         ttwwakeup(tp);
  525 #ifdef RCDEBUG
  526         printf("rcstart: outq = %d obuf = %d\n",
  527                 tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr);
  528 #endif
  529         if (tp->t_state & TS_BUSY)
  530                 goto    out;    /* output still in progress ... */
  531 
  532         if (tp->t_outq.c_cc > 0) {
  533                 u_int   ocnt;
  534 
  535                 tp->t_state |= TS_BUSY;
  536                 ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf);
  537                 disable_intr();
  538                 rc->rc_optr = rc->rc_obuf;
  539                 rc->rc_obufend = rc->rc_optr + ocnt;
  540                 enable_intr();
  541                 if (!(rc->rc_ier & IER_TxRdy)) {
  542 #ifdef RCDEBUG
  543                         printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan);
  544 #endif
  545                         rcout(CD180_CAR, rc->rc_chan);
  546                         rcout(CD180_IER, rc->rc_ier |= IER_TxRdy);
  547                 }
  548         }
  549 out:
  550         rc->rc_flags &= ~RC_OSBUSY;
  551         (void) splx(s);
  552 }
  553 
  554 /* Handle delayed events. */
  555 void rcpoll()
  556 {
  557         register struct rc_chans *rc;
  558         register struct rc_softc *rcb;
  559         register u_char        *tptr, *eptr;
  560         register struct tty    *tp;
  561         register int            chan, icnt, nec, unit;
  562 
  563         if (rc_scheduled_event == 0)
  564                 return;
  565 repeat:
  566         for (unit = 0; unit < NRC; unit++) {
  567                 rcb = &rc_softc[unit];
  568                 rc = rcb->rcb_baserc;
  569                 nec = rc->rc_rcb->rcb_addr;
  570                 for (chan = 0; chan < CD180_NCHAN; rc++, chan++) {
  571                         tp = rc->rc_tp;
  572 #ifdef RCDEBUG
  573                         if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG|
  574                             RC_WAS_BUFOVFL|RC_WAS_SILOVFL))
  575                                 printrcflags(rc, "rcevent");
  576 #endif
  577                         if (rc->rc_flags & RC_WAS_BUFOVFL) {
  578                                 disable_intr();
  579                                 rc->rc_flags &= ~RC_WAS_BUFOVFL;
  580                                 rc_scheduled_event--;
  581                                 enable_intr();
  582                                 printf("rc%d/%d: interrupt-level buffer overflow\n",
  583                                         unit, chan);
  584                         }
  585                         if (rc->rc_flags & RC_WAS_SILOVFL) {
  586                                 disable_intr();
  587                                 rc->rc_flags &= ~RC_WAS_SILOVFL;
  588                                 rc_scheduled_event--;
  589                                 enable_intr();
  590                                 printf("rc%d/%d: silo overflow\n",
  591                                         unit, chan);
  592                         }
  593                         if (rc->rc_flags & RC_MODCHG) {
  594                                 disable_intr();
  595                                 rc->rc_flags &= ~RC_MODCHG;
  596                                 rc_scheduled_event -= LOTS_OF_EVENTS;
  597                                 enable_intr();
  598                                 (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD));
  599                         }
  600                         if (rc->rc_flags & RC_DORXFER) {
  601                                 disable_intr();
  602                                 rc->rc_flags &= ~RC_DORXFER;
  603                                 eptr = rc->rc_iptr;
  604                                 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE])
  605                                         tptr = &rc->rc_ibuf[RC_IBUFSIZE];
  606                                 else
  607                                         tptr = rc->rc_ibuf;
  608                                 icnt = eptr - tptr;
  609                                 if (icnt > 0) {
  610                                         if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
  611                                                 rc->rc_iptr   = rc->rc_ibuf;
  612                                                 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];
  613                                                 rc->rc_hiwat  = &rc->rc_ibuf[RC_IHIGHWATER];
  614                                         } else {
  615                                                 rc->rc_iptr   = &rc->rc_ibuf[RC_IBUFSIZE];
  616                                                 rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE];
  617                                                 rc->rc_hiwat  =
  618                                                         &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER];
  619                                         }
  620                                         if (   (rc->rc_flags & RC_RTSFLOW)
  621                                             && (tp->t_state & TS_ISOPEN)
  622                                             && !(tp->t_state & TS_TBLOCK)
  623                                             && !(rc->rc_msvr & MSVR_RTS)
  624                                             ) {
  625                                                 rcout(CD180_CAR, chan);
  626                                                 rcout(CD180_MSVR,
  627                                                         rc->rc_msvr |= MSVR_RTS);
  628                                         }
  629                                         rc_scheduled_event -= icnt;
  630                                 }
  631                                 enable_intr();
  632 
  633                                 if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))
  634                                         goto done1;
  635 
  636                                 if (   (tp->t_state & TS_CAN_BYPASS_L_RINT)
  637                                     && !(tp->t_state & TS_LOCAL)) {
  638                                         if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER
  639                                             && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
  640                                             && !(tp->t_state & TS_TBLOCK))
  641                                                 ttyblock(tp);
  642                                         tk_nin += icnt;
  643                                         tk_rawcc += icnt;
  644                                         tp->t_rawcc += icnt;
  645                                         if (b_to_q(tptr, icnt, &tp->t_rawq))
  646                                                 printf("rc%d/%d: tty-level buffer overflow\n",
  647                                                         unit, chan);
  648                                         ttwakeup(tp);
  649                                         if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY)
  650                                             || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) {
  651                                                 tp->t_state &= ~TS_TTSTOP;
  652                                                 tp->t_lflag &= ~FLUSHO;
  653                                                 rc_start(tp);
  654                                         }
  655                                 } else {
  656                                         for (; tptr < eptr; tptr++)
  657                                                 (*linesw[tp->t_line].l_rint)
  658                                                     (tptr[0] |
  659                                                     rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp);
  660                                 }
  661 done1: ;
  662                         }
  663                         if (rc->rc_flags & RC_DOXXFER) {
  664                                 disable_intr();
  665                                 rc_scheduled_event -= LOTS_OF_EVENTS;
  666                                 rc->rc_flags &= ~RC_DOXXFER;
  667                                 rc->rc_tp->t_state &= ~TS_BUSY;
  668                                 enable_intr();
  669                                 (*linesw[tp->t_line].l_start)(tp);
  670                         }
  671                 }
  672                 if (rc_scheduled_event == 0)
  673                         break;
  674         }
  675         if (rc_scheduled_event >= LOTS_OF_EVENTS)
  676                 goto repeat;
  677 }
  678 
  679 static  void
  680 rc_stop(tp, rw)
  681         register struct tty     *tp;
  682         int                     rw;
  683 {
  684         register struct rc_chans        *rc = &rc_chans[GET_UNIT(tp->t_dev)];
  685         u_char *tptr, *eptr;
  686 
  687 #ifdef RCDEBUG
  688         printf("rc%d/%d: rc_stop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan,
  689                 (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":"");
  690 #endif
  691         if (rw & FWRITE)
  692                 rc_discard_output(rc);
  693         disable_intr();
  694         if (rw & FREAD) {
  695                 rc->rc_flags &= ~RC_DORXFER;
  696                 eptr = rc->rc_iptr;
  697                 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
  698                         tptr = &rc->rc_ibuf[RC_IBUFSIZE];
  699                         rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];
  700                 } else {
  701                         tptr = rc->rc_ibuf;
  702                         rc->rc_iptr = rc->rc_ibuf;
  703                 }
  704                 rc_scheduled_event -= eptr - tptr;
  705         }
  706         if (tp->t_state & TS_TTSTOP)
  707                 rc->rc_flags |= RC_OSUSP;
  708         else
  709                 rc->rc_flags &= ~RC_OSUSP;
  710         enable_intr();
  711 }
  712 
  713 static  int
  714 rcopen(dev, flag, mode, p)
  715         dev_t           dev;
  716         int             flag, mode;
  717         struct proc    *p;
  718 {
  719         register struct rc_chans *rc;
  720         register struct tty      *tp;
  721         int             unit, nec, s, error = 0;
  722 
  723         unit = GET_UNIT(dev);
  724         if (unit >= NRC * CD180_NCHAN)
  725                 return ENXIO;
  726         if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED)
  727                 return ENXIO;
  728         rc  = &rc_chans[unit];
  729         tp  = rc->rc_tp;
  730         dev->si_tty = tp;
  731         nec = rc->rc_rcb->rcb_addr;
  732 #ifdef RCDEBUG
  733         printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
  734 #endif
  735         s = spltty();
  736 
  737 again:
  738         while (rc->rc_flags & RC_DTR_OFF) {
  739                 error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0);
  740                 if (error != 0)
  741                         goto out;
  742         }
  743         if (tp->t_state & TS_ISOPEN) {
  744                 if (CALLOUT(dev)) {
  745                         if (!(rc->rc_flags & RC_ACTOUT)) {
  746                                 error = EBUSY;
  747                                 goto out;
  748                         }
  749                 } else {
  750                         if (rc->rc_flags & RC_ACTOUT) {
  751                                 if (flag & O_NONBLOCK) {
  752                                         error = EBUSY;
  753                                         goto out;
  754                                 }
  755                                 error = tsleep(&rc->rc_rcb,
  756                                      TTIPRI|PCATCH, "rcbi", 0);
  757                                 if (error)
  758                                         goto out;
  759                                 goto again;
  760                         }
  761                 }
  762                 if (tp->t_state & TS_XCLUDE &&
  763                     suser(p)) {
  764                         error = EBUSY;
  765                         goto out;
  766                 }
  767         } else {
  768                 tp->t_oproc   = rc_start;
  769                 tp->t_param   = rc_param;
  770                 tp->t_stop    = rc_stop;
  771                 tp->t_dev     = dev;
  772 
  773                 if (CALLOUT(dev))
  774                         tp->t_cflag |= CLOCAL;
  775                 else
  776                         tp->t_cflag &= ~CLOCAL;
  777 
  778                 error = rc_param(tp, &tp->t_termios);
  779                 if (error)
  780                         goto out;
  781                 (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET);
  782 
  783                 if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev))
  784                         (*linesw[tp->t_line].l_modem)(tp, 1);
  785         }
  786         if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev)
  787             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
  788                 rc->rc_dcdwaits++;
  789                 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0);
  790                 rc->rc_dcdwaits--;
  791                 if (error != 0)
  792                         goto out;
  793                 goto again;
  794         }
  795         error = (*linesw[tp->t_line].l_open)(dev, tp);
  796         disc_optim(tp, &tp->t_termios, rc);
  797         if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev))
  798                 rc->rc_flags |= RC_ACTOUT;
  799 out:
  800         (void) splx(s);
  801 
  802         if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN))
  803                 rc_hardclose(rc);
  804 
  805         return error;
  806 }
  807 
  808 static  int
  809 rcclose(dev, flag, mode, p)
  810         dev_t           dev;
  811         int             flag, mode;
  812         struct proc    *p;
  813 {
  814         register struct rc_chans *rc;
  815         register struct tty      *tp;
  816         int  s, unit = GET_UNIT(dev);
  817 
  818         if (unit >= NRC * CD180_NCHAN)
  819                 return ENXIO;
  820         rc  = &rc_chans[unit];
  821         tp  = rc->rc_tp;
  822 #ifdef RCDEBUG
  823         printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
  824 #endif
  825         s = spltty();
  826         (*linesw[tp->t_line].l_close)(tp, flag);
  827         disc_optim(tp, &tp->t_termios, rc);
  828         rc_stop(tp, FREAD | FWRITE);
  829         rc_hardclose(rc);
  830         ttyclose(tp);
  831         splx(s);
  832         return 0;
  833 }
  834 
  835 static void rc_hardclose(rc)
  836 register struct rc_chans *rc;
  837 {
  838         register int s, nec = rc->rc_rcb->rcb_addr;
  839         register struct tty *tp = rc->rc_tp;
  840 
  841         s = spltty();
  842         rcout(CD180_CAR, rc->rc_chan);
  843 
  844         /* Disable rx/tx intrs */
  845         rcout(CD180_IER, rc->rc_ier = 0);
  846         if (   (tp->t_cflag & HUPCL)
  847             || (!(rc->rc_flags & RC_ACTOUT)
  848                && !(rc->rc_msvr & MSVR_CD)
  849                && !(tp->t_cflag & CLOCAL))
  850             || !(tp->t_state & TS_ISOPEN)
  851            ) {
  852                 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
  853                 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
  854                 (void) rc_modctl(rc, TIOCM_RTS, DMSET);
  855                 if (rc->rc_dtrwait) {
  856                         timeout(rc_dtrwakeup, rc, rc->rc_dtrwait);
  857                         rc->rc_flags |= RC_DTR_OFF;
  858                 }
  859         }
  860         rc->rc_flags &= ~RC_ACTOUT;
  861         wakeup((caddr_t) &rc->rc_rcb);  /* wake bi */
  862         wakeup(TSA_CARR_ON(tp));
  863         (void) splx(s);
  864 }
  865 
  866 /* Reset the bastard */
  867 static void rc_hwreset(unit, nec, chipid)
  868         register int    unit, nec;
  869         unsigned int    chipid;
  870 {
  871         CCRCMD(unit, -1, CCR_HWRESET);            /* Hardware reset */
  872         DELAY(20000);
  873         WAITFORCCR(unit, -1);
  874 
  875         rcout(RC_CTOUT, 0);             /* Clear timeout  */
  876         rcout(CD180_GIVR,  chipid);
  877         rcout(CD180_GICR,  0);
  878 
  879         /* Set Prescaler Registers (1 msec) */
  880         rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF);
  881         rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8);
  882 
  883         /* Initialize Priority Interrupt Level Registers */
  884         rcout(CD180_PILR1, RC_PILR_MODEM);
  885         rcout(CD180_PILR2, RC_PILR_TX);
  886         rcout(CD180_PILR3, RC_PILR_RX);
  887 
  888         /* Reset DTR */
  889         rcout(RC_DTREG, ~0);
  890 }
  891 
  892 /* Set channel parameters */
  893 static int rc_param(tp, ts)
  894         register struct  tty    *tp;
  895         struct termios          *ts;
  896 {
  897         register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
  898         register int    nec = rc->rc_rcb->rcb_addr;
  899         int      idivs, odivs, s, val, cflag, iflag, lflag, inpflow;
  900 
  901         if (   ts->c_ospeed < 0 || ts->c_ospeed > 76800
  902             || ts->c_ispeed < 0 || ts->c_ispeed > 76800
  903            )
  904                 return (EINVAL);
  905         if (ts->c_ispeed == 0)
  906                 ts->c_ispeed = ts->c_ospeed;
  907         odivs = RC_BRD(ts->c_ospeed);
  908         idivs = RC_BRD(ts->c_ispeed);
  909 
  910         s = spltty();
  911 
  912         /* Select channel */
  913         rcout(CD180_CAR, rc->rc_chan);
  914 
  915         /* If speed == 0, hangup line */
  916         if (ts->c_ospeed == 0) {
  917                 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
  918                 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
  919                 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
  920         }
  921 
  922         tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
  923         cflag = ts->c_cflag;
  924         iflag = ts->c_iflag;
  925         lflag = ts->c_lflag;
  926 
  927         if (idivs > 0) {
  928                 rcout(CD180_RBPRL, idivs & 0xFF);
  929                 rcout(CD180_RBPRH, idivs >> 8);
  930         }
  931         if (odivs > 0) {
  932                 rcout(CD180_TBPRL, odivs & 0xFF);
  933                 rcout(CD180_TBPRH, odivs >> 8);
  934         }
  935 
  936         /* set timeout value */
  937         if (ts->c_ispeed > 0) {
  938                 int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1;
  939 
  940                 if (   !(lflag & ICANON)
  941                     && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0
  942                     && ts->c_cc[VTIME] * 10 > itm)
  943                         itm = ts->c_cc[VTIME] * 10;
  944 
  945                 rcout(CD180_RTPR, itm <= 255 ? itm : 255);
  946         }
  947 
  948         switch (cflag & CSIZE) {
  949                 case CS5:       val = COR1_5BITS;      break;
  950                 case CS6:       val = COR1_6BITS;      break;
  951                 case CS7:       val = COR1_7BITS;      break;
  952                 default:
  953                 case CS8:       val = COR1_8BITS;      break;
  954         }
  955         if (cflag & PARENB) {
  956                 val |= COR1_NORMPAR;
  957                 if (cflag & PARODD)
  958                         val |= COR1_ODDP;
  959                 if (!(cflag & INPCK))
  960                         val |= COR1_Ignore;
  961         } else
  962                 val |= COR1_Ignore;
  963         if (cflag & CSTOPB)
  964                 val |= COR1_2SB;
  965         rcout(CD180_COR1, val);
  966 
  967         /* Set FIFO threshold */
  968         val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2;
  969         inpflow = 0;
  970         if (   (iflag & IXOFF)
  971             && (   ts->c_cc[VSTOP] != _POSIX_VDISABLE
  972                 && (   ts->c_cc[VSTART] != _POSIX_VDISABLE
  973                     || (iflag & IXANY)
  974                    )
  975                )
  976            ) {
  977                 inpflow = 1;
  978                 val |= COR3_SCDE|COR3_FCT;
  979         }
  980         rcout(CD180_COR3, val);
  981 
  982         /* Initialize on-chip automatic flow control */
  983         val = 0;
  984         rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY);
  985         if (cflag & CCTS_OFLOW) {
  986                 rc->rc_flags |= RC_CTSFLOW;
  987                 val |= COR2_CtsAE;
  988         } else
  989                 rc->rc_flags |= RC_SEND_RDY;
  990         if (tp->t_state & TS_TTSTOP)
  991                 rc->rc_flags |= RC_OSUSP;
  992         else
  993                 rc->rc_flags &= ~RC_OSUSP;
  994         if (cflag & CRTS_IFLOW)
  995                 rc->rc_flags |= RC_RTSFLOW;
  996         else
  997                 rc->rc_flags &= ~RC_RTSFLOW;
  998 
  999         if (inpflow) {
 1000                 if (ts->c_cc[VSTART] != _POSIX_VDISABLE)
 1001                         rcout(CD180_SCHR1, ts->c_cc[VSTART]);
 1002                 rcout(CD180_SCHR2, ts->c_cc[VSTOP]);
 1003                 val |= COR2_TxIBE;
 1004                 if (iflag & IXANY)
 1005                         val |= COR2_IXM;
 1006         }
 1007 
 1008         rcout(CD180_COR2, rc->rc_cor2 = val);
 1009 
 1010         CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
 1011                 CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
 1012 
 1013         disc_optim(tp, ts, rc);
 1014 
 1015         /* modem ctl */
 1016         val = cflag & CLOCAL ? 0 : MCOR1_CDzd;
 1017         if (cflag & CCTS_OFLOW)
 1018                 val |= MCOR1_CTSzd;
 1019         rcout(CD180_MCOR1, val);
 1020 
 1021         val = cflag & CLOCAL ? 0 : MCOR2_CDod;
 1022         if (cflag & CCTS_OFLOW)
 1023                 val |= MCOR2_CTSod;
 1024         rcout(CD180_MCOR2, val);
 1025 
 1026         /* enable i/o and interrupts */
 1027         CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
 1028                 CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS));
 1029         WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
 1030 
 1031         rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD;
 1032         if (cflag & CCTS_OFLOW)
 1033                 rc->rc_ier |= IER_CTS;
 1034         if (cflag & CREAD)
 1035                 rc->rc_ier |= IER_RxData;
 1036         if (tp->t_state & TS_BUSY)
 1037                 rc->rc_ier |= IER_TxRdy;
 1038         if (ts->c_ospeed != 0)
 1039                 rc_modctl(rc, TIOCM_DTR, DMBIS);
 1040         if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS))
 1041                 rc->rc_flags |= RC_SEND_RDY;
 1042         rcout(CD180_IER, rc->rc_ier);
 1043         (void) splx(s);
 1044         return 0;
 1045 }
 1046 
 1047 /* Re-initialize board after bogus interrupts */
 1048 static void rc_reinit(rcb)
 1049 struct rc_softc         *rcb;
 1050 {
 1051         register struct rc_chans       *rc, *rce;
 1052         register int                    nec;
 1053 
 1054         nec = rcb->rcb_addr;
 1055         rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID);
 1056         rc  = &rc_chans[rcb->rcb_unit * CD180_NCHAN];
 1057         rce = rc + CD180_NCHAN;
 1058         for (; rc < rce; rc++)
 1059                 (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios);
 1060 }
 1061 
 1062 static  int
 1063 rcioctl(dev, cmd, data, flag, p)
 1064 dev_t           dev;
 1065 u_long          cmd;
 1066 int             flag;
 1067 caddr_t         data;
 1068 struct proc     *p;
 1069 {
 1070         register struct rc_chans       *rc = &rc_chans[GET_UNIT(dev)];
 1071         register int                    s, error;
 1072         struct tty                     *tp = rc->rc_tp;
 1073 
 1074         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
 1075         if (error != ENOIOCTL)
 1076                 return (error);
 1077         error = ttioctl(tp, cmd, data, flag);
 1078         disc_optim(tp, &tp->t_termios, rc);
 1079         if (error != ENOIOCTL)
 1080                 return (error);
 1081         s = spltty();
 1082 
 1083         switch (cmd) {
 1084             case TIOCSBRK:
 1085                 rc->rc_pendcmd = CD180_C_SBRK;
 1086                 break;
 1087 
 1088             case TIOCCBRK:
 1089                 rc->rc_pendcmd = CD180_C_EBRK;
 1090                 break;
 1091 
 1092             case TIOCSDTR:
 1093                 (void) rc_modctl(rc, TIOCM_DTR, DMBIS);
 1094                 break;
 1095 
 1096             case TIOCCDTR:
 1097                 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
 1098                 break;
 1099 
 1100             case TIOCMGET:
 1101                 *(int *) data = rc_modctl(rc, 0, DMGET);
 1102                 break;
 1103 
 1104             case TIOCMSET:
 1105                 (void) rc_modctl(rc, *(int *) data, DMSET);
 1106                 break;
 1107 
 1108             case TIOCMBIC:
 1109                 (void) rc_modctl(rc, *(int *) data, DMBIC);
 1110                 break;
 1111 
 1112             case TIOCMBIS:
 1113                 (void) rc_modctl(rc, *(int *) data, DMBIS);
 1114                 break;
 1115 
 1116             case TIOCMSDTRWAIT:
 1117                 error = suser(p);
 1118                 if (error != 0) {
 1119                         splx(s);
 1120                         return (error);
 1121                 }
 1122                 rc->rc_dtrwait = *(int *)data * hz / 100;
 1123                 break;
 1124 
 1125             case TIOCMGDTRWAIT:
 1126                 *(int *)data = rc->rc_dtrwait * 100 / hz;
 1127                 break;
 1128 
 1129             default:
 1130                 (void) splx(s);
 1131                 return ENOTTY;
 1132         }
 1133         (void) splx(s);
 1134         return 0;
 1135 }
 1136 
 1137 
 1138 /* Modem control routines */
 1139 
 1140 static int rc_modctl(rc, bits, cmd)
 1141 register struct rc_chans       *rc;
 1142 int                             bits, cmd;
 1143 {
 1144         register int    nec = rc->rc_rcb->rcb_addr;
 1145         u_char         *dtr = &rc->rc_rcb->rcb_dtr, msvr;
 1146 
 1147         rcout(CD180_CAR, rc->rc_chan);
 1148 
 1149         switch (cmd) {
 1150             case DMSET:
 1151                 rcout(RC_DTREG, (bits & TIOCM_DTR) ?
 1152                                 ~(*dtr |= 1 << rc->rc_chan) :
 1153                                 ~(*dtr &= ~(1 << rc->rc_chan)));
 1154                 msvr = rcin(CD180_MSVR);
 1155                 if (bits & TIOCM_RTS)
 1156                         msvr |= MSVR_RTS;
 1157                 else
 1158                         msvr &= ~MSVR_RTS;
 1159                 if (bits & TIOCM_DTR)
 1160                         msvr |= MSVR_DTR;
 1161                 else
 1162                         msvr &= ~MSVR_DTR;
 1163                 rcout(CD180_MSVR, msvr);
 1164                 break;
 1165 
 1166             case DMBIS:
 1167                 if (bits & TIOCM_DTR)
 1168                         rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan));
 1169                 msvr = rcin(CD180_MSVR);
 1170                 if (bits & TIOCM_RTS)
 1171                         msvr |= MSVR_RTS;
 1172                 if (bits & TIOCM_DTR)
 1173                         msvr |= MSVR_DTR;
 1174                 rcout(CD180_MSVR, msvr);
 1175                 break;
 1176 
 1177             case DMGET:
 1178                 bits = TIOCM_LE;
 1179                 msvr = rc->rc_msvr = rcin(CD180_MSVR);
 1180 
 1181                 if (msvr & MSVR_RTS)
 1182                         bits |= TIOCM_RTS;
 1183                 if (msvr & MSVR_CTS)
 1184                         bits |= TIOCM_CTS;
 1185                 if (msvr & MSVR_DSR)
 1186                         bits |= TIOCM_DSR;
 1187                 if (msvr & MSVR_DTR)
 1188                         bits |= TIOCM_DTR;
 1189                 if (msvr & MSVR_CD)
 1190                         bits |= TIOCM_CD;
 1191                 if (~rcin(RC_RIREG) & (1 << rc->rc_chan))
 1192                         bits |= TIOCM_RI;
 1193                 return bits;
 1194 
 1195             case DMBIC:
 1196                 if (bits & TIOCM_DTR)
 1197                         rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan)));
 1198                 msvr = rcin(CD180_MSVR);
 1199                 if (bits & TIOCM_RTS)
 1200                         msvr &= ~MSVR_RTS;
 1201                 if (bits & TIOCM_DTR)
 1202                         msvr &= ~MSVR_DTR;
 1203                 rcout(CD180_MSVR, msvr);
 1204                 break;
 1205         }
 1206         rc->rc_msvr = rcin(CD180_MSVR);
 1207         return 0;
 1208 }
 1209 
 1210 /* Test the board. */
 1211 int rc_test(nec, unit)
 1212         register int    nec;
 1213         int             unit;
 1214 {
 1215         int     chan = 0;
 1216         int     i = 0, rcnt, old_level;
 1217         unsigned int    iack, chipid;
 1218         unsigned short  divs;
 1219         static  u_char  ctest[] = "\377\125\252\045\244\0\377";
 1220 #define CTLEN   8
 1221 #define ERR(s)  { \
 1222                 printf("rc%d: ", unit); printf s ; printf("\n"); \
 1223                 (void) splx(old_level); return 1; }
 1224 
 1225         struct rtest {
 1226                 u_char  txbuf[CD180_NFIFO];     /* TX buffer  */
 1227                 u_char  rxbuf[CD180_NFIFO];     /* RX buffer  */
 1228                 int     rxptr;                  /* RX pointer */
 1229                 int     txptr;                  /* TX pointer */
 1230         } tchans[CD180_NCHAN];
 1231 
 1232         old_level = spltty();
 1233 
 1234         chipid = RC_FAKEID;
 1235 
 1236         /* First, reset board to inital state */
 1237         rc_hwreset(unit, nec, chipid);
 1238 
 1239         divs = RC_BRD(19200);
 1240 
 1241         /* Initialize channels */
 1242         for (chan = 0; chan < CD180_NCHAN; chan++) {
 1243 
 1244                 /* Select and reset channel */
 1245                 rcout(CD180_CAR, chan);
 1246                 CCRCMD(unit, chan, CCR_ResetChan);
 1247                 WAITFORCCR(unit, chan);
 1248 
 1249                 /* Set speed */
 1250                 rcout(CD180_RBPRL, divs & 0xFF);
 1251                 rcout(CD180_RBPRH, divs >> 8);
 1252                 rcout(CD180_TBPRL, divs & 0xFF);
 1253                 rcout(CD180_TBPRH, divs >> 8);
 1254 
 1255                 /* set timeout value */
 1256                 rcout(CD180_RTPR,  0);
 1257 
 1258                 /* Establish local loopback */
 1259                 rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB);
 1260                 rcout(CD180_COR2, COR2_LLM);
 1261                 rcout(CD180_COR3, CD180_NFIFO);
 1262                 CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
 1263                 CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN);
 1264                 WAITFORCCR(unit, chan);
 1265                 rcout(CD180_MSVR, MSVR_RTS);
 1266 
 1267                 /* Fill TXBUF with test data */
 1268                 for (i = 0; i < CD180_NFIFO; i++) {
 1269                         tchans[chan].txbuf[i] = ctest[i];
 1270                         tchans[chan].rxbuf[i] = 0;
 1271                 }
 1272                 tchans[chan].txptr = tchans[chan].rxptr = 0;
 1273 
 1274                 /* Now, start transmit */
 1275                 rcout(CD180_IER, IER_TxMpty|IER_RxData);
 1276         }
 1277         /* Pseudo-interrupt poll stuff */
 1278         for (rcnt = 10000; rcnt-- > 0; rcnt--) {
 1279                 i = ~(rcin(RC_BSR));
 1280                 if (i & RC_BSR_TOUT)
 1281                         ERR(("BSR timeout bit set\n"))
 1282                 else if (i & RC_BSR_TXINT) {
 1283                         iack = rcin(RC_PILR_TX);
 1284                         if (iack != (GIVR_IT_TDI | chipid))
 1285                                 ERR(("Bad TX intr ack (%02x != %02x)\n",
 1286                                         iack, GIVR_IT_TDI | chipid));
 1287                         chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
 1288                         /* If no more data to transmit, disable TX intr */
 1289                         if (tchans[chan].txptr >= CD180_NFIFO) {
 1290                                 iack = rcin(CD180_IER);
 1291                                 rcout(CD180_IER, iack & ~IER_TxMpty);
 1292                         } else {
 1293                                 for (iack = tchans[chan].txptr;
 1294                                     iack < CD180_NFIFO; iack++)
 1295                                         rcout(CD180_TDR,
 1296                                             tchans[chan].txbuf[iack]);
 1297                                 tchans[chan].txptr = iack;
 1298                         }
 1299                         rcout(CD180_EOIR, 0);
 1300                 } else if (i & RC_BSR_RXINT) {
 1301                         u_char ucnt;
 1302 
 1303                         iack = rcin(RC_PILR_RX);
 1304                         if (iack != (GIVR_IT_RGDI | chipid) &&
 1305                             iack != (GIVR_IT_REI  | chipid))
 1306                                 ERR(("Bad RX intr ack (%02x != %02x)\n",
 1307                                         iack, GIVR_IT_RGDI | chipid))
 1308                         chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
 1309                         ucnt = rcin(CD180_RDCR) & 0xF;
 1310                         while (ucnt-- > 0) {
 1311                                 iack = rcin(CD180_RCSR);
 1312                                 if (iack & RCSR_Timeout)
 1313                                         break;
 1314                                 if (iack & 0xF)
 1315                                         ERR(("Bad char chan %d (RCSR = %02X)\n",
 1316                                             chan, iack))
 1317                                 if (tchans[chan].rxptr > CD180_NFIFO)
 1318                                         ERR(("Got extra chars chan %d\n",
 1319                                             chan))
 1320                                 tchans[chan].rxbuf[tchans[chan].rxptr++] =
 1321                                         rcin(CD180_RDR);
 1322                         }
 1323                         rcout(CD180_EOIR, 0);
 1324                 }
 1325                 rcout(RC_CTOUT, 0);
 1326                 for (iack = chan = 0; chan < CD180_NCHAN; chan++)
 1327                         if (tchans[chan].rxptr >= CD180_NFIFO)
 1328                                 iack++;
 1329                 if (iack == CD180_NCHAN)
 1330                         break;
 1331         }
 1332         for (chan = 0; chan < CD180_NCHAN; chan++) {
 1333                 /* Select and reset channel */
 1334                 rcout(CD180_CAR, chan);
 1335                 CCRCMD(unit, chan, CCR_ResetChan);
 1336         }
 1337 
 1338         if (!rcnt)
 1339                 ERR(("looses characters during local loopback\n"))
 1340         /* Now, check data */
 1341         for (chan = 0; chan < CD180_NCHAN; chan++)
 1342                 for (i = 0; i < CD180_NFIFO; i++)
 1343                         if (ctest[i] != tchans[chan].rxbuf[i])
 1344                                 ERR(("data mismatch chan %d ptr %d (%d != %d)\n",
 1345                                     chan, i, ctest[i], tchans[chan].rxbuf[i]))
 1346         (void) splx(old_level);
 1347         return 0;
 1348 }
 1349 
 1350 #ifdef RCDEBUG
 1351 static void printrcflags(rc, comment)
 1352 struct rc_chans  *rc;
 1353 char             *comment;
 1354 {
 1355         u_short f = rc->rc_flags;
 1356         register int    nec = rc->rc_rcb->rcb_addr;
 1357 
 1358         printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n",
 1359                 rc->rc_rcb->rcb_unit, rc->rc_chan, comment,
 1360                 (f & RC_DTR_OFF)?"DTR_OFF " :"",
 1361                 (f & RC_ACTOUT) ?"ACTOUT " :"",
 1362                 (f & RC_RTSFLOW)?"RTSFLOW " :"",
 1363                 (f & RC_CTSFLOW)?"CTSFLOW " :"",
 1364                 (f & RC_DORXFER)?"DORXFER " :"",
 1365                 (f & RC_DOXXFER)?"DOXXFER " :"",
 1366                 (f & RC_MODCHG) ?"MODCHG "  :"",
 1367                 (f & RC_OSUSP)  ?"OSUSP " :"",
 1368                 (f & RC_OSBUSY) ?"OSBUSY " :"",
 1369                 (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"",
 1370                 (f & RC_WAS_SILOVFL) ?"SILOVFL " :"",
 1371                 (f & RC_SEND_RDY) ?"SEND_RDY":"");
 1372 
 1373         rcout(CD180_CAR, rc->rc_chan);
 1374 
 1375         printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n",
 1376                 rc->rc_rcb->rcb_unit, rc->rc_chan,
 1377                 rcin(CD180_MSVR),
 1378                 rcin(CD180_IER),
 1379                 rcin(CD180_CCSR));
 1380 }
 1381 #endif /* RCDEBUG */
 1382 
 1383 static void
 1384 rc_dtrwakeup(chan)
 1385         void    *chan;
 1386 {
 1387         struct rc_chans  *rc;
 1388 
 1389         rc = (struct rc_chans *)chan;
 1390         rc->rc_flags &= ~RC_DTR_OFF;
 1391         wakeup(&rc->rc_dtrwait);
 1392 }
 1393 
 1394 static void
 1395 rc_discard_output(rc)
 1396         struct rc_chans  *rc;
 1397 {
 1398         disable_intr();
 1399         if (rc->rc_flags & RC_DOXXFER) {
 1400                 rc_scheduled_event -= LOTS_OF_EVENTS;
 1401                 rc->rc_flags &= ~RC_DOXXFER;
 1402         }
 1403         rc->rc_optr = rc->rc_obufend;
 1404         rc->rc_tp->t_state &= ~TS_BUSY;
 1405         enable_intr();
 1406         ttwwakeup(rc->rc_tp);
 1407 }
 1408 
 1409 static void
 1410 rc_wakeup(chan)
 1411         void    *chan;
 1412 {
 1413         timeout(rc_wakeup, (caddr_t)NULL, 1);
 1414 
 1415         if (rc_scheduled_event != 0) {
 1416                 int     s;
 1417 
 1418                 s = splsofttty();
 1419                 rcpoll();
 1420                 splx(s);
 1421         }
 1422 }
 1423 
 1424 static void
 1425 disc_optim(tp, t, rc)
 1426         struct tty      *tp;
 1427         struct termios  *t;
 1428         struct rc_chans *rc;
 1429 {
 1430 
 1431         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 1432             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 1433             && (!(t->c_iflag & PARMRK)
 1434                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 1435             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 1436             && linesw[tp->t_line].l_rint == ttyinput)
 1437                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
 1438         else
 1439                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 1440         rc->rc_hotchar = linesw[tp->t_line].l_hotchar;
 1441 }
 1442 
 1443 static void
 1444 rc_wait0(nec, unit, chan, line)
 1445         int     nec, unit, chan, line;
 1446 {
 1447         int rcnt;
 1448 
 1449         for (rcnt = 50; rcnt && rcin(CD180_CCR); rcnt--)
 1450                 DELAY(30);
 1451         if (rcnt == 0)
 1452                 printf("rc%d/%d: channel command timeout, rc.c line: %d\n",
 1453                       unit, chan, line);
 1454 }

Cache object: 5b350ef4bfb2fb6034518b6f04d56fb2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.