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

Cache object: 29df8ca2087ba93b0def766ab659a813


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