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/dev/cx/if_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 and Cisco/HDLC protocol in synchronous mode,
    4  * and asyncronous channels with full modem control.
    5  * Keepalive protocol implemented in both Cisco and PPP modes.
    6  *
    7  * Copyright (C) 1994-2002 Cronyx Engineering.
    8  * Author: Serge Vakulenko, <vak@cronyx.ru>
    9  *
   10  * Copyright (C) 1999-2004 Cronyx Engineering.
   11  * Rewritten on DDK, ported to NETGRAPH, rewritten for FreeBSD 3.x-5.x by
   12  * Kurakin Roman, <rik@cronyx.ru>
   13  *
   14  * This software is distributed with NO WARRANTIES, not even the implied
   15  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   16  *
   17  * Authors grant any other persons or organisations a permission to use,
   18  * modify and redistribute this software in source and binary forms,
   19  * as long as this message is kept with the software, all derivative
   20  * works or modified versions.
   21  *
   22  * Cronyx Id: if_cx.c,v 1.1.2.34 2004/06/23 17:09:13 rik Exp $
   23  */
   24 
   25 #include <sys/cdefs.h>
   26 __FBSDID("$FreeBSD: releng/9.0/sys/dev/cx/if_cx.c 207554 2010-05-03 07:32:50Z sobomax $");
   27 
   28 #include <sys/param.h>
   29 
   30 #include <sys/systm.h>
   31 #include <sys/kernel.h>
   32 #include <sys/module.h>
   33 #include <sys/priv.h>
   34 #include <sys/proc.h>
   35 #include <sys/mbuf.h>
   36 #include <sys/sockio.h>
   37 #include <sys/malloc.h>
   38 #include <sys/socket.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/conf.h>
   41 #include <sys/errno.h>
   42 #include <sys/serial.h>
   43 #include <sys/tty.h>
   44 #include <sys/bus.h>
   45 #include <machine/bus.h>
   46 #include <sys/rman.h>
   47 #include <isa/isavar.h>
   48 #include <sys/fcntl.h>
   49 #include <sys/interrupt.h>
   50 #include <vm/vm.h>
   51 #include <vm/pmap.h>
   52 #include <net/if.h>
   53 #include <machine/cpufunc.h>
   54 #include <machine/cserial.h>
   55 #include <machine/resource.h>
   56 #include <dev/cx/machdep.h>
   57 #include <dev/cx/cxddk.h>
   58 #include <dev/cx/cronyxfw.h>
   59 #include "opt_ng_cronyx.h"
   60 #ifdef NETGRAPH_CRONYX
   61 #   include "opt_netgraph.h"
   62 #   include <netgraph/ng_message.h>
   63 #   include <netgraph/netgraph.h>
   64 #   include <dev/cx/ng_cx.h>
   65 #else
   66 #   include <net/if_types.h>
   67 #   include <net/if_sppp.h>
   68 #   define PP_CISCO IFF_LINK2
   69 #   include <net/bpf.h>
   70 #endif
   71 
   72 #define NCX     1
   73 
   74 /* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
   75 #ifndef PP_FR
   76 #define PP_FR 0
   77 #endif
   78 
   79 #define CX_DEBUG(d,s)   ({if (d->chan->debug) {\
   80                                 printf ("%s: ", d->name); printf s;}})
   81 #define CX_DEBUG2(d,s)  ({if (d->chan->debug>1) {\
   82                                 printf ("%s: ", d->name); printf s;}})
   83 
   84 #define CX_LOCK_NAME    "cxX"
   85 
   86 #define CX_LOCK(_bd)            mtx_lock (&(_bd)->cx_mtx)
   87 #define CX_UNLOCK(_bd)          mtx_unlock (&(_bd)->cx_mtx)
   88 #define CX_LOCK_ASSERT(_bd)     mtx_assert (&(_bd)->cx_mtx, MA_OWNED)
   89 
   90 typedef struct _async_q {
   91         int beg;
   92         int end;
   93         #define BF_SZ 14400
   94         int buf[BF_SZ+1];
   95 } async_q;
   96 
   97 #define AQ_GSZ(q)       ((BF_SZ + (q)->end - (q)->beg)%BF_SZ)
   98 #define AQ_PUSH(q,c)    {*((q)->buf + (q)->end) = c;\
   99                         (q)->end = ((q)->end + 1)%BF_SZ;}
  100 #define AQ_POP(q,c)     {c = *((q)->buf + (q)->beg);\
  101                         (q)->beg = ((q)->beg + 1)%BF_SZ;}
  102 
  103 static void cx_identify         __P((driver_t *, device_t));
  104 static int cx_probe             __P((device_t));
  105 static int cx_attach            __P((device_t));
  106 static int cx_detach            __P((device_t));
  107 static t_open_t                 cx_topen;
  108 static t_modem_t                cx_tmodem;
  109 static t_close_t                cx_tclose;
  110 
  111 static device_method_t cx_isa_methods [] = {
  112         DEVMETHOD(device_identify,      cx_identify),
  113         DEVMETHOD(device_probe,         cx_probe),
  114         DEVMETHOD(device_attach,        cx_attach),
  115         DEVMETHOD(device_detach,        cx_detach),
  116         {0, 0}
  117 };
  118 
  119 typedef struct _cx_dma_mem_t {
  120         unsigned long   phys;
  121         void            *virt;
  122         size_t          size;
  123         bus_dma_tag_t   dmat;
  124         bus_dmamap_t    mapp;
  125 } cx_dma_mem_t;
  126 
  127 typedef struct _drv_t {
  128         char name [8];
  129         cx_chan_t *chan;
  130         cx_board_t *board;
  131         cx_dma_mem_t dmamem;
  132         struct tty *tty;
  133         struct callout dcd_timeout_handle;
  134         unsigned callout;
  135         unsigned lock;
  136         int open_dev;
  137         int cd;
  138         int running;
  139 #ifdef NETGRAPH
  140         char    nodename [NG_NODESIZ];
  141         hook_p  hook;
  142         hook_p  debug_hook;
  143         node_p  node;
  144         struct  ifqueue lo_queue;
  145         struct  ifqueue hi_queue;
  146 #else
  147         struct  ifqueue queue;
  148         struct  ifnet *ifp;
  149 #endif
  150         short   timeout;
  151         struct  callout timeout_handle;
  152         struct  cdev *devt;
  153         async_q aqueue;
  154 #define CX_READ 1
  155 #define CX_WRITE 2
  156         int intr_action;
  157         short atimeout;
  158 } drv_t;
  159 
  160 typedef struct _bdrv_t {
  161         cx_board_t      *board;
  162         struct resource *base_res;
  163         struct resource *drq_res;
  164         struct resource *irq_res;
  165         int             base_rid;
  166         int             drq_rid;
  167         int             irq_rid;
  168         void            *intrhand;
  169         drv_t           channel [NCHAN];
  170         struct mtx      cx_mtx;
  171 } bdrv_t;
  172 
  173 static driver_t cx_isa_driver = {
  174         "cx",
  175         cx_isa_methods,
  176         sizeof (bdrv_t),
  177 };
  178 
  179 static devclass_t cx_devclass;
  180 
  181 extern long csigma_fw_len;
  182 extern const char *csigma_fw_version;
  183 extern const char *csigma_fw_date;
  184 extern const char *csigma_fw_copyright;
  185 extern const cr_dat_tst_t csigma_fw_tvec[];
  186 extern const u_char csigma_fw_data[];
  187 static void cx_oproc (struct tty *tp);
  188 static int cx_param (struct tty *tp, struct termios *t);
  189 static void cx_stop (struct tty *tp, int flag);
  190 static void cx_receive (cx_chan_t *c, char *data, int len);
  191 static void cx_transmit (cx_chan_t *c, void *attachment, int len);
  192 static void cx_error (cx_chan_t *c, int data);
  193 static void cx_modem (cx_chan_t *c);
  194 static void cx_up (drv_t *d);
  195 static void cx_start (drv_t *d);
  196 static void cx_softintr (void *);
  197 static void *cx_fast_ih;
  198 static void cx_down (drv_t *d);
  199 static void cx_watchdog (drv_t *d);
  200 static void cx_watchdog_timer (void *arg);
  201 static void cx_carrier (void *arg);
  202 
  203 #ifdef NETGRAPH
  204 extern struct ng_type typestruct;
  205 #else
  206 static void cx_ifstart (struct ifnet *ifp);
  207 static void cx_tlf (struct sppp *sp);
  208 static void cx_tls (struct sppp *sp);
  209 static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
  210 static void cx_initialize (void *softc);
  211 #endif
  212 
  213 static cx_board_t *adapter [NCX];
  214 static drv_t *channel [NCX*NCHAN];
  215 static struct callout led_timo [NCX];
  216 static struct callout timeout_handle;
  217 
  218 static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td);
  219 static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td);
  220 static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
  221 static struct cdevsw cx_cdevsw = {
  222         .d_version  = D_VERSION,
  223         .d_open     = cx_open,
  224         .d_close    = cx_close,
  225         .d_ioctl    = cx_ioctl,
  226         .d_name     = "cx",
  227         .d_flags    = D_TTY,
  228 };
  229 
  230 static int MY_SOFT_INTR;
  231 
  232 /*
  233  * Print the mbuf chain, for debug purposes only.
  234  */
  235 static void printmbuf (struct mbuf *m)
  236 {
  237         printf ("mbuf:");
  238         for (; m; m=m->m_next) {
  239                 if (m->m_flags & M_PKTHDR)
  240                         printf (" HDR %d:", m->m_pkthdr.len);
  241                 if (m->m_flags & M_EXT)
  242                         printf (" EXT:");
  243                 printf (" %d", m->m_len);
  244         }
  245         printf ("\n");
  246 }
  247 
  248 /*
  249  * Make an mbuf from data.
  250  */
  251 static struct mbuf *makembuf (void *buf, u_int len)
  252 {
  253         struct mbuf *m, *o, *p;
  254 
  255         MGETHDR (m, M_DONTWAIT, MT_DATA);
  256 
  257         if (! m)
  258                 return 0;
  259 
  260         if (len >= MINCLSIZE)
  261                 MCLGET (m, M_DONTWAIT);
  262 
  263         m->m_pkthdr.len = len;
  264         m->m_len = 0;
  265 
  266         p = m;
  267         while (len) {
  268                 u_int n = M_TRAILINGSPACE (p);
  269                 if (n > len)
  270                         n = len;
  271                 if (! n) {
  272                         /* Allocate new mbuf. */
  273                         o = p;
  274                         MGET (p, M_DONTWAIT, MT_DATA);
  275                         if (! p) {
  276                                 m_freem (m);
  277                                 return 0;
  278                         }
  279                         if (len >= MINCLSIZE)
  280                                 MCLGET (p, M_DONTWAIT);
  281                         p->m_len = 0;
  282                         o->m_next = p;
  283 
  284                         n = M_TRAILINGSPACE (p);
  285                         if (n > len)
  286                                 n = len;
  287                 }
  288                 bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
  289 
  290                 p->m_len += n;
  291                 buf = n + (char*) buf;
  292                 len -= n;
  293         }
  294         return m;
  295 }
  296 
  297 /*
  298  * Recover after lost transmit interrupts.
  299  */
  300 static void cx_timeout (void *arg)
  301 {
  302         drv_t *d;
  303         int s, i, k;
  304 
  305         for (i = 0; i < NCX; i++) {
  306                 if (adapter[i] == NULL)
  307                         continue;
  308                 for (k = 0; k < NCHAN; ++k) {
  309                         d = channel[i * NCHAN + k];
  310                         if (! d)
  311                                 continue;
  312                         s = splhigh ();
  313                         CX_LOCK ((bdrv_t *)d->board->sys);
  314                         if (d->atimeout == 1 && d->tty && d->tty->t_state & TS_BUSY) {
  315                                 d->tty->t_state &= ~TS_BUSY;
  316                                 if (d->tty->t_dev) {
  317                                         d->intr_action |= CX_WRITE;
  318                                         MY_SOFT_INTR = 1;
  319                                         swi_sched (cx_fast_ih, 0);
  320                                 }
  321                                 CX_DEBUG (d, ("cx_timeout\n"));
  322                         }
  323                         if (d->atimeout)
  324                                 d->atimeout--;
  325                         CX_UNLOCK ((bdrv_t *)d->board->sys);
  326                         splx (s);
  327                 }
  328         }
  329         callout_reset (&timeout_handle, hz*5, cx_timeout, 0);
  330 }
  331 
  332 static void cx_led_off (void *arg)
  333 {
  334         cx_board_t *b = arg;
  335         bdrv_t *bd = b->sys;
  336         int s;
  337 
  338         s = splhigh ();
  339         CX_LOCK (bd);
  340         cx_led (b, 0);
  341         CX_UNLOCK (bd);
  342         splx (s);
  343 }
  344 
  345 /*
  346  * Activate interrupt handler from DDK.
  347  */
  348 static void cx_intr (void *arg)
  349 {
  350         bdrv_t *bd = arg;
  351         cx_board_t *b = bd->board;
  352 #ifndef NETGRAPH
  353         int i;
  354 #endif
  355         int s = splhigh ();
  356 
  357         CX_LOCK (bd);
  358         /* Turn LED on. */
  359         cx_led (b, 1);
  360 
  361         cx_int_handler (b);
  362 
  363         /* Turn LED off 50 msec later. */
  364         callout_reset (&led_timo[b->num], hz/20, cx_led_off, b);
  365         CX_UNLOCK (bd);
  366         splx (s);
  367 
  368 #ifndef NETGRAPH
  369         /* Pass packets in a lock-free state */
  370         for (i = 0; i < NCHAN && b->chan[i].type; i++) {
  371                 drv_t *d = b->chan[i].sys;
  372                 struct mbuf *m;
  373                 if (!d || !d->running)
  374                         continue;
  375                 while (_IF_QLEN(&d->queue)) {
  376                         IF_DEQUEUE (&d->queue,m);
  377                         if (!m)
  378                                 continue;
  379                         sppp_input (d->ifp, m); 
  380                 }
  381         }
  382 #endif
  383 }
  384 
  385 static int probe_irq (cx_board_t *b, int irq)
  386 {
  387         int mask, busy, cnt;
  388 
  389         /* Clear pending irq, if any. */
  390         cx_probe_irq (b, -irq);
  391         DELAY (100);
  392         for (cnt=0; cnt<5; ++cnt) {
  393                 /* Get the mask of pending irqs, assuming they are busy.
  394                  * Activate the adapter on given irq. */
  395                 busy = cx_probe_irq (b, irq);
  396                 DELAY (100);
  397 
  398                 /* Get the mask of active irqs.
  399                  * Deactivate our irq. */
  400                 mask = cx_probe_irq (b, -irq);
  401                 DELAY (100);
  402                 if ((mask & ~busy) == 1 << irq) {
  403                         cx_probe_irq (b, 0);
  404                         /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
  405                                 b->num, irq, mask, busy); */
  406                         return 1;
  407                 }
  408         }
  409         /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
  410                 b->num, irq, mask, busy); */
  411         cx_probe_irq (b, 0);
  412         return 0;
  413 }
  414 
  415 static short porttab [] = {
  416         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
  417         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
  418 };
  419 static char dmatab [] = { 7, 6, 5, 0 };
  420 static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
  421 
  422 static int cx_is_free_res (device_t dev, int rid, int type, u_long start,
  423         u_long end, u_long count)
  424 {
  425         struct resource *res;
  426         
  427         if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
  428             RF_ALLOCATED)))
  429                 return 0;
  430                 
  431         bus_release_resource (dev, type, rid, res);
  432         
  433         return 1;
  434 }
  435 
  436 static void cx_identify (driver_t *driver, device_t dev)
  437 {
  438         u_long iobase, rescount;
  439         int devcount;
  440         device_t *devices;
  441         device_t child;
  442         devclass_t my_devclass;
  443         int i, k;
  444 
  445         if ((my_devclass = devclass_find ("cx")) == NULL)
  446                 return;
  447 
  448         devclass_get_devices (my_devclass, &devices, &devcount);
  449 
  450         if (devcount == 0) {
  451                 /* We should find all devices by our self. We could alter other
  452                  * devices, but we don't have a choise
  453                  */
  454                 for (i = 0; (iobase = porttab [i]) != 0; i++) {
  455                         if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT,
  456                             iobase, iobase + NPORT, NPORT))
  457                                 continue;
  458                         if (cx_probe_board (iobase, -1, -1) == 0)
  459                                 continue;
  460                         
  461                         devcount++;
  462 
  463                         child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "cx",
  464                             -1);
  465 
  466                         if (child == NULL)
  467                                 return;
  468 
  469                         device_set_desc_copy (child, "Cronyx Sigma");
  470                         device_set_driver (child, driver);
  471                         bus_set_resource (child, SYS_RES_IOPORT, 0,
  472                             iobase, NPORT);
  473 
  474                         if (devcount >= NCX)
  475                                 break;
  476                 }
  477         } else {
  478                 static short porttab [] = {
  479                         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
  480                         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
  481                 };
  482                 /* Lets check user choise.
  483                  */
  484                 for (k = 0; k < devcount; k++) {
  485                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
  486                             &iobase, &rescount) != 0)
  487                                 continue;
  488 
  489                         for (i = 0; porttab [i] != 0; i++) {
  490                                 if (porttab [i] != iobase)
  491                                         continue;
  492                                 if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT,
  493                                     iobase, iobase + NPORT, NPORT))
  494                                         continue;
  495                                 if (cx_probe_board (iobase, -1, -1) == 0)
  496                                         continue;
  497                                 porttab [i] = -1;
  498                                 device_set_desc_copy (devices[k], "Cronyx Sigma");
  499                                 break;
  500                         }
  501 
  502                         if (porttab [i] == 0) {
  503                                 device_delete_child (
  504                                     device_get_parent (devices[k]),
  505                                     devices [k]);
  506                                 devices[k] = 0;
  507                                 continue;
  508                         }
  509                 }
  510                 for (k = 0; k < devcount; k++) {
  511                         if (devices[k] == 0)
  512                                 continue;
  513                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
  514                             &iobase, &rescount) == 0)
  515                                 continue;
  516                         for (i = 0; (iobase = porttab [i]) != 0; i++) {
  517                                 if (porttab [i] == -1) {
  518                                         continue;
  519                                 }
  520                                 if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT,
  521                                     iobase, iobase + NPORT, NPORT))
  522                                         continue;
  523                                 if (cx_probe_board (iobase, -1, -1) == 0)
  524                                         continue;
  525                         
  526                                 bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
  527                                     iobase, NPORT);
  528                                 porttab [i] = -1;
  529                                 device_set_desc_copy (devices[k], "Cronyx Sigma");
  530                                 break;
  531                         }
  532                         if (porttab [i] == 0) {
  533                                 device_delete_child (
  534                                     device_get_parent (devices[k]),
  535                                     devices [k]);
  536                         }
  537                 }               
  538                 free (devices, M_TEMP);
  539         }
  540         
  541         return;
  542 }
  543 
  544 static int cx_probe (device_t dev)
  545 {
  546         int unit = device_get_unit (dev);
  547         int i;
  548         u_long iobase, rescount;
  549 
  550         if (!device_get_desc (dev) ||
  551             strcmp (device_get_desc (dev), "Cronyx Sigma"))
  552                 return ENXIO;
  553         
  554         if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
  555                 printf ("cx%d: Couldn't get IOPORT\n", unit);
  556                 return ENXIO;
  557         }
  558 
  559         if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT,
  560             iobase, iobase + NPORT, NPORT)) {
  561                 printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase);
  562                 return ENXIO;
  563         }
  564                 
  565         for (i = 0; porttab [i] != 0; i++) {
  566                 if (porttab [i] == iobase) {
  567                         porttab [i] = -1;
  568                         break;
  569                 }
  570         }
  571         
  572         if (porttab [i] == 0) {
  573                 return ENXIO;
  574         }
  575         
  576         if (!cx_probe_board (iobase, -1, -1)) {
  577                 printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase);
  578                 return ENXIO;
  579         }
  580         
  581         return 0;
  582 }
  583 
  584 static void
  585 cx_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
  586 {
  587         unsigned long *addr;
  588 
  589         if (error)
  590                 return;
  591 
  592         KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
  593         addr = arg;
  594         *addr = segs->ds_addr;
  595 }
  596 
  597 static int
  598 cx_bus_dma_mem_alloc (int bnum, int cnum, cx_dma_mem_t *dmem)
  599 {
  600         int error;
  601 
  602         error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT,
  603                 BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
  604                 dmem->size, 0, NULL, NULL, &dmem->dmat);
  605         if (error) {
  606                 if (cnum >= 0)  printf ("cx%d-%d: ", bnum, cnum);
  607                 else            printf ("cx%d: ", bnum);
  608                 printf ("couldn't allocate tag for dma memory\n");
  609                 return 0;
  610         }
  611         error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
  612                 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
  613         if (error) {
  614                 if (cnum >= 0)  printf ("cx%d-%d: ", bnum, cnum);
  615                 else            printf ("cx%d: ", bnum);
  616                 printf ("couldn't allocate mem for dma memory\n");
  617                 bus_dma_tag_destroy (dmem->dmat);
  618                 return 0;
  619         }
  620         error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
  621                 dmem->size, cx_bus_dmamap_addr, &dmem->phys, 0);
  622         if (error) {
  623                 if (cnum >= 0)  printf ("cx%d-%d: ", bnum, cnum);
  624                 else            printf ("cx%d: ", bnum);
  625                 printf ("couldn't load mem map for dma memory\n");
  626                 bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
  627                 bus_dma_tag_destroy (dmem->dmat);
  628                 return 0;
  629         }
  630         return 1;
  631 }
  632 
  633 static void
  634 cx_bus_dma_mem_free (cx_dma_mem_t *dmem)
  635 {
  636         bus_dmamap_unload (dmem->dmat, dmem->mapp);
  637         bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
  638         bus_dma_tag_destroy (dmem->dmat);
  639 }
  640 
  641 /*
  642  * The adapter is present, initialize the driver structures.
  643  */
  644 static int cx_attach (device_t dev)
  645 {
  646         bdrv_t *bd = device_get_softc (dev);
  647         u_long iobase, drq, irq, rescount;
  648         int unit = device_get_unit (dev);
  649         char *cx_ln = CX_LOCK_NAME;
  650         cx_board_t *b;
  651         cx_chan_t *c;
  652         drv_t *d;
  653         int i;
  654         int s;
  655 
  656         KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit));
  657         
  658         bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
  659         bd->base_rid = 0;
  660         bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
  661                 iobase, iobase + NPORT, NPORT, RF_ACTIVE);
  662         if (! bd->base_res) {
  663                 printf ("cx%d: cannot allocate base address\n", unit);
  664                 return ENXIO;
  665         }
  666         
  667         if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
  668                 for (i = 0; (drq = dmatab [i]) != 0; i++) {
  669                         if (!cx_is_free_res (dev, 0, SYS_RES_DRQ,
  670                             drq, drq + 1, 1))
  671                                 continue;
  672                         bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
  673                         break;
  674                 }
  675                 
  676                 if (dmatab[i] == 0) {   
  677                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  678                                 bd->base_res);
  679                         printf ("cx%d: Couldn't get DRQ\n", unit);
  680                         return ENXIO;
  681                 }
  682         }
  683         
  684         bd->drq_rid = 0;
  685         bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
  686                 drq, drq + 1, 1, RF_ACTIVE);
  687         if (! bd->drq_res) {
  688                 printf ("cx%d: cannot allocate drq\n", unit);
  689                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  690                         bd->base_res);
  691                 return ENXIO;
  692         }       
  693         
  694         if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
  695                 for (i = 0; (irq = irqtab [i]) != 0; i++) {
  696                         if (!cx_is_free_res (dev, 0, SYS_RES_IRQ,
  697                             irq, irq + 1, 1))
  698                                 continue;
  699                         bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
  700                         break;
  701                 }
  702                 
  703                 if (irqtab[i] == 0) {   
  704                         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  705                                 bd->drq_res);
  706                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  707                                 bd->base_res);
  708                         printf ("cx%d: Couldn't get IRQ\n", unit);
  709                         return ENXIO;
  710                 }
  711         }
  712         
  713         bd->irq_rid = 0;
  714         bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
  715                 irq, irq + 1, 1, RF_ACTIVE);
  716         if (! bd->irq_res) {
  717                 printf ("cx%d: Couldn't allocate irq\n", unit);
  718                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  719                         bd->drq_res);
  720                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  721                         bd->base_res);
  722                 return ENXIO;
  723         }
  724         
  725         b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK);
  726         if (!b) {
  727                 printf ("cx:%d: Couldn't allocate memory\n", unit);
  728                 return (ENXIO);
  729         }
  730         adapter[unit] = b;
  731         bzero (b, sizeof(cx_board_t));
  732         
  733         if (! cx_open_board (b, unit, iobase, irq, drq)) {
  734                 printf ("cx%d: error loading firmware\n", unit);
  735                 free (b, M_DEVBUF);
  736                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  737                         bd->irq_res);
  738                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  739                         bd->drq_res);
  740                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  741                         bd->base_res);
  742                 return ENXIO;
  743         }
  744 
  745         bd->board = b;
  746         
  747         cx_ln[2] = '' + unit;
  748         mtx_init (&bd->cx_mtx, cx_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
  749         if (! probe_irq (b, irq)) {
  750                 printf ("cx%d: irq %ld not functional\n", unit, irq);
  751                 bd->board = 0;
  752                 adapter [unit] = 0;
  753                 mtx_destroy (&bd->cx_mtx);
  754                 free (b, M_DEVBUF);
  755                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  756                         bd->irq_res);
  757                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  758                         bd->drq_res);
  759                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  760                         bd->base_res);
  761                 return ENXIO;
  762         }
  763         b->sys = bd;
  764         callout_init (&led_timo[b->num], CALLOUT_MPSAFE);
  765         s = splhigh ();
  766         if (bus_setup_intr (dev, bd->irq_res,
  767                            INTR_TYPE_NET|INTR_MPSAFE,
  768                            NULL, cx_intr, bd, &bd->intrhand)) {
  769                 printf ("cx%d: Can't setup irq %ld\n", unit, irq);
  770                 bd->board = 0;
  771                 b->sys = 0;
  772                 adapter [unit] = 0;
  773                 mtx_destroy (&bd->cx_mtx);
  774                 free (b, M_DEVBUF);
  775                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  776                         bd->irq_res);
  777                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  778                         bd->drq_res);
  779                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  780                         bd->base_res);
  781                 splx (s);
  782                 return ENXIO;           
  783         }
  784         
  785         CX_LOCK (bd);
  786         cx_init (b, b->num, b->port, irq, drq);
  787         cx_setup_board (b, 0, 0, 0);
  788         CX_UNLOCK (bd);
  789 
  790         printf ("cx%d: <Cronyx-Sigma-%s>\n", b->num, b->name);
  791 
  792         for (c=b->chan; c<b->chan+NCHAN; ++c) {
  793                 if (c->type == T_NONE)
  794                         continue;
  795                 d = &bd->channel[c->num];
  796                 d->dmamem.size = sizeof(cx_buf_t);
  797                 if (! cx_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
  798                         continue;
  799                 d->board = b;
  800                 d->chan = c;
  801                 d->open_dev = 0;
  802                 c->sys = d;
  803                 channel [b->num*NCHAN + c->num] = d;
  804                 sprintf (d->name, "cx%d.%d", b->num, c->num);
  805 
  806                 switch (c->type) {
  807                 case T_SYNC_RS232:
  808                 case T_SYNC_V35:
  809                 case T_SYNC_RS449:
  810                 case T_UNIV:
  811                 case T_UNIV_RS232:
  812                 case T_UNIV_RS449:
  813                 case T_UNIV_V35:
  814                 callout_init (&d->timeout_handle, CALLOUT_MPSAFE);
  815 #ifdef NETGRAPH
  816                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
  817                         printf ("%s: cannot make common node\n", d->name);
  818                         channel [b->num*NCHAN + c->num] = 0;
  819                         c->sys = 0;
  820                         cx_bus_dma_mem_free (&d->dmamem);
  821                         continue;
  822                 }
  823                 NG_NODE_SET_PRIVATE (d->node, d);
  824                 sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE,
  825                          c->board->num*NCHAN + c->num);
  826                 if (ng_name_node (d->node, d->nodename)) {
  827                         printf ("%s: cannot name node\n", d->nodename);
  828                         NG_NODE_UNREF (d->node);
  829                         channel [b->num*NCHAN + c->num] = 0;
  830                         c->sys = 0;
  831                         cx_bus_dma_mem_free (&d->dmamem);
  832                         continue;
  833                 }
  834                 d->lo_queue.ifq_maxlen = ifqmaxlen;
  835                 d->hi_queue.ifq_maxlen = ifqmaxlen;
  836                 mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF);
  837                 mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF);
  838 #else /*NETGRAPH*/
  839                 d->ifp = if_alloc(IFT_PPP);
  840                 if (d->ifp == NULL) {
  841                         printf ("%s: cannot if_alloc() common interface\n",
  842                             d->name);
  843                         channel [b->num*NCHAN + c->num] = 0;
  844                         c->sys = 0;
  845                         cx_bus_dma_mem_free (&d->dmamem);
  846                         continue;
  847                 }
  848                 d->ifp->if_softc        = d;
  849                 if_initname (d->ifp, "cx", b->num * NCHAN + c->num);
  850                 d->ifp->if_mtu          = PP_MTU;
  851                 d->ifp->if_flags        = IFF_POINTOPOINT | IFF_MULTICAST;
  852                 d->ifp->if_ioctl        = cx_sioctl;
  853                 d->ifp->if_start        = cx_ifstart;
  854                 d->ifp->if_init         = cx_initialize;
  855                 d->queue.ifq_maxlen     = 2;
  856                 mtx_init (&d->queue.ifq_mtx, "cx_queue", NULL, MTX_DEF);
  857                 sppp_attach (d->ifp);
  858                 if_attach (d->ifp);
  859                 IFP2SP(d->ifp)->pp_tlf  = cx_tlf;
  860                 IFP2SP(d->ifp)->pp_tls  = cx_tls;
  861                 /* If BPF is in the kernel, call the attach for it.
  862                  * Size of PPP header is 4 bytes. */
  863                 bpfattach (d->ifp, DLT_PPP, 4);
  864 #endif /*NETGRAPH*/
  865                 }
  866                 d->tty = ttyalloc ();
  867                 d->tty->t_open  = cx_topen;
  868                 d->tty->t_close = cx_tclose;
  869                 d->tty->t_param = cx_param;
  870                 d->tty->t_stop  = cx_stop;
  871                 d->tty->t_modem = cx_tmodem;
  872                 d->tty->t_oproc = cx_oproc;
  873                 d->tty->t_sc    = d;
  874                 CX_LOCK (bd);
  875                 cx_start_chan (c, d->dmamem.virt, d->dmamem.phys);
  876                 cx_register_receive (c, &cx_receive);
  877                 cx_register_transmit (c, &cx_transmit);
  878                 cx_register_error (c, &cx_error);
  879                 cx_register_modem (c, &cx_modem);
  880                 CX_UNLOCK (bd);
  881 
  882                 ttycreate(d->tty, TS_CALLOUT, "x%r%r", b->num, c->num);
  883                 d->devt = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num);
  884                 d->devt->si_drv1 = d;
  885                 callout_init (&d->dcd_timeout_handle, CALLOUT_MPSAFE);
  886         }
  887         splx (s);
  888 
  889         return 0;
  890 }
  891 
  892 static int cx_detach (device_t dev)
  893 {
  894         bdrv_t *bd = device_get_softc (dev);
  895         cx_board_t *b = bd->board;
  896         cx_chan_t *c;
  897         int s;
  898         
  899         KASSERT (mtx_initialized (&bd->cx_mtx), ("cx mutex not initialized"));
  900 
  901         s = splhigh ();
  902         CX_LOCK (bd);
  903         /* Check if the device is busy (open). */
  904         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  905                 drv_t *d = (drv_t*) c->sys;
  906 
  907                 if (!d || d->chan->type == T_NONE)
  908                         continue;
  909                 if (d->lock) {
  910                         CX_UNLOCK (bd);
  911                         splx (s);
  912                         return EBUSY;
  913                 }
  914                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
  915                     (d->open_dev|0x2)) {
  916                         CX_UNLOCK (bd);
  917                         splx (s);
  918                         return EBUSY;
  919                 }
  920                 if (d->running) {
  921                         CX_UNLOCK (bd);
  922                         splx (s);
  923                         return EBUSY;
  924                 }
  925         }
  926 
  927         /* Deactivate the timeout routine. And soft interrupt*/
  928         callout_stop (&led_timo[b->num]);
  929 
  930         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  931                 drv_t *d = c->sys;
  932 
  933                 if (!d || d->chan->type == T_NONE)
  934                         continue;
  935 
  936                 callout_stop (&d->dcd_timeout_handle);
  937         }
  938         CX_UNLOCK (bd);
  939         bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
  940         bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
  941         
  942         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
  943         
  944         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
  945 
  946         CX_LOCK (bd);
  947         cx_close_board (b);
  948 
  949         /* Detach the interfaces, free buffer memory. */
  950         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  951                 drv_t *d = (drv_t*) c->sys;
  952 
  953                 if (!d || d->chan->type == T_NONE)
  954                         continue;
  955                         
  956                 if (d->tty) {
  957                         ttyfree (d->tty);
  958                         d->tty = NULL;
  959                 }
  960 
  961                 callout_stop (&d->timeout_handle);
  962 #ifdef NETGRAPH
  963                 if (d->node) {
  964                         ng_rmnode_self (d->node);
  965                         NG_NODE_UNREF (d->node);
  966                         d->node = NULL;
  967                 }
  968                 mtx_destroy (&d->lo_queue.ifq_mtx);
  969                 mtx_destroy (&d->hi_queue.ifq_mtx);
  970 #else
  971                 /* Detach from the packet filter list of interfaces. */
  972                 bpfdetach (d->ifp);
  973                 /* Detach from the sync PPP list. */
  974                 sppp_detach (d->ifp);
  975 
  976                 if_detach (d->ifp);
  977                 if_free(d->ifp);
  978                 /* XXXRIK: check interconnection with irq handler */
  979                 IF_DRAIN (&d->queue);
  980                 mtx_destroy (&d->queue.ifq_mtx);
  981 #endif          
  982                 destroy_dev (d->devt);
  983         }
  984 
  985         cx_led_off (b);
  986         CX_UNLOCK (bd);
  987         callout_drain (&led_timo[b->num]);
  988         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  989                 drv_t *d = c->sys;
  990 
  991                 if (!d || d->chan->type == T_NONE)
  992                         continue;
  993 
  994                 callout_drain (&d->dcd_timeout_handle);
  995                 callout_drain (&d->timeout_handle);
  996         }
  997         splx (s);
  998         
  999         s = splhigh ();
 1000         for (c = b->chan; c < b->chan + NCHAN; ++c) {
 1001                 drv_t *d = (drv_t*) c->sys;
 1002 
 1003                 if (!d || d->chan->type == T_NONE)
 1004                         continue;
 1005                 
 1006                 /* Deallocate buffers. */
 1007                 cx_bus_dma_mem_free (&d->dmamem);
 1008         }
 1009         bd->board = 0;
 1010         adapter [b->num] = 0;
 1011         free (b, M_DEVBUF);
 1012         splx (s);
 1013 
 1014         mtx_destroy (&bd->cx_mtx);
 1015         
 1016         return 0;       
 1017 }
 1018 
 1019 #ifndef NETGRAPH
 1020 static void cx_ifstart (struct ifnet *ifp)
 1021 {
 1022         drv_t *d = ifp->if_softc;
 1023         bdrv_t *bd = d->board->sys;
 1024 
 1025         CX_LOCK (bd);
 1026         cx_start (d);
 1027         CX_UNLOCK (bd);
 1028 }
 1029 
 1030 static void cx_tlf (struct sppp *sp)
 1031 {
 1032         drv_t *d = SP2IFP(sp)->if_softc;
 1033 
 1034         CX_DEBUG (d, ("cx_tlf\n"));
 1035 /*      cx_set_dtr (d->chan, 0);*/
 1036 /*      cx_set_rts (d->chan, 0);*/
 1037         if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
 1038                 sp->pp_down (sp);
 1039 }
 1040 
 1041 static void cx_tls (struct sppp *sp)
 1042 {
 1043         drv_t *d = SP2IFP(sp)->if_softc;
 1044 
 1045         CX_DEBUG (d, ("cx_tls\n"));
 1046         if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
 1047                 sp->pp_up (sp);
 1048 }
 1049 
 1050 /*
 1051  * Initialization of interface.
 1052  * It seems to be never called by upper level.
 1053  */
 1054 static void cx_initialize (void *softc)
 1055 {
 1056         drv_t *d = softc;
 1057 
 1058         CX_DEBUG (d, ("cx_initialize\n"));
 1059 }
 1060 
 1061 /*
 1062  * Process an ioctl request.
 1063  */
 1064 static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
 1065 {
 1066         drv_t *d = ifp->if_softc;
 1067         bdrv_t *bd = d->board->sys;
 1068         int error, s, was_up, should_be_up;
 1069 
 1070         /* No socket ioctls while the channel is in async mode. */
 1071         if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC)
 1072                 return EBUSY;
 1073 
 1074         /* Socket ioctls on slave subchannels are not allowed. */
 1075         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
 1076         error = sppp_ioctl (ifp, cmd, data);
 1077         if (error)
 1078                 return error;
 1079 
 1080         s = splhigh ();
 1081         CX_LOCK (bd);
 1082         if (! (ifp->if_flags & IFF_DEBUG))
 1083                 d->chan->debug = 0;
 1084         else
 1085                 d->chan->debug = d->chan->debug_shadow;
 1086         CX_UNLOCK (bd);
 1087         splx (s);
 1088 
 1089         switch (cmd) {
 1090         default:           CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
 1091         case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
 1092         case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
 1093         case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
 1094         case SIOCSIFADDR:  CX_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
 1095         }
 1096 
 1097         /* We get here only in case of SIFFLAGS or SIFADDR. */
 1098         s = splhigh ();
 1099         CX_LOCK (bd);
 1100         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
 1101         if (!was_up && should_be_up) {
 1102                 /* Interface goes up -- start it. */
 1103                 cx_up (d);
 1104                 cx_start (d);
 1105         } else if (was_up && !should_be_up) {
 1106                 /* Interface is going down -- stop it. */
 1107                 /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
 1108                 cx_down (d);
 1109         }
 1110         CX_UNLOCK (bd);
 1111         splx (s);
 1112         return 0;
 1113 }
 1114 #endif /*NETGRAPH*/
 1115 
 1116 /*
 1117  * Stop the interface.  Called on splimp().
 1118  */
 1119 static void cx_down (drv_t *d)
 1120 {
 1121         int s = splhigh ();
 1122         CX_DEBUG (d, ("cx_down\n"));
 1123         cx_set_dtr (d->chan, 0);
 1124         cx_set_rts (d->chan, 0);
 1125         d->running = 0;
 1126         callout_stop (&d->timeout_handle);
 1127         splx (s);
 1128 }
 1129 
 1130 /*
 1131  * Start the interface.  Called on splimp().
 1132  */
 1133 static void cx_up (drv_t *d)
 1134 {
 1135         int s = splhigh ();
 1136         CX_DEBUG (d, ("cx_up\n"));
 1137         cx_set_dtr (d->chan, 1);
 1138         cx_set_rts (d->chan, 1);
 1139         d->running = 1;
 1140         splx (s);
 1141 }
 1142 
 1143 /*
 1144  * Start output on the (slave) interface.  Get another datagram to send
 1145  * off of the interface queue, and copy it to the interface
 1146  * before starting the output.
 1147  */
 1148 static void cx_send (drv_t *d)
 1149 {
 1150         struct mbuf *m;
 1151         u_short len;
 1152 
 1153         CX_DEBUG2 (d, ("cx_send\n"));
 1154 
 1155         /* No output if the interface is down. */
 1156         if (! d->running)
 1157                 return;
 1158 
 1159         /* No output if the modem is off. */
 1160         if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan))
 1161                 return;
 1162 
 1163         if (cx_buf_free (d->chan)) {
 1164                 /* Get the packet to send. */
 1165 #ifdef NETGRAPH
 1166                 IF_DEQUEUE (&d->hi_queue, m);
 1167                 if (! m)
 1168                         IF_DEQUEUE (&d->lo_queue, m);
 1169 #else
 1170                 m = sppp_dequeue (d->ifp);
 1171 #endif
 1172                 if (! m)
 1173                         return;
 1174 #ifndef NETGRAPH
 1175                 BPF_MTAP (d->ifp, m);
 1176 #endif
 1177                 len = m_length (m, NULL);
 1178                 if (! m->m_next)
 1179                         cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
 1180                                 len, 0);
 1181                 else {
 1182                         u_char buf [DMABUFSZ];
 1183                         m_copydata (m, 0, len, buf);
 1184                         cx_send_packet (d->chan, buf, len, 0);
 1185                 }
 1186                 m_freem (m);
 1187 
 1188                 /* Set up transmit timeout, 10 seconds. */
 1189                 d->timeout = 10;
 1190         }
 1191 #ifndef NETGRAPH
 1192         d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 1193 #endif
 1194 }
 1195 
 1196 /*
 1197  * Start output on the interface.
 1198  * Always called on splimp().
 1199  */
 1200 static void cx_start (drv_t *d)
 1201 {
 1202         int s = splhigh ();
 1203         if (d->running) {
 1204                 if (! d->chan->dtr)
 1205                         cx_set_dtr (d->chan, 1);
 1206                 if (! d->chan->rts)
 1207                         cx_set_rts (d->chan, 1);
 1208                 cx_send (d);
 1209                 callout_reset (&d->timeout_handle, hz, cx_watchdog_timer, d);
 1210         }
 1211         splx (s);
 1212 }
 1213 
 1214 /*
 1215  * Handle transmit timeouts.
 1216  * Recover after lost transmit interrupts.
 1217  * Always called on splimp().
 1218  */
 1219 static void cx_watchdog (drv_t *d)
 1220 {
 1221         
 1222         CX_DEBUG (d, ("device timeout\n"));
 1223         if (d->running) {
 1224                 cx_setup_chan (d->chan);
 1225                 cx_start_chan (d->chan, 0, 0);
 1226                 cx_set_dtr (d->chan, 1);
 1227                 cx_set_rts (d->chan, 1);
 1228                 cx_start (d);
 1229         }
 1230 }
 1231 
 1232 static void cx_watchdog_timer (void *arg)
 1233 {
 1234         drv_t *d = arg;
 1235         bdrv_t *bd = d->board->sys;
 1236 
 1237         CX_LOCK (bd);
 1238         if (d->timeout == 1)
 1239                 cx_watchdog (d);
 1240         if (d->timeout)
 1241                 d->timeout--;
 1242         callout_reset (&d->timeout_handle, hz, cx_watchdog_timer, d);
 1243         CX_UNLOCK (bd);
 1244 }
 1245 
 1246 /*
 1247  * Transmit callback function.
 1248  */
 1249 static void cx_transmit (cx_chan_t *c, void *attachment, int len)
 1250 {
 1251         drv_t *d = c->sys;
 1252 
 1253         if (!d)
 1254                 return;
 1255                 
 1256         if (c->mode == M_ASYNC && d->tty) {
 1257                 d->tty->t_state &= ~(TS_BUSY | TS_FLUSH);
 1258                 d->atimeout = 0;
 1259                 if (d->tty->t_dev) {
 1260                         d->intr_action |= CX_WRITE;
 1261                         MY_SOFT_INTR = 1;
 1262                         swi_sched (cx_fast_ih, 0);
 1263                 }
 1264                 return;
 1265         }
 1266         d->timeout = 0;
 1267 #ifndef NETGRAPH
 1268         ++d->ifp->if_opackets;
 1269         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1270 #endif
 1271         cx_start (d);
 1272 }
 1273 
 1274 /*
 1275  * Process the received packet.
 1276  */
 1277 static void cx_receive (cx_chan_t *c, char *data, int len)
 1278 {
 1279         drv_t *d = c->sys;
 1280         struct mbuf *m;
 1281         char *cc = data;
 1282 #ifdef NETGRAPH
 1283         int error;
 1284 #endif
 1285 
 1286         if (!d)
 1287                 return;
 1288                 
 1289         if (c->mode == M_ASYNC && d->tty) {
 1290                 if (d->tty->t_state & TS_ISOPEN) {
 1291                         async_q *q = &d->aqueue;
 1292                         int size = BF_SZ - 1 - AQ_GSZ (q);
 1293 
 1294                         if (len <= 0 && !size)
 1295                                 return;
 1296 
 1297                         if (len > size) {
 1298                                 c->ierrs++;
 1299                                 cx_error (c, CX_OVERRUN);
 1300                                 len = size - 1;
 1301                         }
 1302 
 1303                         while (len--) {
 1304                                 AQ_PUSH (q, *(unsigned char *)cc);
 1305                                 cc++;
 1306                         }
 1307 
 1308                         d->intr_action |= CX_READ;
 1309                         MY_SOFT_INTR = 1;
 1310                         swi_sched (cx_fast_ih, 0);
 1311                 }
 1312                 return;
 1313         }
 1314         if (! d->running)
 1315                 return;
 1316 
 1317         m = makembuf (data, len);
 1318         if (! m) {
 1319                 CX_DEBUG (d, ("no memory for packet\n"));
 1320 #ifndef NETGRAPH
 1321                 ++d->ifp->if_iqdrops;
 1322 #endif
 1323                 return;
 1324         }
 1325         if (c->debug > 1)
 1326                 printmbuf (m);
 1327 #ifdef NETGRAPH
 1328         m->m_pkthdr.rcvif = 0;
 1329         NG_SEND_DATA_ONLY (error, d->hook, m);
 1330 #else
 1331         ++d->ifp->if_ipackets;
 1332         m->m_pkthdr.rcvif = d->ifp;
 1333         /* Check if there's a BPF listener on this interface.
 1334          * If so, hand off the raw packet to bpf. */
 1335         BPF_TAP (d->ifp, data, len);
 1336         IF_ENQUEUE (&d->queue, m);
 1337 #endif
 1338 }
 1339 
 1340 #define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\
 1341             && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\
 1342             && (!(tp->t_iflag & PARMRK)\
 1343                 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\
 1344             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\
 1345             && linesw[tp->t_line]->l_rint == ttyinput)
 1346 
 1347 /*
 1348  * Error callback function.
 1349  */
 1350 static void cx_error (cx_chan_t *c, int data)
 1351 {
 1352         drv_t *d = c->sys;
 1353         async_q *q;
 1354 
 1355         if (!d)
 1356                 return;
 1357 
 1358         q = &(d->aqueue);
 1359 
 1360         switch (data) {
 1361         case CX_FRAME:
 1362                 CX_DEBUG (d, ("frame error\n"));
 1363                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1364                         && (AQ_GSZ (q) < BF_SZ - 1)
 1365                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1366                         || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) {
 1367                         AQ_PUSH (q, TTY_FE);
 1368                         d->intr_action |= CX_READ;
 1369                         MY_SOFT_INTR = 1;
 1370                         swi_sched (cx_fast_ih, 0);
 1371                 }
 1372 #ifndef NETGRAPH
 1373                 else
 1374                         ++d->ifp->if_ierrors;
 1375 #endif
 1376                 break;
 1377         case CX_CRC:
 1378                 CX_DEBUG (d, ("crc error\n"));
 1379                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1380                         && (AQ_GSZ (q) < BF_SZ - 1)
 1381                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1382                         || !(d->tty->t_iflag & INPCK)
 1383                         || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) {
 1384                         AQ_PUSH (q, TTY_PE);
 1385                         d->intr_action |= CX_READ;
 1386                         MY_SOFT_INTR = 1;
 1387                         swi_sched (cx_fast_ih, 0);
 1388                 }
 1389 #ifndef NETGRAPH
 1390                 else
 1391                         ++d->ifp->if_ierrors;
 1392 #endif
 1393                 break;
 1394         case CX_OVERRUN:
 1395                 CX_DEBUG (d, ("overrun error\n"));
 1396 #ifdef TTY_OE
 1397                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1398                         && (AQ_GSZ (q) < BF_SZ - 1)
 1399                         && (!CONDITION((&d->tty->t_termios), (d->tty)))) {
 1400                         AQ_PUSH (q, TTY_OE);
 1401                         d->intr_action |= CX_READ;
 1402                         MY_SOFT_INTR = 1;
 1403                         swi_sched (cx_fast_ih, 0);
 1404                 }
 1405 #endif
 1406 #ifndef NETGRAPH
 1407                 else {
 1408                         ++d->ifp->if_collisions;
 1409                         ++d->ifp->if_ierrors;
 1410                 }
 1411 #endif
 1412                 break;
 1413         case CX_OVERFLOW:
 1414                 CX_DEBUG (d, ("overflow error\n"));
 1415 #ifndef NETGRAPH
 1416                 if (c->mode != M_ASYNC)
 1417                         ++d->ifp->if_ierrors;
 1418 #endif
 1419                 break;
 1420         case CX_UNDERRUN:
 1421                 CX_DEBUG (d, ("underrun error\n"));
 1422                 if (c->mode != M_ASYNC) {
 1423                         d->timeout = 0;
 1424 #ifndef NETGRAPH
 1425                         ++d->ifp->if_oerrors;
 1426                         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1427 #endif
 1428                         cx_start (d);
 1429                 }
 1430                 break;
 1431         case CX_BREAK:
 1432                 CX_DEBUG (d, ("break error\n"));
 1433                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1434                         && (AQ_GSZ (q) < BF_SZ - 1)
 1435                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1436                         || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) {
 1437                         AQ_PUSH (q, TTY_BI);
 1438                         d->intr_action |= CX_READ;
 1439                         MY_SOFT_INTR = 1;
 1440                         swi_sched (cx_fast_ih, 0);
 1441                 }
 1442 #ifndef NETGRAPH
 1443                 else
 1444                         ++d->ifp->if_ierrors;
 1445 #endif
 1446                 break;
 1447         default:
 1448                 CX_DEBUG (d, ("error #%d\n", data));
 1449         }
 1450 }
 1451 
 1452 static int cx_topen (struct tty *tp, struct cdev *dev)
 1453 {
 1454         bdrv_t *bd;
 1455         drv_t *d;
 1456 
 1457         d = tp->t_sc;
 1458         CX_DEBUG2 (d, ("cx_open (serial)\n"));
 1459 
 1460         bd = d->board->sys;
 1461 
 1462         if (d->chan->mode != M_ASYNC)
 1463                 return (EBUSY);
 1464 
 1465         d->open_dev |= 0x2;
 1466         CX_LOCK (bd);
 1467         cx_start_chan (d->chan, 0, 0);
 1468         cx_set_dtr (d->chan, 1);
 1469         cx_set_rts (d->chan, 1);
 1470         d->cd = cx_get_cd (d->chan);
 1471         CX_UNLOCK (bd);
 1472 
 1473         CX_DEBUG2 (d, ("cx_open done\n"));
 1474 
 1475         return 0;
 1476 }
 1477 
 1478 static void cx_tclose (struct tty *tp)
 1479 {
 1480         drv_t *d;
 1481         bdrv_t *bd;
 1482 
 1483         d = tp->t_sc;
 1484         CX_DEBUG2 (d, ("cx_close\n"));
 1485         bd = d->board->sys;
 1486         CX_LOCK (bd);
 1487         /* Disable receiver.
 1488          * Transmitter continues sending the queued data. */
 1489         cx_enable_receive (d->chan, 0);
 1490         CX_UNLOCK (bd);
 1491         d->open_dev &= ~0x2;
 1492 }
 1493 
 1494 static int cx_tmodem (struct tty *tp, int sigon, int sigoff)
 1495 {
 1496         drv_t *d;
 1497         bdrv_t *bd;
 1498 
 1499         d = tp->t_sc;
 1500         bd = d->board->sys;
 1501 
 1502         CX_LOCK (bd);
 1503         if (!sigon && !sigoff) {
 1504                 if (cx_get_dsr (d->chan)) sigon |= SER_DSR;
 1505                 if (cx_get_cd  (d->chan)) sigon |= SER_DCD;
 1506                 if (cx_get_cts (d->chan)) sigon |= SER_CTS;
 1507                 if (d->chan->dtr)         sigon |= SER_DTR;
 1508                 if (d->chan->rts)         sigon |= SER_RTS;
 1509                 CX_UNLOCK (bd);
 1510                 return sigon;
 1511         }
 1512 
 1513         if (sigon & SER_DTR)
 1514                 cx_set_dtr (d->chan, 1);
 1515         if (sigoff & SER_DTR)
 1516                 cx_set_dtr (d->chan, 0);
 1517         if (sigon & SER_RTS)
 1518                 cx_set_rts (d->chan, 1);
 1519         if (sigoff & SER_RTS)
 1520                 cx_set_rts (d->chan, 0);
 1521         CX_UNLOCK (bd);
 1522 
 1523         return (0);
 1524 }
 1525 
 1526 static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td)
 1527 {
 1528         int unit;
 1529         drv_t *d;
 1530 
 1531         d = dev->si_drv1;
 1532         unit = d->chan->num;
 1533 
 1534         CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n",
 1535                     unit, flag, mode));
 1536 
 1537         d->open_dev |= 0x1;
 1538 
 1539         CX_DEBUG2 (d, ("cx_open done\n"));
 1540 
 1541         return 0;
 1542 }
 1543 
 1544 static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td)
 1545 {
 1546         drv_t *d;
 1547 
 1548         d = dev->si_drv1;
 1549         CX_DEBUG2 (d, ("cx_close\n"));
 1550         d->open_dev &= ~0x1;
 1551         return 0;
 1552 }
 1553 
 1554 static int cx_modem_status (drv_t *d)
 1555 {
 1556         bdrv_t *bd = d->board->sys;
 1557         int status = 0, s = splhigh ();
 1558         CX_LOCK (bd);
 1559         /* Already opened by someone or network interface is up? */
 1560         if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
 1561             (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running))
 1562                 status = TIOCM_LE;      /* always enabled while open */
 1563 
 1564         if (cx_get_dsr (d->chan)) status |= TIOCM_DSR;
 1565         if (cx_get_cd  (d->chan)) status |= TIOCM_CD;
 1566         if (cx_get_cts (d->chan)) status |= TIOCM_CTS;
 1567         if (d->chan->dtr)         status |= TIOCM_DTR;
 1568         if (d->chan->rts)         status |= TIOCM_RTS;
 1569         CX_UNLOCK (bd);
 1570         splx (s);
 1571         return status;
 1572 }
 1573 
 1574 static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 1575 {
 1576         drv_t *d;
 1577         bdrv_t *bd;
 1578         cx_chan_t *c;
 1579         struct serial_statistics *st;
 1580         int error, s;
 1581         char mask[16];
 1582 
 1583         d = dev->si_drv1;
 1584         c = d->chan;
 1585                 
 1586         bd = d->board->sys;
 1587         
 1588         switch (cmd) {
 1589         case SERIAL_GETREGISTERED:
 1590                 CX_DEBUG2 (d, ("ioctl: getregistered\n"));
 1591                 bzero (mask, sizeof(mask));
 1592                 for (s=0; s<NCX*NCHAN; ++s)
 1593                         if (channel [s])
 1594                                 mask [s/8] |= 1 << (s & 7);
 1595                 bcopy (mask, data, sizeof (mask));
 1596                 return 0;
 1597 
 1598         case SERIAL_GETPORT:
 1599                 CX_DEBUG2 (d, ("ioctl: getport\n"));
 1600                 s = splhigh ();
 1601                 CX_LOCK (bd);
 1602                 *(int *)data = cx_get_port (c);
 1603                 CX_UNLOCK (bd);
 1604                 splx (s);
 1605                 if (*(int *)data<0)
 1606                         return (EINVAL);
 1607                 else
 1608                         return 0;
 1609 
 1610         case SERIAL_SETPORT:
 1611                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1612                 /* Only for superuser! */
 1613                 error = priv_check (td, PRIV_DRIVER);
 1614                 if (error)
 1615                         return error;
 1616 
 1617                 s = splhigh ();
 1618                 CX_LOCK (bd);
 1619                 cx_set_port (c, *(int *)data);
 1620                 CX_UNLOCK (bd);
 1621                 splx (s);
 1622                 return 0;
 1623 
 1624 #ifndef NETGRAPH
 1625         case SERIAL_GETPROTO:
 1626                 CX_DEBUG2 (d, ("ioctl: getproto\n"));
 1627                 s = splhigh ();
 1628                 CX_LOCK (bd);
 1629                 strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" :
 1630                         (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
 1631                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
 1632                 CX_UNLOCK (bd);
 1633                 splx (s);
 1634                 return 0;
 1635 
 1636         case SERIAL_SETPROTO:
 1637                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1638                 /* Only for superuser! */
 1639                 error = priv_check (td, PRIV_DRIVER);
 1640                 if (error)
 1641                         return error;
 1642                 if (c->mode == M_ASYNC)
 1643                         return EBUSY;
 1644                 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
 1645                         return EBUSY;
 1646                 if (! strcmp ("cisco", (char*)data)) {
 1647                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
 1648                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
 1649                         d->ifp->if_flags |= PP_CISCO;
 1650                 } else if (! strcmp ("fr", (char*)data)) {
 1651                         d->ifp->if_flags &= ~(PP_CISCO);
 1652                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
 1653                 } else if (! strcmp ("ppp", (char*)data)) {
 1654                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE);
 1655                         d->ifp->if_flags &= ~(PP_CISCO);
 1656                 } else
 1657                         return EINVAL;
 1658                 return 0;
 1659 
 1660         case SERIAL_GETKEEPALIVE:
 1661                 CX_DEBUG2 (d, ("ioctl: getkeepalive\n"));
 1662                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
 1663                     (d->ifp->if_flags & PP_CISCO) ||
 1664                     (c->mode == M_ASYNC))
 1665                         return EINVAL;
 1666                 s = splhigh ();
 1667                 CX_LOCK (bd);
 1668                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
 1669                 CX_UNLOCK (bd);
 1670                 splx (s);
 1671                 return 0;
 1672 
 1673         case SERIAL_SETKEEPALIVE:
 1674                 CX_DEBUG2 (d, ("ioctl: setkeepalive\n"));
 1675                 /* Only for superuser! */
 1676                 error = priv_check (td, PRIV_DRIVER);
 1677                 if (error)
 1678                         return error;
 1679                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
 1680                         (d->ifp->if_flags & PP_CISCO))
 1681                         return EINVAL;
 1682                 s = splhigh ();
 1683                 CX_LOCK (bd);
 1684                 if (*(int*)data)
 1685                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
 1686                 else
 1687                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
 1688                 CX_UNLOCK (bd);
 1689                 splx (s);
 1690                 return 0;
 1691 #endif /*NETGRAPH*/
 1692 
 1693         case SERIAL_GETMODE:
 1694                 CX_DEBUG2 (d, ("ioctl: getmode\n"));
 1695                 s = splhigh ();
 1696                 CX_LOCK (bd);
 1697                 *(int*)data = (c->mode == M_ASYNC) ?
 1698                         SERIAL_ASYNC : SERIAL_HDLC;
 1699                 CX_UNLOCK (bd);
 1700                 splx (s);
 1701                 return 0;
 1702 
 1703         case SERIAL_SETMODE:
 1704                 CX_DEBUG2 (d, ("ioctl: setmode\n"));
 1705                 /* Only for superuser! */
 1706                 error = priv_check (td, PRIV_DRIVER);
 1707                 if (error)
 1708                         return error;
 1709 
 1710                 /* Somebody is waiting for carrier? */
 1711                 if (d->lock)
 1712                         return EBUSY;
 1713                 /* /dev/ttyXX is already opened by someone? */
 1714                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
 1715                     (d->open_dev|0x2))
 1716                         return EBUSY;
 1717                 /* Network interface is up?
 1718                  * Cannot change to async mode. */
 1719                 if (c->mode != M_ASYNC && d->running &&
 1720                     (*(int*)data == SERIAL_ASYNC))
 1721                         return EBUSY;
 1722 
 1723                 s = splhigh ();
 1724                 CX_LOCK (bd);
 1725                 if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) {
 1726                         cx_set_mode (c, M_ASYNC);
 1727                         cx_enable_receive (c, 0);
 1728                         cx_enable_transmit (c, 0);
 1729                 } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) {
 1730                         if (d->ifp->if_flags & IFF_DEBUG)
 1731                                 c->debug = c->debug_shadow;
 1732                         cx_set_mode (c, M_HDLC);
 1733                         cx_enable_receive (c, 1);
 1734                         cx_enable_transmit (c, 1);
 1735                 }
 1736                 CX_UNLOCK (bd);
 1737                 splx (s);
 1738                 return 0;
 1739 
 1740         case SERIAL_GETSTAT:
 1741                 CX_DEBUG2 (d, ("ioctl: getestat\n"));
 1742                 st = (struct serial_statistics*) data;
 1743                 s = splhigh ();
 1744                 CX_LOCK (bd);
 1745                 st->rintr  = c->rintr;
 1746                 st->tintr  = c->tintr;
 1747                 st->mintr  = c->mintr;
 1748                 st->ibytes = c->ibytes;
 1749                 st->ipkts  = c->ipkts;
 1750                 st->ierrs  = c->ierrs;
 1751                 st->obytes = c->obytes;
 1752                 st->opkts  = c->opkts;
 1753                 st->oerrs  = c->oerrs;
 1754                 CX_UNLOCK (bd);
 1755                 splx (s);
 1756                 return 0;
 1757 
 1758         case SERIAL_CLRSTAT:
 1759                 CX_DEBUG2 (d, ("ioctl: clrstat\n"));
 1760                 /* Only for superuser! */
 1761                 error = priv_check (td, PRIV_DRIVER);
 1762                 if (error)
 1763                         return error;
 1764                 s = splhigh ();
 1765                 CX_LOCK (bd);
 1766                 c->rintr = 0;
 1767                 c->tintr = 0;
 1768                 c->mintr = 0;
 1769                 c->ibytes = 0;
 1770                 c->ipkts = 0;
 1771                 c->ierrs = 0;
 1772                 c->obytes = 0;
 1773                 c->opkts = 0;
 1774                 c->oerrs = 0;
 1775                 CX_UNLOCK (bd);
 1776                 splx (s);
 1777                 return 0;
 1778 
 1779         case SERIAL_GETBAUD:
 1780                 CX_DEBUG2 (d, ("ioctl: getbaud\n"));
 1781                 if (c->mode == M_ASYNC)
 1782                         return EINVAL;
 1783                 s = splhigh ();
 1784                 CX_LOCK (bd);
 1785                 *(long*)data = cx_get_baud(c);
 1786                 CX_UNLOCK (bd);
 1787                 splx (s);
 1788                 return 0;
 1789 
 1790         case SERIAL_SETBAUD:
 1791                 CX_DEBUG2 (d, ("ioctl: setbaud\n"));
 1792                 /* Only for superuser! */
 1793                 error = priv_check (td, PRIV_DRIVER);
 1794                 if (error)
 1795                         return error;
 1796                 if (c->mode == M_ASYNC)
 1797                         return EINVAL;
 1798                 s = splhigh ();
 1799                 CX_LOCK (bd);
 1800                 cx_set_baud (c, *(long*)data);
 1801                 CX_UNLOCK (bd);
 1802                 splx (s);
 1803                 return 0;
 1804 
 1805         case SERIAL_GETLOOP:
 1806                 CX_DEBUG2 (d, ("ioctl: getloop\n"));
 1807                 if (c->mode == M_ASYNC)
 1808                         return EINVAL;
 1809                 s = splhigh ();
 1810                 CX_LOCK (bd);
 1811                 *(int*)data = cx_get_loop (c);
 1812                 CX_UNLOCK (bd);
 1813                 splx (s);
 1814                 return 0;
 1815 
 1816         case SERIAL_SETLOOP:
 1817                 CX_DEBUG2 (d, ("ioctl: setloop\n"));
 1818                 /* Only for superuser! */
 1819                 error = priv_check (td, PRIV_DRIVER);
 1820                 if (error)
 1821                         return error;
 1822                 if (c->mode == M_ASYNC)
 1823                         return EINVAL;
 1824                 s = splhigh ();
 1825                 CX_LOCK (bd);
 1826                 cx_set_loop (c, *(int*)data);
 1827                 CX_UNLOCK (bd);
 1828                 splx (s);
 1829                 return 0;
 1830 
 1831         case SERIAL_GETDPLL:
 1832                 CX_DEBUG2 (d, ("ioctl: getdpll\n"));
 1833                 if (c->mode == M_ASYNC)
 1834                         return EINVAL;
 1835                 s = splhigh ();
 1836                 CX_LOCK (bd);
 1837                 *(int*)data = cx_get_dpll (c);
 1838                 CX_UNLOCK (bd);
 1839                 splx (s);
 1840                 return 0;
 1841 
 1842         case SERIAL_SETDPLL:
 1843                 CX_DEBUG2 (d, ("ioctl: setdpll\n"));
 1844                 /* Only for superuser! */
 1845                 error = priv_check (td, PRIV_DRIVER);
 1846                 if (error)
 1847                         return error;
 1848                 if (c->mode == M_ASYNC)
 1849                         return EINVAL;
 1850                 s = splhigh ();
 1851                 CX_LOCK (bd);
 1852                 cx_set_dpll (c, *(int*)data);
 1853                 CX_UNLOCK (bd);
 1854                 splx (s);
 1855                 return 0;
 1856 
 1857         case SERIAL_GETNRZI:
 1858                 CX_DEBUG2 (d, ("ioctl: getnrzi\n"));
 1859                 if (c->mode == M_ASYNC)
 1860                         return EINVAL;
 1861                 s = splhigh ();
 1862                 CX_LOCK (bd);
 1863                 *(int*)data = cx_get_nrzi (c);
 1864                 CX_UNLOCK (bd);
 1865                 splx (s);
 1866                 return 0;
 1867 
 1868         case SERIAL_SETNRZI:
 1869                 CX_DEBUG2 (d, ("ioctl: setnrzi\n"));
 1870                 /* Only for superuser! */
 1871                 error = priv_check (td, PRIV_DRIVER);
 1872                 if (error)
 1873                         return error;
 1874                 if (c->mode == M_ASYNC)
 1875                         return EINVAL;
 1876                 s = splhigh ();
 1877                 CX_LOCK (bd);
 1878                 cx_set_nrzi (c, *(int*)data);
 1879                 CX_UNLOCK (bd);
 1880                 splx (s);
 1881                 return 0;
 1882 
 1883         case SERIAL_GETDEBUG:
 1884                 CX_DEBUG2 (d, ("ioctl: getdebug\n"));
 1885                 s = splhigh ();
 1886                 CX_LOCK (bd);
 1887                 *(int*)data = c->debug;
 1888                 CX_UNLOCK (bd);
 1889                 splx (s);
 1890                 return 0;
 1891 
 1892         case SERIAL_SETDEBUG:
 1893                 CX_DEBUG2 (d, ("ioctl: setdebug\n"));
 1894                 /* Only for superuser! */
 1895                 error = priv_check (td, PRIV_DRIVER);
 1896                 if (error)
 1897                         return error;
 1898                 s = splhigh ();
 1899                 CX_LOCK (bd);
 1900 #ifndef NETGRAPH
 1901                 if (c->mode == M_ASYNC) {
 1902                         c->debug = *(int*)data;
 1903                 } else {
 1904                         /*
 1905                          * The debug_shadow is always greater than zero for
 1906                          * logic simplicity.  For switching debug off the
 1907                          * IFF_DEBUG is responsible (for !M_ASYNC mode).
 1908                          */
 1909                         c->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
 1910                         if (d->ifp->if_flags & IFF_DEBUG)
 1911                                 c->debug = c->debug_shadow;
 1912                 }
 1913 #else
 1914                 c->debug = *(int*)data;
 1915 #endif
 1916                 CX_UNLOCK (bd);
 1917                 splx (s);
 1918                 return 0;
 1919         }
 1920 
 1921         switch (cmd) {
 1922         case TIOCSDTR:  /* Set DTR */
 1923                 CX_DEBUG2 (d, ("ioctl: tiocsdtr\n"));
 1924                 s = splhigh ();
 1925                 CX_LOCK (bd);
 1926                 cx_set_dtr (c, 1);
 1927                 CX_UNLOCK (bd);
 1928                 splx (s);
 1929                 return 0;
 1930 
 1931         case TIOCCDTR:  /* Clear DTR */
 1932                 CX_DEBUG2 (d, ("ioctl: tioccdtr\n"));
 1933                 s = splhigh ();
 1934                 CX_LOCK (bd);
 1935                 cx_set_dtr (c, 0);
 1936                 CX_UNLOCK (bd);
 1937                 splx (s);
 1938                 return 0;
 1939 
 1940         case TIOCMSET:  /* Set DTR/RTS */
 1941                 CX_DEBUG2 (d, ("ioctl: tiocmset\n"));
 1942                 s = splhigh ();
 1943                 CX_LOCK (bd);
 1944                 cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
 1945                 cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
 1946                 CX_UNLOCK (bd);
 1947                 splx (s);
 1948                 return 0;
 1949 
 1950         case TIOCMBIS:  /* Add DTR/RTS */
 1951                 CX_DEBUG2 (d, ("ioctl: tiocmbis\n"));
 1952                 s = splhigh ();
 1953                 CX_LOCK (bd);
 1954                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1);
 1955                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1);
 1956                 CX_UNLOCK (bd);
 1957                 splx (s);
 1958                 return 0;
 1959 
 1960         case TIOCMBIC:  /* Clear DTR/RTS */
 1961                 CX_DEBUG2 (d, ("ioctl: tiocmbic\n"));
 1962                 s = splhigh ();
 1963                 CX_LOCK (bd);
 1964                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0);
 1965                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0);
 1966                 CX_UNLOCK (bd);
 1967                 splx (s);
 1968                 return 0;
 1969 
 1970         case TIOCMGET:  /* Get modem status */
 1971                 CX_DEBUG2 (d, ("ioctl: tiocmget\n"));
 1972                 *(int*)data = cx_modem_status (d);
 1973                 return 0;
 1974 
 1975         }
 1976 
 1977         CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd));
 1978         return ENOTTY;
 1979 }
 1980 
 1981 void cx_softintr (void *unused)
 1982 {
 1983         drv_t *d;
 1984         bdrv_t *bd;
 1985         async_q *q;
 1986         int i, s, ic, k;
 1987         while (MY_SOFT_INTR) {
 1988                 MY_SOFT_INTR = 0;
 1989                 for (i=0; i<NCX*NCHAN; ++i) {
 1990                         d = channel [i];
 1991                         if (!d || !d->chan || d->chan->type == T_NONE
 1992                             || d->chan->mode != M_ASYNC || !d->tty
 1993                             || !d->tty->t_dev)
 1994                                 continue;
 1995                         bd = d->board->sys;
 1996                         s = splhigh ();
 1997                         CX_LOCK (bd);
 1998                         if (d->intr_action & CX_READ) {
 1999                                 q = &(d->aqueue);
 2000                                 if (d->tty->t_state & TS_CAN_BYPASS_L_RINT) {
 2001                                         k = AQ_GSZ(q);
 2002                                         if (d->tty->t_rawq.c_cc + k >
 2003                                                 d->tty->t_ihiwat
 2004                                             && (d->tty->t_cflag & CRTS_IFLOW
 2005                                                 || d->tty->t_iflag & IXOFF)
 2006                                             && !(d->tty->t_state & TS_TBLOCK))
 2007                                                 ttyblock(d->tty);
 2008                                         d->tty->t_rawcc += k;
 2009                                         while (k>0) {
 2010                                                 k--;
 2011                                                 AQ_POP (q, ic);
 2012                                                 CX_UNLOCK (bd);
 2013                                                 splx (s);
 2014                                                 putc (ic, &d->tty->t_rawq);
 2015                                                 s = splhigh ();
 2016                                                 CX_LOCK (bd);
 2017                                         }
 2018                                         ttwakeup(d->tty);
 2019                                         if (d->tty->t_state & TS_TTSTOP
 2020                                             && (d->tty->t_iflag & IXANY
 2021                                                 || d->tty->t_cc[VSTART] ==
 2022                                                 d->tty->t_cc[VSTOP])) {
 2023                                                 d->tty->t_state &= ~TS_TTSTOP;
 2024                                                 d->tty->t_lflag &= ~FLUSHO;
 2025                                                 d->intr_action |= CX_WRITE;
 2026                                         }
 2027                                 } else {
 2028                                         while (q->end != q->beg) {
 2029                                                 AQ_POP (q, ic);
 2030                                                 CX_UNLOCK (bd);
 2031                                                 splx (s);
 2032                                                 ttyld_rint (d->tty, ic);
 2033                                                 s = splhigh ();
 2034                                                 CX_LOCK (bd);
 2035                                         }
 2036                                 }
 2037                                 d->intr_action &= ~CX_READ;
 2038                         }
 2039                         splx (s);
 2040                         CX_UNLOCK (bd);
 2041 
 2042                         s = splhigh ();
 2043                         CX_LOCK (bd);
 2044                         if (d->intr_action & CX_WRITE) {
 2045                                 if (d->tty->t_line)
 2046                                         ttyld_start (d->tty);
 2047                                 else
 2048                                         cx_oproc (d->tty);
 2049                                 d->intr_action &= ~CX_WRITE;
 2050                         }
 2051                         CX_UNLOCK (bd);
 2052                         splx (s);
 2053 
 2054                 }
 2055         }
 2056 }
 2057 
 2058 /*
 2059  * Fill transmitter buffer with data.
 2060  */
 2061 static void cx_oproc (struct tty *tp)
 2062 {
 2063         int s, k;
 2064         drv_t *d;
 2065         bdrv_t *bd;
 2066         static u_char buf[DMABUFSZ];
 2067         u_char *p;
 2068         u_short len = 0, sublen = 0;
 2069 
 2070         d = tp->t_sc;
 2071         bd = d->board->sys;
 2072 
 2073         CX_DEBUG2 (d, ("cx_oproc\n"));
 2074 
 2075         s = splhigh ();
 2076         CX_LOCK (bd);
 2077 
 2078         if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts)
 2079                 cx_set_rts (d->chan, 0);
 2080         else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts)
 2081                 cx_set_rts (d->chan, 1);
 2082 
 2083         if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
 2084                 /* Start transmitter. */
 2085                 cx_enable_transmit (d->chan, 1);
 2086 
 2087                 /* Is it busy? */
 2088                 if (! cx_buf_free (d->chan)) {
 2089                         tp->t_state |= TS_BUSY;
 2090                         CX_UNLOCK (bd);
 2091                         splx (s);
 2092                         return;
 2093                 }
 2094                 if (tp->t_iflag & IXOFF) {
 2095                         p = (buf + (DMABUFSZ/2));
 2096                         sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2097                         k = sublen;
 2098                         while (k--) {
 2099                                 /* Send XON/XOFF out of band. */
 2100                                 if (*p == tp->t_cc[VSTOP]) {
 2101                                         cx_xflow_ctl (d->chan, 0);
 2102                                         p++;
 2103                                         continue;
 2104                                 }
 2105                                 if (*p == tp->t_cc[VSTART]) {
 2106                                         cx_xflow_ctl (d->chan, 1);
 2107                                         p++;
 2108                                         continue;
 2109                                 }
 2110                                 buf[len] = *p;
 2111                                 len++;
 2112                                 p++;
 2113                         }
 2114                 } else {
 2115                         p = buf;
 2116                         len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2117                 }
 2118                 if (len) {
 2119                         cx_send_packet (d->chan, buf, len, 0);
 2120                         tp->t_state |= TS_BUSY;
 2121                         d->atimeout = 10;
 2122                         CX_DEBUG2 (d, ("out %d bytes\n", len));
 2123                 }
 2124         }
 2125         ttwwakeup (tp);
 2126         CX_UNLOCK (bd);
 2127         splx (s);
 2128 }
 2129 
 2130 static int cx_param (struct tty *tp, struct termios *t)
 2131 {
 2132         drv_t *d;
 2133         bdrv_t *bd;
 2134         int s, bits, parity;
 2135 
 2136         d = tp->t_sc;
 2137         bd = d->board->sys;
 2138         
 2139         s = splhigh ();
 2140         CX_LOCK (bd);
 2141         if (t->c_ospeed == 0) {
 2142                 /* Clear DTR and RTS. */
 2143                 cx_set_dtr (d->chan, 0);
 2144                 CX_UNLOCK (bd);
 2145                 splx (s);
 2146                 CX_DEBUG2 (d, ("cx_param (hangup)\n"));
 2147                 return 0;
 2148         }
 2149         CX_DEBUG2 (d, ("cx_param\n"));
 2150 
 2151         /* Check requested parameters. */
 2152         if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) {
 2153                 CX_UNLOCK (bd);
 2154                 splx (s);
 2155                 return EINVAL;
 2156         }
 2157         if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) {
 2158                 CX_UNLOCK (bd);
 2159                 splx (s);
 2160                 return EINVAL;
 2161         }
 2162 
 2163         /* And copy them to tty and channel structures. */
 2164         tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed;
 2165         tp->t_cflag = t->c_cflag;
 2166 
 2167         /* Set character length and parity mode. */
 2168         switch (t->c_cflag & CSIZE) {
 2169         default:
 2170         case CS8: bits = 8; break;
 2171         case CS7: bits = 7; break;
 2172         case CS6: bits = 6; break;
 2173         case CS5: bits = 5; break;
 2174         }
 2175 
 2176         parity = ((t->c_cflag & PARENB) ? 1 : 0) *
 2177                  (1 + ((t->c_cflag & PARODD) ? 0 : 1));
 2178 
 2179         /* Set current channel number. */
 2180         if (! d->chan->dtr)
 2181                 cx_set_dtr (d->chan, 1);
 2182 
 2183         ttyldoptim (tp);
 2184         cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB),
 2185                 !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS),
 2186                 (t->c_iflag & IXON), (t->c_iflag & IXANY),
 2187                 t->c_cc[VSTART], t->c_cc[VSTOP]);
 2188         CX_UNLOCK (bd);
 2189         splx (s);
 2190         return 0;
 2191 }
 2192 
 2193 /*
 2194  * Stop output on a line
 2195  */
 2196 static void cx_stop (struct tty *tp, int flag)
 2197 {
 2198         drv_t *d;
 2199         bdrv_t *bd;
 2200         int s;
 2201 
 2202         d = tp->t_sc;
 2203         bd = d->board->sys;
 2204         
 2205         s = splhigh ();
 2206         CX_LOCK (bd);
 2207         if (tp->t_state & TS_BUSY) {
 2208                 /* Stop transmitter */
 2209                 CX_DEBUG2 (d, ("cx_stop\n"));
 2210                 cx_transmitter_ctl (d->chan, 0);
 2211         }
 2212         CX_UNLOCK (bd);
 2213         splx (s);
 2214 }
 2215 
 2216 /*
 2217  * Process the (delayed) carrier signal setup.
 2218  */
 2219 static void cx_carrier (void *arg)
 2220 {
 2221         drv_t *d = arg;
 2222         bdrv_t *bd = d->board->sys;
 2223         cx_chan_t *c = d->chan;
 2224         int s, cd;
 2225 
 2226         s = splhigh ();
 2227         CX_LOCK (bd);
 2228         cd = cx_get_cd (c);
 2229         if (d->cd != cd) {
 2230                 if (cd) {
 2231                         CX_DEBUG (d, ("carrier on\n"));
 2232                         d->cd = 1;
 2233                         CX_UNLOCK (bd);
 2234                         splx (s);
 2235                         if (d->tty)
 2236                                 ttyld_modem(d->tty, 1);
 2237                 } else {
 2238                         CX_DEBUG (d, ("carrier loss\n"));
 2239                         d->cd = 0;
 2240                         CX_UNLOCK (bd);
 2241                         splx (s);
 2242                         if (d->tty)
 2243                                 ttyld_modem(d->tty, 0);
 2244                 }
 2245         } else {
 2246                 CX_UNLOCK (bd);
 2247                 splx (s);
 2248         }
 2249 }
 2250 
 2251 /*
 2252  * Modem signal callback function.
 2253  */
 2254 static void cx_modem (cx_chan_t *c)
 2255 {
 2256         drv_t *d = c->sys;
 2257 
 2258         if (!d || c->mode != M_ASYNC)
 2259                 return;
 2260         /* Handle carrier detect/loss. */
 2261         /* Carrier changed - delay processing DCD for a while
 2262          * to give both sides some time to initialize. */
 2263         callout_reset (&d->dcd_timeout_handle, hz/2, cx_carrier, d);
 2264 }
 2265 
 2266 #ifdef NETGRAPH
 2267 static int ng_cx_constructor (node_p node)
 2268 {
 2269         drv_t *d = NG_NODE_PRIVATE (node);
 2270         CX_DEBUG (d, ("Constructor\n"));
 2271         return EINVAL;
 2272 }
 2273 
 2274 static int ng_cx_newhook (node_p node, hook_p hook, const char *name)
 2275 {
 2276         int s;
 2277         drv_t *d = NG_NODE_PRIVATE (node);
 2278         bdrv_t *bd = d->board->sys;
 2279 
 2280         if (d->chan->mode == M_ASYNC)
 2281                 return EINVAL;
 2282 
 2283         /* Attach debug hook */
 2284         if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) {
 2285                 NG_HOOK_SET_PRIVATE (hook, NULL);
 2286                 d->debug_hook = hook;
 2287                 return 0;
 2288         }
 2289 
 2290         /* Check for raw hook */
 2291         if (strcmp (name, NG_CX_HOOK_RAW) != 0)
 2292                 return EINVAL;
 2293 
 2294         NG_HOOK_SET_PRIVATE (hook, d);
 2295         d->hook = hook;
 2296         s = splhigh ();
 2297         CX_LOCK (bd);
 2298         cx_up (d);
 2299         CX_UNLOCK (bd);
 2300         splx (s);
 2301         return 0;
 2302 }
 2303 
 2304 static int print_modems (char *s, cx_chan_t *c, int need_header)
 2305 {
 2306         int status = cx_modem_status (c->sys);
 2307         int length = 0;
 2308 
 2309         if (need_header)
 2310                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
 2311         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
 2312                 status & TIOCM_LE  ? "On" : "-",
 2313                 status & TIOCM_DTR ? "On" : "-",
 2314                 status & TIOCM_DSR ? "On" : "-",
 2315                 status & TIOCM_RTS ? "On" : "-",
 2316                 status & TIOCM_CTS ? "On" : "-",
 2317                 status & TIOCM_CD  ? "On" : "-");
 2318         return length;
 2319 }
 2320 
 2321 static int print_stats (char *s, cx_chan_t *c, int need_header)
 2322 {
 2323         int length = 0;
 2324 
 2325         if (need_header)
 2326                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
 2327         length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
 2328                 c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts,
 2329                 c->ierrs, c->obytes, c->opkts, c->oerrs);
 2330         return length;
 2331 }
 2332 
 2333 static int print_chan (char *s, cx_chan_t *c)
 2334 {
 2335         drv_t *d = c->sys;
 2336         int length = 0;
 2337 
 2338         length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num);
 2339         if (d->chan->debug)
 2340                 length += sprintf (s + length, " debug=%d", d->chan->debug);
 2341 
 2342         if (cx_get_baud (c))
 2343                 length += sprintf (s + length, " %ld", cx_get_baud (c));
 2344         else
 2345                 length += sprintf (s + length, " extclock");
 2346 
 2347         if (c->mode == M_HDLC) {
 2348                 length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off");
 2349                 length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off");
 2350         }
 2351 
 2352         length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n");
 2353         return length;
 2354 }
 2355 
 2356 static int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook)
 2357 {
 2358         drv_t *d = NG_NODE_PRIVATE (node);
 2359         struct ng_mesg *msg;
 2360         struct ng_mesg *resp = NULL;
 2361         int error = 0;
 2362 
 2363         if (!d)
 2364                 return EINVAL;
 2365                 
 2366         CX_DEBUG (d, ("Rcvmsg\n"));
 2367         NGI_GET_MSG (item, msg);
 2368         switch (msg->header.typecookie) {
 2369         default:
 2370                 error = EINVAL;
 2371                 break;
 2372 
 2373         case NGM_CX_COOKIE:
 2374                 printf ("Don't forget to implement\n");
 2375                 error = EINVAL;
 2376                 break;
 2377 
 2378         case NGM_GENERIC_COOKIE:
 2379                 switch (msg->header.cmd) {
 2380                 default:
 2381                         error = EINVAL;
 2382                         break;
 2383 
 2384                 case NGM_TEXT_STATUS: {
 2385                         char *s;
 2386                         int l = 0;
 2387                         int dl = sizeof (struct ng_mesg) + 730;
 2388 
 2389                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
 2390                         if (! resp) {
 2391                                 error = ENOMEM;
 2392                                 break;
 2393                         }
 2394                         bzero (resp, dl);
 2395                         s = (resp)->data;
 2396                         l += print_chan (s + l, d->chan);
 2397                         l += print_stats (s + l, d->chan, 1);
 2398                         l += print_modems (s + l, d->chan, 1);
 2399                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ);
 2400                         }
 2401                         break;
 2402                 }
 2403                 break;
 2404         }
 2405         NG_RESPOND_MSG (error, node, item, resp);
 2406         NG_FREE_MSG (msg);
 2407         return error;
 2408 }
 2409 
 2410 static int ng_cx_rcvdata (hook_p hook, item_p item)
 2411 {
 2412         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
 2413         struct mbuf *m;
 2414         struct ng_tag_prio *ptag;
 2415         bdrv_t *bd;
 2416         struct ifqueue *q;
 2417         int s;
 2418 
 2419         NGI_GET_M (item, m);
 2420         NG_FREE_ITEM (item);
 2421         if (! NG_HOOK_PRIVATE (hook) || ! d) {
 2422                 NG_FREE_M (m);
 2423                 return ENETDOWN;
 2424         }
 2425 
 2426         bd = d->board->sys;
 2427         /* Check for high priority data */
 2428         if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
 2429             NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
 2430                 q = &d->hi_queue;
 2431         else
 2432                 q = &d->lo_queue;
 2433 
 2434         s = splhigh ();
 2435         CX_LOCK (bd);
 2436         IF_LOCK (q);
 2437         if (_IF_QFULL (q)) {
 2438                 _IF_DROP (q);
 2439                 IF_UNLOCK (q);
 2440                 CX_UNLOCK (bd);
 2441                 splx (s);
 2442                 NG_FREE_M (m);
 2443                 return ENOBUFS;
 2444         }
 2445         _IF_ENQUEUE (q, m);
 2446         IF_UNLOCK (q);
 2447         cx_start (d);
 2448         CX_UNLOCK (bd);
 2449         splx (s);
 2450         return 0;
 2451 }
 2452 
 2453 static int ng_cx_rmnode (node_p node)
 2454 {
 2455         drv_t *d = NG_NODE_PRIVATE (node);
 2456         bdrv_t *bd;
 2457 
 2458         CX_DEBUG (d, ("Rmnode\n"));
 2459         if (d && d->running) {
 2460                 int s = splhigh ();
 2461                 bd = d->board->sys;
 2462                 CX_LOCK (bd);
 2463                 cx_down (d);
 2464                 CX_UNLOCK (bd);
 2465                 splx (s);
 2466         }
 2467 #ifdef  KLD_MODULE
 2468         if (node->nd_flags & NGF_REALLY_DIE) {
 2469                 NG_NODE_SET_PRIVATE (node, NULL);
 2470                 NG_NODE_UNREF (node);
 2471         }
 2472         NG_NODE_REVIVE(node);           /* Persistant node */
 2473 #endif
 2474         return 0;
 2475 }
 2476 
 2477 static int ng_cx_connect (hook_p hook)
 2478 {
 2479         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2480 
 2481         callout_reset (&d->timeout_handle, hz, cx_watchdog_timer, d);
 2482         return 0;
 2483 }
 2484 
 2485 static int ng_cx_disconnect (hook_p hook)
 2486 {
 2487         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2488         bdrv_t *bd = d->board->sys;
 2489         int s;
 2490 
 2491         s = splhigh ();
 2492         CX_LOCK (bd);
 2493         if (NG_HOOK_PRIVATE (hook))
 2494                 cx_down (d);
 2495         CX_UNLOCK (bd);
 2496         splx (s);
 2497         /* If we were wait it than it reasserted now, just stop it. */
 2498         if (!callout_drain (&d->timeout_handle))
 2499                 callout_stop (&d->timeout_handle);
 2500         return 0;
 2501 }
 2502 #endif /*NETGRAPH*/
 2503 
 2504 static int cx_modevent (module_t mod, int type, void *unused)
 2505 {
 2506         static int load_count = 0;
 2507 
 2508         switch (type) {
 2509         case MOD_LOAD:
 2510 #ifdef NETGRAPH
 2511                 if (ng_newtype (&typestruct))
 2512                         printf ("Failed to register ng_cx\n");
 2513 #endif
 2514                 ++load_count;
 2515 
 2516                 callout_init (&timeout_handle, CALLOUT_MPSAFE);
 2517                 callout_reset (&timeout_handle, hz*5, cx_timeout, 0);
 2518                 /* Software interrupt. */
 2519                 swi_add(&tty_intr_event, "cx", cx_softintr, NULL, SWI_TTY,
 2520                     INTR_MPSAFE, &cx_fast_ih);
 2521                 break;
 2522         case MOD_UNLOAD:
 2523                 if (load_count == 1) {
 2524                         printf ("Removing device entry for Sigma\n");
 2525 #ifdef NETGRAPH
 2526                         ng_rmtype (&typestruct);
 2527 #endif                  
 2528                 }
 2529                 /* If we were wait it than it reasserted now, just stop it. */
 2530                 if (!callout_drain (&timeout_handle))
 2531                         callout_stop (&timeout_handle);
 2532                 swi_remove (cx_fast_ih);
 2533                 --load_count;
 2534                 break;
 2535         case MOD_SHUTDOWN:
 2536                 break;
 2537         }
 2538         return 0;
 2539 }
 2540 
 2541 #ifdef NETGRAPH
 2542 static struct ng_type typestruct = {
 2543         .version        = NG_ABI_VERSION,
 2544         .name           = NG_CX_NODE_TYPE,
 2545         .constructor    = ng_cx_constructor,
 2546         .rcvmsg         = ng_cx_rcvmsg,
 2547         .shutdown       = ng_cx_rmnode,
 2548         .newhook        = ng_cx_newhook,
 2549         .connect        = ng_cx_connect,
 2550         .rcvdata        = ng_cx_rcvdata,
 2551         .disconnect     = ng_cx_disconnect,
 2552 };
 2553 #endif /*NETGRAPH*/
 2554 
 2555 #ifdef NETGRAPH
 2556 MODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
 2557 #else
 2558 MODULE_DEPEND (isa_cx, sppp, 1, 1, 1);
 2559 #endif
 2560 DRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL);
 2561 MODULE_VERSION (cx, 1);

Cache object: 1edb156b758f9cbcf1a04039a8e8cf1a


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