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

Cache object: 55aef06c4b9911c5c59ca6cfb3afcb78


[ 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.