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

Cache object: 72acfba11b837e97751b3ff4a6a93a6f


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