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/cx.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Cronyx-Sigma adapter driver for FreeBSD.
    3  * Supports PPP/HDLC protocol in synchronous mode,
    4  * and asyncronous channels with full modem control.
    5  *
    6  * Copyright (C) 1994 Cronyx Ltd.
    7  * Author: Serge Vakulenko, <vak@zebub.msk.su>
    8  *
    9  * This software is distributed with NO WARRANTIES, not even the implied
   10  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   11  *
   12  * Authors grant any other persons or organisations permission to use
   13  * or modify this software as long as this message is kept with the software,
   14  * all derivative works or modified versions.
   15  *
   16  * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
   17  *
   18  * $FreeBSD: releng/5.1/sys/i386/isa/cx.c 111821 2003-03-03 16:24:47Z phk $
   19  *
   20  */
   21 #undef DEBUG
   22 
   23 #include "cx.h"
   24 
   25 #include <sys/param.h>
   26 #include <sys/systm.h>
   27 #include <sys/kernel.h>
   28 #include <sys/fcntl.h>
   29 #include <sys/conf.h>
   30 #include <sys/tty.h>
   31 #include <sys/socket.h>
   32 #include <net/if.h>
   33 
   34 #      define t_out t_outq
   35 #      define RB_LEN(q) ((q).c_cc)
   36 #      define RB_GETC(q) getc(&q)
   37 #ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */
   38 #      define TSA_CARR_ON(tp) tp
   39 #      define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
   40 #endif
   41 
   42 #include <machine/cronyx.h>
   43 #include <i386/isa/cxreg.h>
   44 
   45 /* XXX imported from if_cx.c. */
   46 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
   47 
   48 /* XXX exported. */
   49 void cxmint (cx_chan_t *c);
   50 int cxrinta (cx_chan_t *c);
   51 void cxtinta (cx_chan_t *c);
   52 timeout_t cxtimeout;
   53 
   54 #ifdef DEBUG
   55 #   define print(s)     printf s
   56 #else
   57 #   define print(s)     {/*void*/}
   58 #endif
   59 
   60 #define DMABUFSZ        (6*256)         /* buffer size */
   61 #define BYTE            *(unsigned char*)&
   62 #define UNIT(u)         (minor(u) & 077)
   63 #define UNIT_CTL        077
   64 
   65 extern cx_board_t cxboard [NCX];        /* adapter state structures */
   66 extern cx_chan_t *cxchan [NCX*NCHAN];   /* unit to channel struct pointer */
   67 static struct tty cx_tty [NCX*NCHAN];          /* tty data */
   68 
   69 static  d_open_t        cxopen;
   70 static  d_close_t       cxclose;
   71 static  d_ioctl_t       cxioctl;
   72 
   73 #define CDEV_MAJOR      42
   74 /* Don't make this static, since if_cx.c uses it. */
   75 struct cdevsw cx_cdevsw = {
   76         .d_open =       cxopen,
   77         .d_close =      cxclose,
   78         .d_read =       ttyread,
   79         .d_write =      ttywrite,
   80         .d_ioctl =      cxioctl,
   81         .d_poll =       ttypoll,
   82         .d_name =       "cx",
   83         .d_maj =        CDEV_MAJOR,
   84         .d_flags =      D_TTY,
   85         .d_kqfilter =   ttykqfilter,
   86 };
   87 
   88 static void cxoproc (struct tty *tp);
   89 static void cxstop (struct tty *tp, int flag);
   90 static int cxparam (struct tty *tp, struct termios *t);
   91 
   92 static int
   93 cxopen (dev_t dev, int flag, int mode, struct thread *td)
   94 {
   95         int unit = UNIT (dev);
   96         cx_chan_t *c = cxchan[unit];
   97         unsigned short port;
   98         struct tty *tp;
   99         int error = 0;
  100 
  101         if (unit == UNIT_CTL) {
  102                 print (("cx: cxopen /dev/cronyx\n"));
  103                 return (0);
  104         }
  105         if (unit >= NCX*NCHAN || !c || c->type==T_NONE)
  106                 return (ENXIO);
  107         port = c->chip->port;
  108         print (("cx%d.%d: cxopen unit=%d\n", c->board->num, c->num, unit));
  109         if (c->mode != M_ASYNC)
  110                 return (EBUSY);
  111         if (! c->ttyp) {
  112                 c->ttyp = &cx_tty[unit];
  113                 c->ttyp->t_oproc = cxoproc;
  114                 c->ttyp->t_stop = cxstop;
  115                 c->ttyp->t_param = cxparam;
  116         }
  117         dev->si_tty = c->ttyp;
  118         tp = c->ttyp;
  119         tp->t_dev = dev;
  120         if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
  121             suser(td))
  122                 return (EBUSY);
  123         if (! (tp->t_state & TS_ISOPEN)) {
  124                 ttychars (tp);
  125                 if (tp->t_ispeed == 0) {
  126                         tp->t_iflag = 0;
  127                         tp->t_oflag = 0;
  128                         tp->t_lflag = 0;
  129                         tp->t_cflag = CREAD | CS8 | HUPCL;
  130                         tp->t_ispeed = c->rxbaud;
  131                         tp->t_ospeed = c->txbaud;
  132                 }
  133                 cxparam (tp, &tp->t_termios);
  134                 ttsetwater (tp);
  135         }
  136 
  137         spltty ();
  138         if (! (tp->t_state & TS_ISOPEN)) {
  139                 /*
  140                  * Compute optimal receiver buffer length.
  141                  * The best choice is rxbaud/400.
  142                  * Make it even, to avoid byte-wide DMA transfers.
  143                  * --------------------------
  144                  * Baud rate    Buffer length
  145                  * --------------------------
  146                  *      300     4
  147                  *     1200     4
  148                  *     9600     24
  149                  *    19200     48
  150                  *    38400     96
  151                  *    57600     192
  152                  *   115200     288
  153                  * --------------------------
  154                  */
  155                 int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
  156                 if (rbsz < 4)
  157                         rbsz = 4;
  158                 else if (rbsz > DMABUFSZ)
  159                         rbsz = DMABUFSZ;
  160 
  161                 /* Initialize channel, enable receiver. */
  162                 cx_cmd (port, CCR_INITCH | CCR_ENRX);
  163                 cx_cmd (port, CCR_INITCH | CCR_ENRX);
  164 
  165                 /* Start receiver. */
  166                 outw (ARBCNT(port), rbsz);
  167                 outw (BRBCNT(port), rbsz);
  168                 outw (ARBSTS(port), BSTS_OWN24);
  169                 outw (BRBSTS(port), BSTS_OWN24);
  170 
  171                 /* Enable interrupts. */
  172                 outb (IER(port), IER_RXD | IER_RET | IER_TXD | IER_MDM);
  173 
  174                 cx_chan_dtr (c, 1);
  175                 cx_chan_rts (c, 1);
  176         }
  177         if (cx_chan_cd (c))
  178                 (*linesw[tp->t_line].l_modem)(tp, 1);
  179         if (! (flag & O_NONBLOCK)) {
  180                 /* Lock the channel against cxconfig while we are
  181                  * waiting for carrier. */
  182                 c->sopt.lock = 1;
  183                 while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON))
  184                         if ((error = tsleep (TSA_CARR_ON(tp), TTIPRI | PCATCH,
  185                             "cxdcd", 0)))
  186                                 break;
  187                 c->sopt.lock = 0;       /* Unlock the channel. */
  188         }
  189         print (("cx%d.%d: cxopen done csr=%b\n", c->board->num, c->num,
  190                 inb(CSR(c->chip->port)), CSRA_BITS));
  191         spl0 ();
  192         if (error)
  193                 return (error);
  194         error = (*linesw[tp->t_line].l_open) (dev, tp);
  195         return (error);
  196 }
  197 
  198 static int
  199 cxclose (dev_t dev, int flag, int mode, struct thread *td)
  200 {
  201         int unit = UNIT (dev);
  202         cx_chan_t *c = cxchan[unit];
  203         struct tty *tp;
  204         int s;
  205 
  206         if (unit == UNIT_CTL)
  207                 return (0);
  208         tp = c->ttyp;
  209         (*linesw[tp->t_line].l_close) (tp, flag);
  210 
  211         /* Disable receiver.
  212          * Transmitter continues sending the queued data. */
  213         s = spltty ();
  214         outb (CAR(c->chip->port), c->num & 3);
  215         outb (IER(c->chip->port), IER_TXD | IER_MDM);
  216         cx_cmd (c->chip->port, CCR_DISRX);
  217 
  218         /* Clear DTR and RTS. */
  219         if ((tp->t_cflag & HUPCL) || ! (tp->t_state & TS_ISOPEN)) {
  220                 cx_chan_dtr (c, 0);
  221                 cx_chan_rts (c, 0);
  222         }
  223 
  224         /* Stop sending break. */
  225         if (c->brk == BRK_SEND) {
  226                 c->brk = BRK_STOP;
  227                 if (! (tp->t_state & TS_BUSY))
  228                         cxoproc (tp);
  229         }
  230         splx (s);
  231         ttyclose (tp);
  232         return (0);
  233 }
  234 
  235 static int
  236 cxioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  237 {
  238         int unit = UNIT (dev);
  239         cx_chan_t *c, *m;
  240         cx_stat_t *st;
  241         struct tty *tp;
  242         int error, s;
  243         unsigned char msv;
  244         struct ifnet *master;
  245 
  246         if (unit == UNIT_CTL) {
  247                 /* Process an ioctl request on /dev/cronyx */
  248                 cx_options_t *o = (cx_options_t*) data;
  249 
  250                 if (o->board >= NCX || o->channel >= NCHAN)
  251                         return (EINVAL);
  252                 c = &cxboard[o->board].chan[o->channel];
  253                 if (c->type == T_NONE)
  254                         return (ENXIO);
  255                 switch (cmd) {
  256                 default:
  257                         return (EINVAL);
  258 
  259                 case CXIOCSETMODE:
  260                         print (("cx%d.%d: CXIOCSETMODE\n", o->board, o->channel));
  261                         if (c->type == T_NONE)
  262                                 return (EINVAL);
  263                         if (c->type == T_ASYNC && o->mode != M_ASYNC)
  264                                 return (EINVAL);
  265                         if (o->mode == M_ASYNC)
  266                                 switch (c->type) {
  267                                 case T_SYNC_RS232:
  268                                 case T_SYNC_V35:
  269                                 case T_SYNC_RS449:
  270                                         return (EINVAL);
  271                                 }
  272                         /* Somebody is waiting for carrier? */
  273                         if (c->sopt.lock)
  274                                 return (EBUSY);
  275                         /* /dev/ttyXX is already opened by someone? */
  276                         if (c->mode == M_ASYNC && c->ttyp &&
  277                             (c->ttyp->t_state & TS_ISOPEN))
  278                                 return (EBUSY);
  279                         /* Network interface is up? */
  280                         if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP))
  281                                 return (EBUSY);
  282 
  283                         /* Find the master interface. */
  284                         master = *o->master ? ifunit (o->master) : c->ifp;
  285                         if (! master)
  286                                 return (EINVAL);
  287                         m = cxchan[master->if_unit];
  288 
  289                         /* Leave the previous master queue. */
  290                         if (c->master != c->ifp) {
  291                                 cx_chan_t *p = cxchan[c->master->if_unit];
  292 
  293                                 for (; p; p=p->slaveq)
  294                                         if (p->slaveq == c)
  295                                                 p->slaveq = c->slaveq;
  296                         }
  297 
  298                         /* Set up new master. */
  299                         c->master = master;
  300                         c->slaveq = 0;
  301 
  302                         /* Join the new master queue. */
  303                         if (c->master != c->ifp) {
  304                                 c->slaveq = m->slaveq;
  305                                 m->slaveq = c;
  306                         }
  307 
  308                         c->mode   = o->mode;
  309                         c->rxbaud = o->rxbaud;
  310                         c->txbaud = o->txbaud;
  311                         c->opt    = o->opt;
  312                         c->aopt   = o->aopt;
  313                         c->hopt   = o->hopt;
  314                         c->bopt   = o->bopt;
  315                         c->xopt   = o->xopt;
  316                         switch (c->num) {
  317                         case 0: c->board->if0type = o->iftype; break;
  318                         case 8: c->board->if8type = o->iftype; break;
  319                         }
  320                         s = spltty ();
  321                         cxswitch (c, o->sopt);
  322                         cx_setup_chan (c);
  323                         outb (IER(c->chip->port), 0);
  324                         splx (s);
  325                         break;
  326 
  327                 case CXIOCGETSTAT:
  328                         st = (cx_stat_t*) data;
  329                         st->rintr  = c->stat->rintr;
  330                         st->tintr  = c->stat->tintr;
  331                         st->mintr  = c->stat->mintr;
  332                         st->ibytes = c->stat->ibytes;
  333                         st->ipkts  = c->stat->ipkts;
  334                         st->ierrs  = c->stat->ierrs;
  335                         st->obytes = c->stat->obytes;
  336                         st->opkts  = c->stat->opkts;
  337                         st->oerrs  = c->stat->oerrs;
  338                         break;
  339 
  340                 case CXIOCGETMODE:
  341                         print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel));
  342                         o->type   = c->type;
  343                         o->mode   = c->mode;
  344                         o->rxbaud = c->rxbaud;
  345                         o->txbaud = c->txbaud;
  346                         o->opt    = c->opt;
  347                         o->aopt   = c->aopt;
  348                         o->hopt   = c->hopt;
  349                         o->bopt   = c->bopt;
  350                         o->xopt   = c->xopt;
  351                         o->sopt   = c->sopt;
  352                         switch (c->num) {
  353                         case 0: o->iftype = c->board->if0type; break;
  354                         case 8: o->iftype = c->board->if8type; break;
  355                         }
  356                         if (c->master != c->ifp)
  357                                 snprintf (o->master, sizeof(o->master),
  358                                     "%s%d", c->master->if_name,
  359                                         c->master->if_unit);
  360                         else
  361                                 *o->master = 0;
  362                         break;
  363                 }
  364                 return (0);
  365         }
  366 
  367         c = cxchan[unit];
  368         tp = c->ttyp;
  369         if (! tp)
  370                 return (EINVAL);
  371         error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, td);
  372         if (error != ENOIOCTL)
  373                 return (error);
  374         error = ttioctl (tp, cmd, data, flag);
  375         if (error != ENOIOCTL)
  376                 return (error);
  377 
  378         s = spltty ();
  379         switch (cmd) {
  380         default:
  381                 splx (s);
  382                 return (ENOTTY);
  383         case TIOCSBRK:          /* Start sending line break */
  384                 c->brk = BRK_SEND;
  385                 if (! (tp->t_state & TS_BUSY))
  386                         cxoproc (tp);
  387                 break;
  388         case TIOCCBRK:          /* Stop sending line break */
  389                 c->brk = BRK_STOP;
  390                 if (! (tp->t_state & TS_BUSY))
  391                         cxoproc (tp);
  392                 break;
  393         case TIOCSDTR:          /* Set DTR */
  394                 cx_chan_dtr (c, 1);
  395                 break;
  396         case TIOCCDTR:          /* Clear DTR */
  397                 cx_chan_dtr (c, 0);
  398                 break;
  399         case TIOCMSET:          /* Set DTR/RTS */
  400                 cx_chan_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
  401                 cx_chan_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
  402                 break;
  403         case TIOCMBIS:          /* Add DTR/RTS */
  404                 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 1);
  405                 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 1);
  406                 break;
  407         case TIOCMBIC:          /* Clear DTR/RTS */
  408                 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 0);
  409                 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 0);
  410                 break;
  411         case TIOCMGET:          /* Get modem status */
  412                 msv = inb (MSVR(c->chip->port));
  413                 *(int*)data = TIOCM_LE; /* always enabled while open */
  414                 if (msv & MSV_DSR) *(int*)data |= TIOCM_DSR;
  415                 if (msv & MSV_CTS) *(int*)data |= TIOCM_CTS;
  416                 if (msv & MSV_CD)  *(int*)data |= TIOCM_CD;
  417                 if (c->dtr)        *(int*)data |= TIOCM_DTR;
  418                 if (c->rts)        *(int*)data |= TIOCM_RTS;
  419                 break;
  420         }
  421         splx (s);
  422         return (0);
  423 }
  424 
  425 /*
  426  * Fill transmitter buffer with data.
  427  */
  428 static void
  429 cxout (cx_chan_t *c, char b)
  430 {
  431         unsigned char *buf, *p, sym;
  432         unsigned short port = c->chip->port, len = 0, cnt_port, sts_port;
  433         struct tty *tp = c->ttyp;
  434 
  435         if (! tp)
  436                 return;
  437 
  438         /* Choose the buffer. */
  439         if (b == 'A') {
  440                 buf      = c->atbuf;
  441                 cnt_port = ATBCNT(port);
  442                 sts_port = ATBSTS(port);
  443         } else {
  444                 buf      = c->btbuf;
  445                 cnt_port = BTBCNT(port);
  446                 sts_port = BTBSTS(port);
  447         }
  448 
  449         /* Is it busy? */
  450         if (inb (sts_port) & BSTS_OWN24) {
  451                 tp->t_state |= TS_BUSY;
  452                 return;
  453         }
  454 
  455         switch (c->brk) {
  456         case BRK_SEND:
  457                 *buf++ = 0;     /* extended transmit command */
  458                 *buf++ = 0x81;  /* send break */
  459                 *buf++ = 0;     /* extended transmit command */
  460                 *buf++ = 0x82;  /* insert delay */
  461                 *buf++ = 250;   /* 1/4 of second */
  462                 *buf++ = 0;     /* extended transmit command */
  463                 *buf++ = 0x82;  /* insert delay */
  464                 *buf++ = 250;   /* + 1/4 of second */
  465                 len = 8;
  466                 c->brk = BRK_IDLE;
  467                 break;
  468         case BRK_STOP:
  469                 *buf++ = 0;     /* extended transmit command */
  470                 *buf++ = 0x83;  /* stop break */
  471                 len = 2;
  472                 c->brk = BRK_IDLE;
  473                 break;
  474         case BRK_IDLE:
  475                 p = buf;
  476                 if (tp->t_iflag & IXOFF)
  477                         while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
  478                                 sym = RB_GETC (tp->t_out);
  479                                 /* Send XON/XOFF out of band. */
  480                                 if (sym == tp->t_cc[VSTOP]) {
  481                                         outb (STCR(port), STC_SNDSPC|STC_SSPC_2);
  482                                         continue;
  483                                 }
  484                                 if (sym == tp->t_cc[VSTART]) {
  485                                         outb (STCR(port), STC_SNDSPC|STC_SSPC_1);
  486                                         continue;
  487                                 }
  488                                 /* Duplicate NULLs in ETC mode. */
  489                                 if (! sym)
  490                                         *p++ = 0;
  491                                 *p++ = sym;
  492                         }
  493                 else
  494                         while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
  495                                 sym = RB_GETC (tp->t_out);
  496                                 /* Duplicate NULLs in ETC mode. */
  497                                 if (! sym)
  498                                         *p++ = 0;
  499                                 *p++ = sym;
  500                         }
  501                 len = p - buf;
  502                 break;
  503         }
  504 
  505         /* Start transmitter. */
  506         if (len) {
  507                 outw (cnt_port, len);
  508                 outb (sts_port, BSTS_INTR | BSTS_OWN24);
  509                 c->stat->obytes += len;
  510                 tp->t_state |= TS_BUSY;
  511                 print (("cx%d.%d: out %d bytes to %c\n",
  512                         c->board->num, c->num, len, b));
  513         }
  514 }
  515 
  516 static void
  517 cxoproc (struct tty *tp)
  518 {
  519         int unit = UNIT (tp->t_dev);
  520         cx_chan_t *c = cxchan[unit];
  521         unsigned short port = c->chip->port;
  522         int s = spltty ();
  523 
  524         /* Set current channel number */
  525         outb (CAR(port), c->num & 3);
  526 
  527         if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
  528                 /* Start transmitter. */
  529                 if (! (inb (CSR(port)) & CSRA_TXEN))
  530                         cx_cmd (port, CCR_ENTX);
  531 
  532                 /* Determine the buffer order. */
  533                 if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
  534                         cxout (c, 'B');
  535                         cxout (c, 'A');
  536                 } else {
  537                         cxout (c, 'A');
  538                         cxout (c, 'B');
  539                 }
  540         }
  541 #ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */
  542         ttwwakeup(tp);
  543 #else
  544         if (RB_LEN (tp->t_out) <= tp->t_lowat) {
  545                 if (tp->t_state & TS_ASLEEP) {
  546                         tp->t_state &= ~TS_ASLEEP;
  547                         wakeup(TSA_OLOWAT(tp));
  548                 }
  549                 selwakeup(&tp->t_wsel);
  550         }
  551 #endif
  552         splx (s);
  553 }
  554 
  555 static int
  556 cxparam (struct tty *tp, struct termios *t)
  557 {
  558         int unit = UNIT (tp->t_dev);
  559         cx_chan_t *c = cxchan[unit];
  560         unsigned short port = c->chip->port;
  561         int clock, period, s;
  562         cx_cor1_async_t cor1;
  563 
  564         if (t->c_ospeed == 0) {
  565                 /* Clear DTR and RTS. */
  566                 s = spltty ();
  567                 cx_chan_dtr (c, 0);
  568                 cx_chan_rts (c, 0);
  569                 splx (s);
  570                 print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num));
  571                 return (0);
  572         }
  573         print (("cx%d.%d: cxparam\n", c->board->num, c->num));
  574 
  575         /* Check requested parameters. */
  576         if (t->c_ospeed < 300 || t->c_ospeed > 256*1024)
  577                 return(EINVAL);
  578         if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024))
  579                 return(EINVAL);
  580 
  581         /* And copy them to tty and channel structures. */
  582         c->rxbaud = tp->t_ispeed = t->c_ispeed;
  583         c->txbaud = tp->t_ospeed = t->c_ospeed;
  584         tp->t_cflag = t->c_cflag;
  585 
  586         /* Set character length and parity mode. */
  587         BYTE cor1 = 0;
  588         switch (t->c_cflag & CSIZE) {
  589         default:
  590         case CS8: cor1.charlen = 7; break;
  591         case CS7: cor1.charlen = 6; break;
  592         case CS6: cor1.charlen = 5; break;
  593         case CS5: cor1.charlen = 4; break;
  594         }
  595         if (t->c_cflag & PARENB) {
  596                 cor1.parmode = PARM_NORMAL;
  597                 cor1.ignpar = 0;
  598                 cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN;
  599         } else {
  600                 cor1.parmode = PARM_NOPAR;
  601                 cor1.ignpar = 1;
  602         }
  603 
  604         /* Enable/disable hardware CTS. */
  605         c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0;
  606         /* Handle DSR as CTS. */
  607         c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0;
  608         /* Enable extended transmit command mode.
  609          * Unfortunately, there is no other method for sending break. */
  610         c->aopt.cor2.etc = 1;
  611         /* Enable/disable hardware XON/XOFF. */
  612         c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0;
  613         c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0;
  614 
  615         /* Set the number of stop bits. */
  616         if (t->c_cflag & CSTOPB)
  617                 c->aopt.cor3.stopb = STOPB_2;
  618         else
  619                 c->aopt.cor3.stopb = STOPB_1;
  620         /* Disable/enable passing XON/XOFF chars to the host. */
  621         c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0;
  622         c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS;
  623 
  624         c->aopt.schr1 = t->c_cc[VSTART];        /* XON */
  625         c->aopt.schr2 = t->c_cc[VSTOP];         /* XOFF */
  626 
  627         /* Set current channel number. */
  628         s = spltty ();
  629         outb (CAR(port), c->num & 3);
  630 
  631         /* Set up receiver clock values. */
  632         cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
  633         c->opt.rcor.clk = clock;
  634         outb (RCOR(port), BYTE c->opt.rcor);
  635         outb (RBPR(port), period);
  636 
  637         /* Set up transmitter clock values. */
  638         cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
  639         c->opt.tcor.clk = clock;
  640         c->opt.tcor.ext1x = 0;
  641         outb (TCOR(port), BYTE c->opt.tcor);
  642         outb (TBPR(port), period);
  643 
  644         outb (COR2(port), BYTE c->aopt.cor2);
  645         outb (COR3(port), BYTE c->aopt.cor3);
  646         outb (SCHR1(port), c->aopt.schr1);
  647         outb (SCHR2(port), c->aopt.schr2);
  648 
  649         if (BYTE c->aopt.cor1 != BYTE cor1) {
  650                 BYTE c->aopt.cor1 = BYTE cor1;
  651                 outb (COR1(port), BYTE c->aopt.cor1);
  652                 /* Any change to COR1 require reinitialization. */
  653                 /* Unfortunately, it may cause transmitter glitches... */
  654                 cx_cmd (port, CCR_INITCH);
  655         }
  656         splx (s);
  657         return (0);
  658 }
  659 
  660 /*
  661  * Stop output on a line
  662  */
  663 static void
  664 cxstop (struct tty *tp, int flag)
  665 {
  666         cx_chan_t *c = cxchan[UNIT(tp->t_dev)];
  667         unsigned short port = c->chip->port;
  668         int s = spltty ();
  669 
  670         if (tp->t_state & TS_BUSY) {
  671                 print (("cx%d.%d: cxstop\n", c->board->num, c->num));
  672 
  673                 /* Set current channel number */
  674                 outb (CAR(port), c->num & 3);
  675 
  676                 /* Stop transmitter */
  677                 cx_cmd (port, CCR_DISTX);
  678         }
  679         splx (s);
  680 }
  681 
  682 /*
  683  * Handle receive interrupts, including receive errors and
  684  * receive timeout interrupt.
  685  */
  686 int cxrinta (cx_chan_t *c)
  687 {
  688         unsigned short port = c->chip->port;
  689         unsigned short len = 0, risr = inw (RISR(port)), reoir = 0;
  690         struct tty *tp = c->ttyp;
  691 
  692         /* Compute optimal receiver buffer length. */
  693         int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
  694         if (rbsz < 4)
  695                 rbsz = 4;
  696         else if (rbsz > DMABUFSZ)
  697                 rbsz = DMABUFSZ;
  698 
  699         if (risr & RISA_TIMEOUT) {
  700                 unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) |
  701                         (long) inw (RCBADRU(port)) << 16;
  702                 unsigned char *buf = 0;
  703                 unsigned short cnt_port = 0, sts_port = 0;
  704                 if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
  705                         buf = c->brbuf;
  706                         len = rcbadr - c->brphys;
  707                         cnt_port = BRBCNT(port);
  708                         sts_port = BRBSTS(port);
  709                 } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
  710                         buf = c->arbuf;
  711                         len = rcbadr - c->arphys;
  712                         cnt_port = ARBCNT(port);
  713                         sts_port = ARBSTS(port);
  714                 } else
  715                         printf ("cx%d.%d: timeout: invalid buffer address\n",
  716                                 c->board->num, c->num);
  717 
  718                 if (len) {
  719                         print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
  720                                 c->board->num, c->num, len, risr, RISA_BITS,
  721                                 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
  722                         c->stat->ibytes += len;
  723                         if (tp && (tp->t_state & TS_ISOPEN)) {
  724                                 int i;
  725                                 int (*rint)(int, struct tty *) =
  726                                         linesw[tp->t_line].l_rint;
  727 
  728                                 for (i=0; i<len; ++i)
  729                                         (*rint) (buf[i], tp);
  730                         }
  731 
  732                         /* Restart receiver. */
  733                         outw (cnt_port, rbsz);
  734                         outb (sts_port, BSTS_OWN24);
  735                 }
  736                 return (REOI_TERMBUFF);
  737         }
  738 
  739         print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
  740                 c->board->num, c->num, risr, RISA_BITS,
  741                 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
  742 
  743         if (risr & RIS_BUSERR) {
  744                 printf ("cx%d.%d: receive bus error\n", c->board->num, c->num);
  745                 ++c->stat->ierrs;
  746         }
  747         if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) {
  748                 int err = 0;
  749 
  750                 if (risr & RISA_PARERR)
  751                         err |= TTY_PE;
  752                 if (risr & RISA_FRERR)
  753                         err |= TTY_FE;
  754 #ifdef TTY_OE
  755                 if (risr & RIS_OVERRUN)
  756                         err |= TTY_OE;
  757 #endif
  758 #ifdef TTY_BI
  759                 if (risr & RISA_BREAK)
  760                         err |= TTY_BI;
  761 #endif
  762                 print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err));
  763                 if (tp && (tp->t_state & TS_ISOPEN))
  764                         (*linesw[tp->t_line].l_rint) (err, tp);
  765                 ++c->stat->ierrs;
  766         }
  767 
  768         /* Discard exception characters. */
  769         if ((risr & RISA_SCMASK) && tp && (tp->t_iflag & IXON))
  770                 reoir |= REOI_DISCEXC;
  771 
  772         /* Handle received data. */
  773         if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) {
  774                 int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
  775                 unsigned char *buf;
  776                 int i;
  777 
  778                 len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
  779 
  780                 print (("cx%d.%d: async: %d bytes received\n",
  781                         c->board->num, c->num, len));
  782                 c->stat->ibytes += len;
  783 
  784                 buf = (risr & RIS_BB) ? c->brbuf : c->arbuf;
  785                 for (i=0; i<len; ++i)
  786                         (*rint) (buf[i], tp);
  787         }
  788 
  789         /* Restart receiver. */
  790         if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
  791                 outw (ARBCNT(port), rbsz);
  792                 outb (ARBSTS(port), BSTS_OWN24);
  793         }
  794         if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
  795                 outw (BRBCNT(port), rbsz);
  796                 outb (BRBSTS(port), BSTS_OWN24);
  797         }
  798         return (reoir);
  799 }
  800 
  801 /*
  802  * Handle transmit interrupt.
  803  */
  804 void cxtinta (cx_chan_t *c)
  805 {
  806         struct tty *tp = c->ttyp;
  807         unsigned short port = c->chip->port;
  808         unsigned char tisr = inb (TISR(port));
  809 
  810         print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
  811                 c->board->num, c->num, tisr, TIS_BITS,
  812                 inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
  813 
  814         if (tisr & TIS_BUSERR) {
  815                 printf ("cx%d.%d: transmit bus error\n",
  816                         c->board->num, c->num);
  817                 ++c->stat->oerrs;
  818         } else if (tisr & TIS_UNDERRUN) {
  819                 printf ("cx%d.%d: transmit underrun error\n",
  820                         c->board->num, c->num);
  821                 ++c->stat->oerrs;
  822         }
  823         if (tp) {
  824                 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
  825                 if (tp->t_line)
  826                         (*linesw[tp->t_line].l_start) (tp);
  827                 else
  828                         cxoproc (tp);
  829         }
  830 }
  831 
  832 /*
  833  * Handle modem interrupt.
  834  */
  835 void cxmint (cx_chan_t *c)
  836 {
  837         unsigned short port = c->chip->port;
  838         unsigned char misr = inb (MISR(port));
  839         unsigned char msvr = inb (MSVR(port));
  840         struct tty *tp = c->ttyp;
  841 
  842         if (c->mode != M_ASYNC) {
  843                 printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n",
  844                         c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS);
  845                 return;
  846         }
  847         print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n",
  848                 c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS));
  849 
  850         /* Ignore DSR events. */
  851         /* Ignore RTC/CTS events, handled by hardware. */
  852         /* Handle carrier detect/loss. */
  853         if (tp && (misr & MIS_CCD))
  854                 (*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);
  855 }
  856 
  857 /*
  858  * Recover after lost transmit interrupts.
  859  */
  860 void cxtimeout (void *a)
  861 {
  862         cx_board_t *b;
  863         cx_chan_t *c;
  864         struct tty *tp;
  865         int s;
  866 
  867         for (b=cxboard; b<cxboard+NCX; ++b)
  868                 for (c=b->chan; c<b->chan+NCHAN; ++c) {
  869                         tp = c->ttyp;
  870                         if (c->type==T_NONE || c->mode!=M_ASYNC || !tp)
  871                                 continue;
  872                         s = spltty ();
  873                         if (tp->t_state & TS_BUSY) {
  874                                 tp->t_state &= ~TS_BUSY;
  875                                 if (tp->t_line)
  876                                         (*linesw[tp->t_line].l_start) (tp);
  877                                 else
  878                                         cxoproc (tp);
  879                         }
  880                         splx (s);
  881                 }
  882         timeout (cxtimeout, 0, hz*5);
  883 }

Cache object: e955b665177072d8281b6457987249f0


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