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

Cache object: 0d46c727e9fc671c2b8f0df14ce6f6e6


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