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/8.3/sys/dev/cx/if_cx.c 215342 2010-11-15 17:48:13Z 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         short   timeout;
  147         struct  callout timeout_handle;
  148 #else
  149         struct  ifqueue queue;
  150         struct  ifnet *ifp;
  151 #endif
  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_carrier (void *arg);
  201 
  202 #ifdef NETGRAPH
  203 extern struct ng_type typestruct;
  204 #else
  205 static void cx_ifstart (struct ifnet *ifp);
  206 static void cx_tlf (struct sppp *sp);
  207 static void cx_tls (struct sppp *sp);
  208 static void cx_ifwatchdog (struct ifnet *ifp);
  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 #ifdef NETGRAPH
  815                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
  816                         printf ("%s: cannot make common node\n", d->name);
  817                         channel [b->num*NCHAN + c->num] = 0;
  818                         c->sys = 0;
  819                         cx_bus_dma_mem_free (&d->dmamem);
  820                         continue;
  821                 }
  822                 NG_NODE_SET_PRIVATE (d->node, d);
  823                 sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE,
  824                          c->board->num*NCHAN + c->num);
  825                 if (ng_name_node (d->node, d->nodename)) {
  826                         printf ("%s: cannot name node\n", d->nodename);
  827                         NG_NODE_UNREF (d->node);
  828                         channel [b->num*NCHAN + c->num] = 0;
  829                         c->sys = 0;
  830                         cx_bus_dma_mem_free (&d->dmamem);
  831                         continue;
  832                 }
  833                 d->lo_queue.ifq_maxlen = ifqmaxlen;
  834                 d->hi_queue.ifq_maxlen = ifqmaxlen;
  835                 mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF);
  836                 mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF);
  837                 callout_init (&d->timeout_handle, CALLOUT_MPSAFE);
  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_watchdog     = cx_ifwatchdog;
  855                 d->ifp->if_init         = cx_initialize;
  856                 d->queue.ifq_maxlen     = 2;
  857                 mtx_init (&d->queue.ifq_mtx, "cx_queue", NULL, MTX_DEF);
  858                 sppp_attach (d->ifp);
  859                 if_attach (d->ifp);
  860                 IFP2SP(d->ifp)->pp_tlf  = cx_tlf;
  861                 IFP2SP(d->ifp)->pp_tls  = cx_tls;
  862                 /* If BPF is in the kernel, call the attach for it.
  863                  * Size of PPP header is 4 bytes. */
  864                 bpfattach (d->ifp, DLT_PPP, 4);
  865 #endif /*NETGRAPH*/
  866                 }
  867                 d->tty = ttyalloc ();
  868                 d->tty->t_open  = cx_topen;
  869                 d->tty->t_close = cx_tclose;
  870                 d->tty->t_param = cx_param;
  871                 d->tty->t_stop  = cx_stop;
  872                 d->tty->t_modem = cx_tmodem;
  873                 d->tty->t_oproc = cx_oproc;
  874                 d->tty->t_sc    = d;
  875                 CX_LOCK (bd);
  876                 cx_start_chan (c, d->dmamem.virt, d->dmamem.phys);
  877                 cx_register_receive (c, &cx_receive);
  878                 cx_register_transmit (c, &cx_transmit);
  879                 cx_register_error (c, &cx_error);
  880                 cx_register_modem (c, &cx_modem);
  881                 CX_UNLOCK (bd);
  882 
  883                 ttycreate(d->tty, TS_CALLOUT, "x%r%r", b->num, c->num);
  884                 d->devt = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num);
  885                 d->devt->si_drv1 = d;
  886                 callout_init (&d->dcd_timeout_handle, CALLOUT_MPSAFE);
  887         }
  888         splx (s);
  889 
  890         return 0;
  891 }
  892 
  893 static int cx_detach (device_t dev)
  894 {
  895         bdrv_t *bd = device_get_softc (dev);
  896         cx_board_t *b = bd->board;
  897         cx_chan_t *c;
  898         int s;
  899         
  900         KASSERT (mtx_initialized (&bd->cx_mtx), ("cx mutex not initialized"));
  901 
  902         s = splhigh ();
  903         CX_LOCK (bd);
  904         /* Check if the device is busy (open). */
  905         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  906                 drv_t *d = (drv_t*) c->sys;
  907 
  908                 if (!d || d->chan->type == T_NONE)
  909                         continue;
  910                 if (d->lock) {
  911                         CX_UNLOCK (bd);
  912                         splx (s);
  913                         return EBUSY;
  914                 }
  915                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
  916                     (d->open_dev|0x2)) {
  917                         CX_UNLOCK (bd);
  918                         splx (s);
  919                         return EBUSY;
  920                 }
  921                 if (d->running) {
  922                         CX_UNLOCK (bd);
  923                         splx (s);
  924                         return EBUSY;
  925                 }
  926         }
  927 
  928         /* Deactivate the timeout routine. And soft interrupt*/
  929         callout_stop (&led_timo[b->num]);
  930 
  931         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  932                 drv_t *d = c->sys;
  933 
  934                 if (!d || d->chan->type == T_NONE)
  935                         continue;
  936 
  937                 callout_stop (&d->dcd_timeout_handle);
  938         }
  939         CX_UNLOCK (bd);
  940         bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
  941         bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
  942         
  943         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
  944         
  945         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
  946 
  947         CX_LOCK (bd);
  948         cx_close_board (b);
  949 
  950         /* Detach the interfaces, free buffer memory. */
  951         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  952                 drv_t *d = (drv_t*) c->sys;
  953 
  954                 if (!d || d->chan->type == T_NONE)
  955                         continue;
  956                         
  957                 if (d->tty) {
  958                         ttyfree (d->tty);
  959                         d->tty = NULL;
  960                 }
  961 
  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         }
  996         splx (s);
  997         
  998         s = splhigh ();
  999         for (c = b->chan; c < b->chan + NCHAN; ++c) {
 1000                 drv_t *d = (drv_t*) c->sys;
 1001 
 1002                 if (!d || d->chan->type == T_NONE)
 1003                         continue;
 1004                 
 1005                 /* Deallocate buffers. */
 1006                 cx_bus_dma_mem_free (&d->dmamem);
 1007         }
 1008         bd->board = 0;
 1009         adapter [b->num] = 0;
 1010         free (b, M_DEVBUF);
 1011         splx (s);
 1012 
 1013         mtx_destroy (&bd->cx_mtx);
 1014         
 1015         return 0;       
 1016 }
 1017 
 1018 #ifndef NETGRAPH
 1019 static void cx_ifstart (struct ifnet *ifp)
 1020 {
 1021         drv_t *d = ifp->if_softc;
 1022         bdrv_t *bd = d->board->sys;
 1023 
 1024         CX_LOCK (bd);
 1025         cx_start (d);
 1026         CX_UNLOCK (bd);
 1027 }
 1028 
 1029 static void cx_ifwatchdog (struct ifnet *ifp)
 1030 {
 1031         drv_t *d = ifp->if_softc;
 1032 
 1033         cx_watchdog (d);
 1034 }
 1035 
 1036 static void cx_tlf (struct sppp *sp)
 1037 {
 1038         drv_t *d = SP2IFP(sp)->if_softc;
 1039 
 1040         CX_DEBUG (d, ("cx_tlf\n"));
 1041 /*      cx_set_dtr (d->chan, 0);*/
 1042 /*      cx_set_rts (d->chan, 0);*/
 1043         if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
 1044                 sp->pp_down (sp);
 1045 }
 1046 
 1047 static void cx_tls (struct sppp *sp)
 1048 {
 1049         drv_t *d = SP2IFP(sp)->if_softc;
 1050 
 1051         CX_DEBUG (d, ("cx_tls\n"));
 1052         if (!(IFP2SP(d->ifp)->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
 1053                 sp->pp_up (sp);
 1054 }
 1055 
 1056 /*
 1057  * Initialization of interface.
 1058  * It seems to be never called by upper level.
 1059  */
 1060 static void cx_initialize (void *softc)
 1061 {
 1062         drv_t *d = softc;
 1063 
 1064         CX_DEBUG (d, ("cx_initialize\n"));
 1065 }
 1066 
 1067 /*
 1068  * Process an ioctl request.
 1069  */
 1070 static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
 1071 {
 1072         drv_t *d = ifp->if_softc;
 1073         bdrv_t *bd = d->board->sys;
 1074         int error, s, was_up, should_be_up;
 1075 
 1076         /* No socket ioctls while the channel is in async mode. */
 1077         if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC)
 1078                 return EBUSY;
 1079 
 1080         /* Socket ioctls on slave subchannels are not allowed. */
 1081         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
 1082         error = sppp_ioctl (ifp, cmd, data);
 1083         if (error)
 1084                 return error;
 1085 
 1086         s = splhigh ();
 1087         CX_LOCK (bd);
 1088         if (! (ifp->if_flags & IFF_DEBUG))
 1089                 d->chan->debug = 0;
 1090         else
 1091                 d->chan->debug = d->chan->debug_shadow;
 1092         CX_UNLOCK (bd);
 1093         splx (s);
 1094 
 1095         switch (cmd) {
 1096         default:           CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
 1097         case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
 1098         case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
 1099         case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
 1100         case SIOCSIFADDR:  CX_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
 1101         }
 1102 
 1103         /* We get here only in case of SIFFLAGS or SIFADDR. */
 1104         s = splhigh ();
 1105         CX_LOCK (bd);
 1106         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
 1107         if (!was_up && should_be_up) {
 1108                 /* Interface goes up -- start it. */
 1109                 cx_up (d);
 1110                 cx_start (d);
 1111         } else if (was_up && !should_be_up) {
 1112                 /* Interface is going down -- stop it. */
 1113                 /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
 1114                 cx_down (d);
 1115         }
 1116         CX_UNLOCK (bd);
 1117         splx (s);
 1118         return 0;
 1119 }
 1120 #endif /*NETGRAPH*/
 1121 
 1122 /*
 1123  * Stop the interface.  Called on splimp().
 1124  */
 1125 static void cx_down (drv_t *d)
 1126 {
 1127         int s = splhigh ();
 1128         CX_DEBUG (d, ("cx_down\n"));
 1129         cx_set_dtr (d->chan, 0);
 1130         cx_set_rts (d->chan, 0);
 1131         d->running = 0;
 1132         splx (s);
 1133 }
 1134 
 1135 /*
 1136  * Start the interface.  Called on splimp().
 1137  */
 1138 static void cx_up (drv_t *d)
 1139 {
 1140         int s = splhigh ();
 1141         CX_DEBUG (d, ("cx_up\n"));
 1142         cx_set_dtr (d->chan, 1);
 1143         cx_set_rts (d->chan, 1);
 1144         d->running = 1;
 1145         splx (s);
 1146 }
 1147 
 1148 /*
 1149  * Start output on the (slave) interface.  Get another datagram to send
 1150  * off of the interface queue, and copy it to the interface
 1151  * before starting the output.
 1152  */
 1153 static void cx_send (drv_t *d)
 1154 {
 1155         struct mbuf *m;
 1156         u_short len;
 1157 
 1158         CX_DEBUG2 (d, ("cx_send\n"));
 1159 
 1160         /* No output if the interface is down. */
 1161         if (! d->running)
 1162                 return;
 1163 
 1164         /* No output if the modem is off. */
 1165         if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan))
 1166                 return;
 1167 
 1168         if (cx_buf_free (d->chan)) {
 1169                 /* Get the packet to send. */
 1170 #ifdef NETGRAPH
 1171                 IF_DEQUEUE (&d->hi_queue, m);
 1172                 if (! m)
 1173                         IF_DEQUEUE (&d->lo_queue, m);
 1174 #else
 1175                 m = sppp_dequeue (d->ifp);
 1176 #endif
 1177                 if (! m)
 1178                         return;
 1179 #ifndef NETGRAPH
 1180                 BPF_MTAP (d->ifp, m);
 1181 #endif
 1182                 len = m_length (m, NULL);
 1183                 if (! m->m_next)
 1184                         cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
 1185                                 len, 0);
 1186                 else {
 1187                         u_char buf [DMABUFSZ];
 1188                         m_copydata (m, 0, len, buf);
 1189                         cx_send_packet (d->chan, buf, len, 0);
 1190                 }
 1191                 m_freem (m);
 1192 
 1193                 /* Set up transmit timeout, 10 seconds. */
 1194 #ifdef NETGRAPH
 1195                 d->timeout = 10;
 1196 #else
 1197                 d->ifp->if_timer = 10;
 1198 #endif
 1199         }
 1200 #ifndef NETGRAPH
 1201         d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 1202 #endif
 1203 }
 1204 
 1205 /*
 1206  * Start output on the interface.
 1207  * Always called on splimp().
 1208  */
 1209 static void cx_start (drv_t *d)
 1210 {
 1211         int s = splhigh ();
 1212         if (d->running) {
 1213                 if (! d->chan->dtr)
 1214                         cx_set_dtr (d->chan, 1);
 1215                 if (! d->chan->rts)
 1216                         cx_set_rts (d->chan, 1);
 1217                 cx_send (d);
 1218         }
 1219         splx (s);
 1220 }
 1221 
 1222 /*
 1223  * Handle transmit timeouts.
 1224  * Recover after lost transmit interrupts.
 1225  * Always called on splimp().
 1226  */
 1227 static void cx_watchdog (drv_t *d)
 1228 {
 1229         bdrv_t *bd = d->board->sys;
 1230         
 1231         int s = splhigh ();
 1232         CX_LOCK (bd);
 1233         CX_DEBUG (d, ("device timeout\n"));
 1234         if (d->running) {
 1235                 cx_setup_chan (d->chan);
 1236                 cx_start_chan (d->chan, 0, 0);
 1237                 cx_set_dtr (d->chan, 1);
 1238                 cx_set_rts (d->chan, 1);
 1239                 cx_start (d);
 1240         }
 1241         CX_UNLOCK (bd);
 1242         splx (s);
 1243 }
 1244 
 1245 /*
 1246  * Transmit callback function.
 1247  */
 1248 static void cx_transmit (cx_chan_t *c, void *attachment, int len)
 1249 {
 1250         drv_t *d = c->sys;
 1251 
 1252         if (!d)
 1253                 return;
 1254                 
 1255         if (c->mode == M_ASYNC && d->tty) {
 1256                 d->tty->t_state &= ~(TS_BUSY | TS_FLUSH);
 1257                 d->atimeout = 0;
 1258                 if (d->tty->t_dev) {
 1259                         d->intr_action |= CX_WRITE;
 1260                         MY_SOFT_INTR = 1;
 1261                         swi_sched (cx_fast_ih, 0);
 1262                 }
 1263                 return;
 1264         }
 1265 #ifdef NETGRAPH
 1266         d->timeout = 0;
 1267 #else
 1268         ++d->ifp->if_opackets;
 1269         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1270         d->ifp->if_timer = 0;
 1271 #endif
 1272         cx_start (d);
 1273 }
 1274 
 1275 /*
 1276  * Process the received packet.
 1277  */
 1278 static void cx_receive (cx_chan_t *c, char *data, int len)
 1279 {
 1280         drv_t *d = c->sys;
 1281         struct mbuf *m;
 1282         char *cc = data;
 1283 #ifdef NETGRAPH
 1284         int error;
 1285 #endif
 1286 
 1287         if (!d)
 1288                 return;
 1289                 
 1290         if (c->mode == M_ASYNC && d->tty) {
 1291                 if (d->tty->t_state & TS_ISOPEN) {
 1292                         async_q *q = &d->aqueue;
 1293                         int size = BF_SZ - 1 - AQ_GSZ (q);
 1294 
 1295                         if (len <= 0 && !size)
 1296                                 return;
 1297 
 1298                         if (len > size) {
 1299                                 c->ierrs++;
 1300                                 cx_error (c, CX_OVERRUN);
 1301                                 len = size - 1;
 1302                         }
 1303 
 1304                         while (len--) {
 1305                                 AQ_PUSH (q, *(unsigned char *)cc);
 1306                                 cc++;
 1307                         }
 1308 
 1309                         d->intr_action |= CX_READ;
 1310                         MY_SOFT_INTR = 1;
 1311                         swi_sched (cx_fast_ih, 0);
 1312                 }
 1313                 return;
 1314         }
 1315         if (! d->running)
 1316                 return;
 1317 
 1318         m = makembuf (data, len);
 1319         if (! m) {
 1320                 CX_DEBUG (d, ("no memory for packet\n"));
 1321 #ifndef NETGRAPH
 1322                 ++d->ifp->if_iqdrops;
 1323 #endif
 1324                 return;
 1325         }
 1326         if (c->debug > 1)
 1327                 printmbuf (m);
 1328 #ifdef NETGRAPH
 1329         m->m_pkthdr.rcvif = 0;
 1330         NG_SEND_DATA_ONLY (error, d->hook, m);
 1331 #else
 1332         ++d->ifp->if_ipackets;
 1333         m->m_pkthdr.rcvif = d->ifp;
 1334         /* Check if there's a BPF listener on this interface.
 1335          * If so, hand off the raw packet to bpf. */
 1336         BPF_TAP (d->ifp, data, len);
 1337         IF_ENQUEUE (&d->queue, m);
 1338 #endif
 1339 }
 1340 
 1341 #define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\
 1342             && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\
 1343             && (!(tp->t_iflag & PARMRK)\
 1344                 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\
 1345             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\
 1346             && linesw[tp->t_line]->l_rint == ttyinput)
 1347 
 1348 /*
 1349  * Error callback function.
 1350  */
 1351 static void cx_error (cx_chan_t *c, int data)
 1352 {
 1353         drv_t *d = c->sys;
 1354         async_q *q;
 1355 
 1356         if (!d)
 1357                 return;
 1358 
 1359         q = &(d->aqueue);
 1360 
 1361         switch (data) {
 1362         case CX_FRAME:
 1363                 CX_DEBUG (d, ("frame error\n"));
 1364                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1365                         && (AQ_GSZ (q) < BF_SZ - 1)
 1366                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1367                         || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) {
 1368                         AQ_PUSH (q, TTY_FE);
 1369                         d->intr_action |= CX_READ;
 1370                         MY_SOFT_INTR = 1;
 1371                         swi_sched (cx_fast_ih, 0);
 1372                 }
 1373 #ifndef NETGRAPH
 1374                 else
 1375                         ++d->ifp->if_ierrors;
 1376 #endif
 1377                 break;
 1378         case CX_CRC:
 1379                 CX_DEBUG (d, ("crc error\n"));
 1380                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1381                         && (AQ_GSZ (q) < BF_SZ - 1)
 1382                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1383                         || !(d->tty->t_iflag & INPCK)
 1384                         || !(d->tty->t_iflag & (IGNPAR | PARMRK)))) {
 1385                         AQ_PUSH (q, TTY_PE);
 1386                         d->intr_action |= CX_READ;
 1387                         MY_SOFT_INTR = 1;
 1388                         swi_sched (cx_fast_ih, 0);
 1389                 }
 1390 #ifndef NETGRAPH
 1391                 else
 1392                         ++d->ifp->if_ierrors;
 1393 #endif
 1394                 break;
 1395         case CX_OVERRUN:
 1396                 CX_DEBUG (d, ("overrun error\n"));
 1397 #ifdef TTY_OE
 1398                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1399                         && (AQ_GSZ (q) < BF_SZ - 1)
 1400                         && (!CONDITION((&d->tty->t_termios), (d->tty)))) {
 1401                         AQ_PUSH (q, TTY_OE);
 1402                         d->intr_action |= CX_READ;
 1403                         MY_SOFT_INTR = 1;
 1404                         swi_sched (cx_fast_ih, 0);
 1405                 }
 1406 #endif
 1407 #ifndef NETGRAPH
 1408                 else {
 1409                         ++d->ifp->if_collisions;
 1410                         ++d->ifp->if_ierrors;
 1411                 }
 1412 #endif
 1413                 break;
 1414         case CX_OVERFLOW:
 1415                 CX_DEBUG (d, ("overflow error\n"));
 1416 #ifndef NETGRAPH
 1417                 if (c->mode != M_ASYNC)
 1418                         ++d->ifp->if_ierrors;
 1419 #endif
 1420                 break;
 1421         case CX_UNDERRUN:
 1422                 CX_DEBUG (d, ("underrun error\n"));
 1423                 if (c->mode != M_ASYNC) {
 1424 #ifdef NETGRAPH
 1425                         d->timeout = 0;
 1426 #else
 1427                         ++d->ifp->if_oerrors;
 1428                         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1429                         d->ifp->if_timer = 0;
 1430                         cx_start (d);
 1431 #endif
 1432                 }
 1433                 break;
 1434         case CX_BREAK:
 1435                 CX_DEBUG (d, ("break error\n"));
 1436                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN)
 1437                         && (AQ_GSZ (q) < BF_SZ - 1)
 1438                         && (!CONDITION((&d->tty->t_termios), (d->tty))
 1439                         || !(d->tty->t_iflag & (IGNBRK | BRKINT | PARMRK)))) {
 1440                         AQ_PUSH (q, TTY_BI);
 1441                         d->intr_action |= CX_READ;
 1442                         MY_SOFT_INTR = 1;
 1443                         swi_sched (cx_fast_ih, 0);
 1444                 }
 1445 #ifndef NETGRAPH
 1446                 else
 1447                         ++d->ifp->if_ierrors;
 1448 #endif
 1449                 break;
 1450         default:
 1451                 CX_DEBUG (d, ("error #%d\n", data));
 1452         }
 1453 }
 1454 
 1455 static int cx_topen (struct tty *tp, struct cdev *dev)
 1456 {
 1457         bdrv_t *bd;
 1458         drv_t *d;
 1459 
 1460         d = tp->t_sc;
 1461         CX_DEBUG2 (d, ("cx_open (serial)\n"));
 1462 
 1463         bd = d->board->sys;
 1464 
 1465         if (d->chan->mode != M_ASYNC)
 1466                 return (EBUSY);
 1467 
 1468         d->open_dev |= 0x2;
 1469         CX_LOCK (bd);
 1470         cx_start_chan (d->chan, 0, 0);
 1471         cx_set_dtr (d->chan, 1);
 1472         cx_set_rts (d->chan, 1);
 1473         d->cd = cx_get_cd (d->chan);
 1474         CX_UNLOCK (bd);
 1475 
 1476         CX_DEBUG2 (d, ("cx_open done\n"));
 1477 
 1478         return 0;
 1479 }
 1480 
 1481 static void cx_tclose (struct tty *tp)
 1482 {
 1483         drv_t *d;
 1484         bdrv_t *bd;
 1485 
 1486         d = tp->t_sc;
 1487         CX_DEBUG2 (d, ("cx_close\n"));
 1488         bd = d->board->sys;
 1489         CX_LOCK (bd);
 1490         /* Disable receiver.
 1491          * Transmitter continues sending the queued data. */
 1492         cx_enable_receive (d->chan, 0);
 1493         CX_UNLOCK (bd);
 1494         d->open_dev &= ~0x2;
 1495 }
 1496 
 1497 static int cx_tmodem (struct tty *tp, int sigon, int sigoff)
 1498 {
 1499         drv_t *d;
 1500         bdrv_t *bd;
 1501 
 1502         d = tp->t_sc;
 1503         bd = d->board->sys;
 1504 
 1505         CX_LOCK (bd);
 1506         if (!sigon && !sigoff) {
 1507                 if (cx_get_dsr (d->chan)) sigon |= SER_DSR;
 1508                 if (cx_get_cd  (d->chan)) sigon |= SER_DCD;
 1509                 if (cx_get_cts (d->chan)) sigon |= SER_CTS;
 1510                 if (d->chan->dtr)         sigon |= SER_DTR;
 1511                 if (d->chan->rts)         sigon |= SER_RTS;
 1512                 CX_UNLOCK (bd);
 1513                 return sigon;
 1514         }
 1515 
 1516         if (sigon & SER_DTR)
 1517                 cx_set_dtr (d->chan, 1);
 1518         if (sigoff & SER_DTR)
 1519                 cx_set_dtr (d->chan, 0);
 1520         if (sigon & SER_RTS)
 1521                 cx_set_rts (d->chan, 1);
 1522         if (sigoff & SER_RTS)
 1523                 cx_set_rts (d->chan, 0);
 1524         CX_UNLOCK (bd);
 1525 
 1526         return (0);
 1527 }
 1528 
 1529 static int cx_open (struct cdev *dev, int flag, int mode, struct thread *td)
 1530 {
 1531         int unit;
 1532         drv_t *d;
 1533 
 1534         d = dev->si_drv1;
 1535         unit = d->chan->num;
 1536 
 1537         CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n",
 1538                     unit, flag, mode));
 1539 
 1540         d->open_dev |= 0x1;
 1541 
 1542         CX_DEBUG2 (d, ("cx_open done\n"));
 1543 
 1544         return 0;
 1545 }
 1546 
 1547 static int cx_close (struct cdev *dev, int flag, int mode, struct thread *td)
 1548 {
 1549         drv_t *d;
 1550 
 1551         d = dev->si_drv1;
 1552         CX_DEBUG2 (d, ("cx_close\n"));
 1553         d->open_dev &= ~0x1;
 1554         return 0;
 1555 }
 1556 
 1557 static int cx_modem_status (drv_t *d)
 1558 {
 1559         bdrv_t *bd = d->board->sys;
 1560         int status = 0, s = splhigh ();
 1561         CX_LOCK (bd);
 1562         /* Already opened by someone or network interface is up? */
 1563         if ((d->chan->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
 1564             (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running))
 1565                 status = TIOCM_LE;      /* always enabled while open */
 1566 
 1567         if (cx_get_dsr (d->chan)) status |= TIOCM_DSR;
 1568         if (cx_get_cd  (d->chan)) status |= TIOCM_CD;
 1569         if (cx_get_cts (d->chan)) status |= TIOCM_CTS;
 1570         if (d->chan->dtr)         status |= TIOCM_DTR;
 1571         if (d->chan->rts)         status |= TIOCM_RTS;
 1572         CX_UNLOCK (bd);
 1573         splx (s);
 1574         return status;
 1575 }
 1576 
 1577 static int cx_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 1578 {
 1579         drv_t *d;
 1580         bdrv_t *bd;
 1581         cx_chan_t *c;
 1582         struct serial_statistics *st;
 1583         int error, s;
 1584         char mask[16];
 1585 
 1586         d = dev->si_drv1;
 1587         c = d->chan;
 1588                 
 1589         bd = d->board->sys;
 1590         
 1591         switch (cmd) {
 1592         case SERIAL_GETREGISTERED:
 1593                 CX_DEBUG2 (d, ("ioctl: getregistered\n"));
 1594                 bzero (mask, sizeof(mask));
 1595                 for (s=0; s<NCX*NCHAN; ++s)
 1596                         if (channel [s])
 1597                                 mask [s/8] |= 1 << (s & 7);
 1598                 bcopy (mask, data, sizeof (mask));
 1599                 return 0;
 1600 
 1601         case SERIAL_GETPORT:
 1602                 CX_DEBUG2 (d, ("ioctl: getport\n"));
 1603                 s = splhigh ();
 1604                 CX_LOCK (bd);
 1605                 *(int *)data = cx_get_port (c);
 1606                 CX_UNLOCK (bd);
 1607                 splx (s);
 1608                 if (*(int *)data<0)
 1609                         return (EINVAL);
 1610                 else
 1611                         return 0;
 1612 
 1613         case SERIAL_SETPORT:
 1614                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1615                 /* Only for superuser! */
 1616                 error = priv_check (td, PRIV_DRIVER);
 1617                 if (error)
 1618                         return error;
 1619 
 1620                 s = splhigh ();
 1621                 CX_LOCK (bd);
 1622                 cx_set_port (c, *(int *)data);
 1623                 CX_UNLOCK (bd);
 1624                 splx (s);
 1625                 return 0;
 1626 
 1627 #ifndef NETGRAPH
 1628         case SERIAL_GETPROTO:
 1629                 CX_DEBUG2 (d, ("ioctl: getproto\n"));
 1630                 s = splhigh ();
 1631                 CX_LOCK (bd);
 1632                 strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" :
 1633                         (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
 1634                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
 1635                 CX_UNLOCK (bd);
 1636                 splx (s);
 1637                 return 0;
 1638 
 1639         case SERIAL_SETPROTO:
 1640                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1641                 /* Only for superuser! */
 1642                 error = priv_check (td, PRIV_DRIVER);
 1643                 if (error)
 1644                         return error;
 1645                 if (c->mode == M_ASYNC)
 1646                         return EBUSY;
 1647                 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
 1648                         return EBUSY;
 1649                 if (! strcmp ("cisco", (char*)data)) {
 1650                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
 1651                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
 1652                         d->ifp->if_flags |= PP_CISCO;
 1653                 } else if (! strcmp ("fr", (char*)data)) {
 1654                         d->ifp->if_flags &= ~(PP_CISCO);
 1655                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
 1656                 } else if (! strcmp ("ppp", (char*)data)) {
 1657                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE);
 1658                         d->ifp->if_flags &= ~(PP_CISCO);
 1659                 } else
 1660                         return EINVAL;
 1661                 return 0;
 1662 
 1663         case SERIAL_GETKEEPALIVE:
 1664                 CX_DEBUG2 (d, ("ioctl: getkeepalive\n"));
 1665                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
 1666                     (d->ifp->if_flags & PP_CISCO) ||
 1667                     (c->mode == M_ASYNC))
 1668                         return EINVAL;
 1669                 s = splhigh ();
 1670                 CX_LOCK (bd);
 1671                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
 1672                 CX_UNLOCK (bd);
 1673                 splx (s);
 1674                 return 0;
 1675 
 1676         case SERIAL_SETKEEPALIVE:
 1677                 CX_DEBUG2 (d, ("ioctl: setkeepalive\n"));
 1678                 /* Only for superuser! */
 1679                 error = priv_check (td, PRIV_DRIVER);
 1680                 if (error)
 1681                         return error;
 1682                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
 1683                         (d->ifp->if_flags & PP_CISCO))
 1684                         return EINVAL;
 1685                 s = splhigh ();
 1686                 CX_LOCK (bd);
 1687                 if (*(int*)data)
 1688                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
 1689                 else
 1690                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
 1691                 CX_UNLOCK (bd);
 1692                 splx (s);
 1693                 return 0;
 1694 #endif /*NETGRAPH*/
 1695 
 1696         case SERIAL_GETMODE:
 1697                 CX_DEBUG2 (d, ("ioctl: getmode\n"));
 1698                 s = splhigh ();
 1699                 CX_LOCK (bd);
 1700                 *(int*)data = (c->mode == M_ASYNC) ?
 1701                         SERIAL_ASYNC : SERIAL_HDLC;
 1702                 CX_UNLOCK (bd);
 1703                 splx (s);
 1704                 return 0;
 1705 
 1706         case SERIAL_SETMODE:
 1707                 CX_DEBUG2 (d, ("ioctl: setmode\n"));
 1708                 /* Only for superuser! */
 1709                 error = priv_check (td, PRIV_DRIVER);
 1710                 if (error)
 1711                         return error;
 1712 
 1713                 /* Somebody is waiting for carrier? */
 1714                 if (d->lock)
 1715                         return EBUSY;
 1716                 /* /dev/ttyXX is already opened by someone? */
 1717                 if (c->mode == M_ASYNC && d->tty && (d->tty->t_state & TS_ISOPEN) &&
 1718                     (d->open_dev|0x2))
 1719                         return EBUSY;
 1720                 /* Network interface is up?
 1721                  * Cannot change to async mode. */
 1722                 if (c->mode != M_ASYNC && d->running &&
 1723                     (*(int*)data == SERIAL_ASYNC))
 1724                         return EBUSY;
 1725 
 1726                 s = splhigh ();
 1727                 CX_LOCK (bd);
 1728                 if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) {
 1729                         cx_set_mode (c, M_ASYNC);
 1730                         cx_enable_receive (c, 0);
 1731                         cx_enable_transmit (c, 0);
 1732                 } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) {
 1733                         if (d->ifp->if_flags & IFF_DEBUG)
 1734                                 c->debug = c->debug_shadow;
 1735                         cx_set_mode (c, M_HDLC);
 1736                         cx_enable_receive (c, 1);
 1737                         cx_enable_transmit (c, 1);
 1738                 }
 1739                 CX_UNLOCK (bd);
 1740                 splx (s);
 1741                 return 0;
 1742 
 1743         case SERIAL_GETSTAT:
 1744                 CX_DEBUG2 (d, ("ioctl: getestat\n"));
 1745                 st = (struct serial_statistics*) data;
 1746                 s = splhigh ();
 1747                 CX_LOCK (bd);
 1748                 st->rintr  = c->rintr;
 1749                 st->tintr  = c->tintr;
 1750                 st->mintr  = c->mintr;
 1751                 st->ibytes = c->ibytes;
 1752                 st->ipkts  = c->ipkts;
 1753                 st->ierrs  = c->ierrs;
 1754                 st->obytes = c->obytes;
 1755                 st->opkts  = c->opkts;
 1756                 st->oerrs  = c->oerrs;
 1757                 CX_UNLOCK (bd);
 1758                 splx (s);
 1759                 return 0;
 1760 
 1761         case SERIAL_CLRSTAT:
 1762                 CX_DEBUG2 (d, ("ioctl: clrstat\n"));
 1763                 /* Only for superuser! */
 1764                 error = priv_check (td, PRIV_DRIVER);
 1765                 if (error)
 1766                         return error;
 1767                 s = splhigh ();
 1768                 CX_LOCK (bd);
 1769                 c->rintr = 0;
 1770                 c->tintr = 0;
 1771                 c->mintr = 0;
 1772                 c->ibytes = 0;
 1773                 c->ipkts = 0;
 1774                 c->ierrs = 0;
 1775                 c->obytes = 0;
 1776                 c->opkts = 0;
 1777                 c->oerrs = 0;
 1778                 CX_UNLOCK (bd);
 1779                 splx (s);
 1780                 return 0;
 1781 
 1782         case SERIAL_GETBAUD:
 1783                 CX_DEBUG2 (d, ("ioctl: getbaud\n"));
 1784                 if (c->mode == M_ASYNC)
 1785                         return EINVAL;
 1786                 s = splhigh ();
 1787                 CX_LOCK (bd);
 1788                 *(long*)data = cx_get_baud(c);
 1789                 CX_UNLOCK (bd);
 1790                 splx (s);
 1791                 return 0;
 1792 
 1793         case SERIAL_SETBAUD:
 1794                 CX_DEBUG2 (d, ("ioctl: setbaud\n"));
 1795                 /* Only for superuser! */
 1796                 error = priv_check (td, PRIV_DRIVER);
 1797                 if (error)
 1798                         return error;
 1799                 if (c->mode == M_ASYNC)
 1800                         return EINVAL;
 1801                 s = splhigh ();
 1802                 CX_LOCK (bd);
 1803                 cx_set_baud (c, *(long*)data);
 1804                 CX_UNLOCK (bd);
 1805                 splx (s);
 1806                 return 0;
 1807 
 1808         case SERIAL_GETLOOP:
 1809                 CX_DEBUG2 (d, ("ioctl: getloop\n"));
 1810                 if (c->mode == M_ASYNC)
 1811                         return EINVAL;
 1812                 s = splhigh ();
 1813                 CX_LOCK (bd);
 1814                 *(int*)data = cx_get_loop (c);
 1815                 CX_UNLOCK (bd);
 1816                 splx (s);
 1817                 return 0;
 1818 
 1819         case SERIAL_SETLOOP:
 1820                 CX_DEBUG2 (d, ("ioctl: setloop\n"));
 1821                 /* Only for superuser! */
 1822                 error = priv_check (td, PRIV_DRIVER);
 1823                 if (error)
 1824                         return error;
 1825                 if (c->mode == M_ASYNC)
 1826                         return EINVAL;
 1827                 s = splhigh ();
 1828                 CX_LOCK (bd);
 1829                 cx_set_loop (c, *(int*)data);
 1830                 CX_UNLOCK (bd);
 1831                 splx (s);
 1832                 return 0;
 1833 
 1834         case SERIAL_GETDPLL:
 1835                 CX_DEBUG2 (d, ("ioctl: getdpll\n"));
 1836                 if (c->mode == M_ASYNC)
 1837                         return EINVAL;
 1838                 s = splhigh ();
 1839                 CX_LOCK (bd);
 1840                 *(int*)data = cx_get_dpll (c);
 1841                 CX_UNLOCK (bd);
 1842                 splx (s);
 1843                 return 0;
 1844 
 1845         case SERIAL_SETDPLL:
 1846                 CX_DEBUG2 (d, ("ioctl: setdpll\n"));
 1847                 /* Only for superuser! */
 1848                 error = priv_check (td, PRIV_DRIVER);
 1849                 if (error)
 1850                         return error;
 1851                 if (c->mode == M_ASYNC)
 1852                         return EINVAL;
 1853                 s = splhigh ();
 1854                 CX_LOCK (bd);
 1855                 cx_set_dpll (c, *(int*)data);
 1856                 CX_UNLOCK (bd);
 1857                 splx (s);
 1858                 return 0;
 1859 
 1860         case SERIAL_GETNRZI:
 1861                 CX_DEBUG2 (d, ("ioctl: getnrzi\n"));
 1862                 if (c->mode == M_ASYNC)
 1863                         return EINVAL;
 1864                 s = splhigh ();
 1865                 CX_LOCK (bd);
 1866                 *(int*)data = cx_get_nrzi (c);
 1867                 CX_UNLOCK (bd);
 1868                 splx (s);
 1869                 return 0;
 1870 
 1871         case SERIAL_SETNRZI:
 1872                 CX_DEBUG2 (d, ("ioctl: setnrzi\n"));
 1873                 /* Only for superuser! */
 1874                 error = priv_check (td, PRIV_DRIVER);
 1875                 if (error)
 1876                         return error;
 1877                 if (c->mode == M_ASYNC)
 1878                         return EINVAL;
 1879                 s = splhigh ();
 1880                 CX_LOCK (bd);
 1881                 cx_set_nrzi (c, *(int*)data);
 1882                 CX_UNLOCK (bd);
 1883                 splx (s);
 1884                 return 0;
 1885 
 1886         case SERIAL_GETDEBUG:
 1887                 CX_DEBUG2 (d, ("ioctl: getdebug\n"));
 1888                 s = splhigh ();
 1889                 CX_LOCK (bd);
 1890                 *(int*)data = c->debug;
 1891                 CX_UNLOCK (bd);
 1892                 splx (s);
 1893                 return 0;
 1894 
 1895         case SERIAL_SETDEBUG:
 1896                 CX_DEBUG2 (d, ("ioctl: setdebug\n"));
 1897                 /* Only for superuser! */
 1898                 error = priv_check (td, PRIV_DRIVER);
 1899                 if (error)
 1900                         return error;
 1901                 s = splhigh ();
 1902                 CX_LOCK (bd);
 1903 #ifndef NETGRAPH
 1904                 if (c->mode == M_ASYNC) {
 1905                         c->debug = *(int*)data;
 1906                 } else {
 1907                         /*
 1908                          * The debug_shadow is always greater than zero for
 1909                          * logic simplicity.  For switching debug off the
 1910                          * IFF_DEBUG is responsible (for !M_ASYNC mode).
 1911                          */
 1912                         c->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
 1913                         if (d->ifp->if_flags & IFF_DEBUG)
 1914                                 c->debug = c->debug_shadow;
 1915                 }
 1916 #else
 1917                 c->debug = *(int*)data;
 1918 #endif
 1919                 CX_UNLOCK (bd);
 1920                 splx (s);
 1921                 return 0;
 1922         }
 1923 
 1924         switch (cmd) {
 1925         case TIOCSDTR:  /* Set DTR */
 1926                 CX_DEBUG2 (d, ("ioctl: tiocsdtr\n"));
 1927                 s = splhigh ();
 1928                 CX_LOCK (bd);
 1929                 cx_set_dtr (c, 1);
 1930                 CX_UNLOCK (bd);
 1931                 splx (s);
 1932                 return 0;
 1933 
 1934         case TIOCCDTR:  /* Clear DTR */
 1935                 CX_DEBUG2 (d, ("ioctl: tioccdtr\n"));
 1936                 s = splhigh ();
 1937                 CX_LOCK (bd);
 1938                 cx_set_dtr (c, 0);
 1939                 CX_UNLOCK (bd);
 1940                 splx (s);
 1941                 return 0;
 1942 
 1943         case TIOCMSET:  /* Set DTR/RTS */
 1944                 CX_DEBUG2 (d, ("ioctl: tiocmset\n"));
 1945                 s = splhigh ();
 1946                 CX_LOCK (bd);
 1947                 cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
 1948                 cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
 1949                 CX_UNLOCK (bd);
 1950                 splx (s);
 1951                 return 0;
 1952 
 1953         case TIOCMBIS:  /* Add DTR/RTS */
 1954                 CX_DEBUG2 (d, ("ioctl: tiocmbis\n"));
 1955                 s = splhigh ();
 1956                 CX_LOCK (bd);
 1957                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1);
 1958                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1);
 1959                 CX_UNLOCK (bd);
 1960                 splx (s);
 1961                 return 0;
 1962 
 1963         case TIOCMBIC:  /* Clear DTR/RTS */
 1964                 CX_DEBUG2 (d, ("ioctl: tiocmbic\n"));
 1965                 s = splhigh ();
 1966                 CX_LOCK (bd);
 1967                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0);
 1968                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0);
 1969                 CX_UNLOCK (bd);
 1970                 splx (s);
 1971                 return 0;
 1972 
 1973         case TIOCMGET:  /* Get modem status */
 1974                 CX_DEBUG2 (d, ("ioctl: tiocmget\n"));
 1975                 *(int*)data = cx_modem_status (d);
 1976                 return 0;
 1977 
 1978         }
 1979 
 1980         CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd));
 1981         return ENOTTY;
 1982 }
 1983 
 1984 void cx_softintr (void *unused)
 1985 {
 1986         drv_t *d;
 1987         bdrv_t *bd;
 1988         async_q *q;
 1989         int i, s, ic, k;
 1990         while (MY_SOFT_INTR) {
 1991                 MY_SOFT_INTR = 0;
 1992                 for (i=0; i<NCX*NCHAN; ++i) {
 1993                         d = channel [i];
 1994                         if (!d || !d->chan || d->chan->type == T_NONE
 1995                             || d->chan->mode != M_ASYNC || !d->tty
 1996                             || !d->tty->t_dev)
 1997                                 continue;
 1998                         bd = d->board->sys;
 1999                         s = splhigh ();
 2000                         CX_LOCK (bd);
 2001                         if (d->intr_action & CX_READ) {
 2002                                 q = &(d->aqueue);
 2003                                 if (d->tty->t_state & TS_CAN_BYPASS_L_RINT) {
 2004                                         k = AQ_GSZ(q);
 2005                                         if (d->tty->t_rawq.c_cc + k >
 2006                                                 d->tty->t_ihiwat
 2007                                             && (d->tty->t_cflag & CRTS_IFLOW
 2008                                                 || d->tty->t_iflag & IXOFF)
 2009                                             && !(d->tty->t_state & TS_TBLOCK))
 2010                                                 ttyblock(d->tty);
 2011                                         d->tty->t_rawcc += k;
 2012                                         while (k>0) {
 2013                                                 k--;
 2014                                                 AQ_POP (q, ic);
 2015                                                 CX_UNLOCK (bd);
 2016                                                 splx (s);
 2017                                                 putc (ic, &d->tty->t_rawq);
 2018                                                 s = splhigh ();
 2019                                                 CX_LOCK (bd);
 2020                                         }
 2021                                         ttwakeup(d->tty);
 2022                                         if (d->tty->t_state & TS_TTSTOP
 2023                                             && (d->tty->t_iflag & IXANY
 2024                                                 || d->tty->t_cc[VSTART] ==
 2025                                                 d->tty->t_cc[VSTOP])) {
 2026                                                 d->tty->t_state &= ~TS_TTSTOP;
 2027                                                 d->tty->t_lflag &= ~FLUSHO;
 2028                                                 d->intr_action |= CX_WRITE;
 2029                                         }
 2030                                 } else {
 2031                                         while (q->end != q->beg) {
 2032                                                 AQ_POP (q, ic);
 2033                                                 CX_UNLOCK (bd);
 2034                                                 splx (s);
 2035                                                 ttyld_rint (d->tty, ic);
 2036                                                 s = splhigh ();
 2037                                                 CX_LOCK (bd);
 2038                                         }
 2039                                 }
 2040                                 d->intr_action &= ~CX_READ;
 2041                         }
 2042                         splx (s);
 2043                         CX_UNLOCK (bd);
 2044 
 2045                         s = splhigh ();
 2046                         CX_LOCK (bd);
 2047                         if (d->intr_action & CX_WRITE) {
 2048                                 if (d->tty->t_line)
 2049                                         ttyld_start (d->tty);
 2050                                 else
 2051                                         cx_oproc (d->tty);
 2052                                 d->intr_action &= ~CX_WRITE;
 2053                         }
 2054                         CX_UNLOCK (bd);
 2055                         splx (s);
 2056 
 2057                 }
 2058         }
 2059 }
 2060 
 2061 /*
 2062  * Fill transmitter buffer with data.
 2063  */
 2064 static void cx_oproc (struct tty *tp)
 2065 {
 2066         int s, k;
 2067         drv_t *d;
 2068         bdrv_t *bd;
 2069         static u_char buf[DMABUFSZ];
 2070         u_char *p;
 2071         u_short len = 0, sublen = 0;
 2072 
 2073         d = tp->t_sc;
 2074         bd = d->board->sys;
 2075 
 2076         CX_DEBUG2 (d, ("cx_oproc\n"));
 2077 
 2078         s = splhigh ();
 2079         CX_LOCK (bd);
 2080 
 2081         if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts)
 2082                 cx_set_rts (d->chan, 0);
 2083         else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts)
 2084                 cx_set_rts (d->chan, 1);
 2085 
 2086         if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
 2087                 /* Start transmitter. */
 2088                 cx_enable_transmit (d->chan, 1);
 2089 
 2090                 /* Is it busy? */
 2091                 if (! cx_buf_free (d->chan)) {
 2092                         tp->t_state |= TS_BUSY;
 2093                         CX_UNLOCK (bd);
 2094                         splx (s);
 2095                         return;
 2096                 }
 2097                 if (tp->t_iflag & IXOFF) {
 2098                         p = (buf + (DMABUFSZ/2));
 2099                         sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2100                         k = sublen;
 2101                         while (k--) {
 2102                                 /* Send XON/XOFF out of band. */
 2103                                 if (*p == tp->t_cc[VSTOP]) {
 2104                                         cx_xflow_ctl (d->chan, 0);
 2105                                         p++;
 2106                                         continue;
 2107                                 }
 2108                                 if (*p == tp->t_cc[VSTART]) {
 2109                                         cx_xflow_ctl (d->chan, 1);
 2110                                         p++;
 2111                                         continue;
 2112                                 }
 2113                                 buf[len] = *p;
 2114                                 len++;
 2115                                 p++;
 2116                         }
 2117                 } else {
 2118                         p = buf;
 2119                         len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2120                 }
 2121                 if (len) {
 2122                         cx_send_packet (d->chan, buf, len, 0);
 2123                         tp->t_state |= TS_BUSY;
 2124                         d->atimeout = 10;
 2125                         CX_DEBUG2 (d, ("out %d bytes\n", len));
 2126                 }
 2127         }
 2128         ttwwakeup (tp);
 2129         CX_UNLOCK (bd);
 2130         splx (s);
 2131 }
 2132 
 2133 static int cx_param (struct tty *tp, struct termios *t)
 2134 {
 2135         drv_t *d;
 2136         bdrv_t *bd;
 2137         int s, bits, parity;
 2138 
 2139         d = tp->t_sc;
 2140         bd = d->board->sys;
 2141         
 2142         s = splhigh ();
 2143         CX_LOCK (bd);
 2144         if (t->c_ospeed == 0) {
 2145                 /* Clear DTR and RTS. */
 2146                 cx_set_dtr (d->chan, 0);
 2147                 CX_UNLOCK (bd);
 2148                 splx (s);
 2149                 CX_DEBUG2 (d, ("cx_param (hangup)\n"));
 2150                 return 0;
 2151         }
 2152         CX_DEBUG2 (d, ("cx_param\n"));
 2153 
 2154         /* Check requested parameters. */
 2155         if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) {
 2156                 CX_UNLOCK (bd);
 2157                 splx (s);
 2158                 return EINVAL;
 2159         }
 2160         if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) {
 2161                 CX_UNLOCK (bd);
 2162                 splx (s);
 2163                 return EINVAL;
 2164         }
 2165 
 2166         /* And copy them to tty and channel structures. */
 2167         tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed;
 2168         tp->t_cflag = t->c_cflag;
 2169 
 2170         /* Set character length and parity mode. */
 2171         switch (t->c_cflag & CSIZE) {
 2172         default:
 2173         case CS8: bits = 8; break;
 2174         case CS7: bits = 7; break;
 2175         case CS6: bits = 6; break;
 2176         case CS5: bits = 5; break;
 2177         }
 2178 
 2179         parity = ((t->c_cflag & PARENB) ? 1 : 0) *
 2180                  (1 + ((t->c_cflag & PARODD) ? 0 : 1));
 2181 
 2182         /* Set current channel number. */
 2183         if (! d->chan->dtr)
 2184                 cx_set_dtr (d->chan, 1);
 2185 
 2186         ttyldoptim (tp);
 2187         cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB),
 2188                 !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS),
 2189                 (t->c_iflag & IXON), (t->c_iflag & IXANY),
 2190                 t->c_cc[VSTART], t->c_cc[VSTOP]);
 2191         CX_UNLOCK (bd);
 2192         splx (s);
 2193         return 0;
 2194 }
 2195 
 2196 /*
 2197  * Stop output on a line
 2198  */
 2199 static void cx_stop (struct tty *tp, int flag)
 2200 {
 2201         drv_t *d;
 2202         bdrv_t *bd;
 2203         int s;
 2204 
 2205         d = tp->t_sc;
 2206         bd = d->board->sys;
 2207         
 2208         s = splhigh ();
 2209         CX_LOCK (bd);
 2210         if (tp->t_state & TS_BUSY) {
 2211                 /* Stop transmitter */
 2212                 CX_DEBUG2 (d, ("cx_stop\n"));
 2213                 cx_transmitter_ctl (d->chan, 0);
 2214         }
 2215         CX_UNLOCK (bd);
 2216         splx (s);
 2217 }
 2218 
 2219 /*
 2220  * Process the (delayed) carrier signal setup.
 2221  */
 2222 static void cx_carrier (void *arg)
 2223 {
 2224         drv_t *d = arg;
 2225         bdrv_t *bd = d->board->sys;
 2226         cx_chan_t *c = d->chan;
 2227         int s, cd;
 2228 
 2229         s = splhigh ();
 2230         CX_LOCK (bd);
 2231         cd = cx_get_cd (c);
 2232         if (d->cd != cd) {
 2233                 if (cd) {
 2234                         CX_DEBUG (d, ("carrier on\n"));
 2235                         d->cd = 1;
 2236                         CX_UNLOCK (bd);
 2237                         splx (s);
 2238                         if (d->tty)
 2239                                 ttyld_modem(d->tty, 1);
 2240                 } else {
 2241                         CX_DEBUG (d, ("carrier loss\n"));
 2242                         d->cd = 0;
 2243                         CX_UNLOCK (bd);
 2244                         splx (s);
 2245                         if (d->tty)
 2246                                 ttyld_modem(d->tty, 0);
 2247                 }
 2248         } else {
 2249                 CX_UNLOCK (bd);
 2250                 splx (s);
 2251         }
 2252 }
 2253 
 2254 /*
 2255  * Modem signal callback function.
 2256  */
 2257 static void cx_modem (cx_chan_t *c)
 2258 {
 2259         drv_t *d = c->sys;
 2260 
 2261         if (!d || c->mode != M_ASYNC)
 2262                 return;
 2263         /* Handle carrier detect/loss. */
 2264         /* Carrier changed - delay processing DCD for a while
 2265          * to give both sides some time to initialize. */
 2266         callout_reset (&d->dcd_timeout_handle, hz/2, cx_carrier, d);
 2267 }
 2268 
 2269 #ifdef NETGRAPH
 2270 static int ng_cx_constructor (node_p node)
 2271 {
 2272         drv_t *d = NG_NODE_PRIVATE (node);
 2273         CX_DEBUG (d, ("Constructor\n"));
 2274         return EINVAL;
 2275 }
 2276 
 2277 static int ng_cx_newhook (node_p node, hook_p hook, const char *name)
 2278 {
 2279         int s;
 2280         drv_t *d = NG_NODE_PRIVATE (node);
 2281         bdrv_t *bd = d->board->sys;
 2282 
 2283         if (d->chan->mode == M_ASYNC)
 2284                 return EINVAL;
 2285 
 2286         /* Attach debug hook */
 2287         if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) {
 2288                 NG_HOOK_SET_PRIVATE (hook, NULL);
 2289                 d->debug_hook = hook;
 2290                 return 0;
 2291         }
 2292 
 2293         /* Check for raw hook */
 2294         if (strcmp (name, NG_CX_HOOK_RAW) != 0)
 2295                 return EINVAL;
 2296 
 2297         NG_HOOK_SET_PRIVATE (hook, d);
 2298         d->hook = hook;
 2299         s = splhigh ();
 2300         CX_LOCK (bd);
 2301         cx_up (d);
 2302         CX_UNLOCK (bd);
 2303         splx (s);
 2304         return 0;
 2305 }
 2306 
 2307 static int print_modems (char *s, cx_chan_t *c, int need_header)
 2308 {
 2309         int status = cx_modem_status (c->sys);
 2310         int length = 0;
 2311 
 2312         if (need_header)
 2313                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
 2314         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
 2315                 status & TIOCM_LE  ? "On" : "-",
 2316                 status & TIOCM_DTR ? "On" : "-",
 2317                 status & TIOCM_DSR ? "On" : "-",
 2318                 status & TIOCM_RTS ? "On" : "-",
 2319                 status & TIOCM_CTS ? "On" : "-",
 2320                 status & TIOCM_CD  ? "On" : "-");
 2321         return length;
 2322 }
 2323 
 2324 static int print_stats (char *s, cx_chan_t *c, int need_header)
 2325 {
 2326         int length = 0;
 2327 
 2328         if (need_header)
 2329                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
 2330         length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
 2331                 c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts,
 2332                 c->ierrs, c->obytes, c->opkts, c->oerrs);
 2333         return length;
 2334 }
 2335 
 2336 static int print_chan (char *s, cx_chan_t *c)
 2337 {
 2338         drv_t *d = c->sys;
 2339         int length = 0;
 2340 
 2341         length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num);
 2342         if (d->chan->debug)
 2343                 length += sprintf (s + length, " debug=%d", d->chan->debug);
 2344 
 2345         if (cx_get_baud (c))
 2346                 length += sprintf (s + length, " %ld", cx_get_baud (c));
 2347         else
 2348                 length += sprintf (s + length, " extclock");
 2349 
 2350         if (c->mode == M_HDLC) {
 2351                 length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off");
 2352                 length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off");
 2353         }
 2354 
 2355         length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n");
 2356         return length;
 2357 }
 2358 
 2359 static int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook)
 2360 {
 2361         drv_t *d = NG_NODE_PRIVATE (node);
 2362         struct ng_mesg *msg;
 2363         struct ng_mesg *resp = NULL;
 2364         int error = 0;
 2365 
 2366         if (!d)
 2367                 return EINVAL;
 2368                 
 2369         CX_DEBUG (d, ("Rcvmsg\n"));
 2370         NGI_GET_MSG (item, msg);
 2371         switch (msg->header.typecookie) {
 2372         default:
 2373                 error = EINVAL;
 2374                 break;
 2375 
 2376         case NGM_CX_COOKIE:
 2377                 printf ("Don't forget to implement\n");
 2378                 error = EINVAL;
 2379                 break;
 2380 
 2381         case NGM_GENERIC_COOKIE:
 2382                 switch (msg->header.cmd) {
 2383                 default:
 2384                         error = EINVAL;
 2385                         break;
 2386 
 2387                 case NGM_TEXT_STATUS: {
 2388                         char *s;
 2389                         int l = 0;
 2390                         int dl = sizeof (struct ng_mesg) + 730;
 2391 
 2392                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
 2393                         if (! resp) {
 2394                                 error = ENOMEM;
 2395                                 break;
 2396                         }
 2397                         bzero (resp, dl);
 2398                         s = (resp)->data;
 2399                         l += print_chan (s + l, d->chan);
 2400                         l += print_stats (s + l, d->chan, 1);
 2401                         l += print_modems (s + l, d->chan, 1);
 2402                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ);
 2403                         }
 2404                         break;
 2405                 }
 2406                 break;
 2407         }
 2408         NG_RESPOND_MSG (error, node, item, resp);
 2409         NG_FREE_MSG (msg);
 2410         return error;
 2411 }
 2412 
 2413 static int ng_cx_rcvdata (hook_p hook, item_p item)
 2414 {
 2415         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
 2416         struct mbuf *m;
 2417         struct ng_tag_prio *ptag;
 2418         bdrv_t *bd;
 2419         struct ifqueue *q;
 2420         int s;
 2421 
 2422         NGI_GET_M (item, m);
 2423         NG_FREE_ITEM (item);
 2424         if (! NG_HOOK_PRIVATE (hook) || ! d) {
 2425                 NG_FREE_M (m);
 2426                 return ENETDOWN;
 2427         }
 2428 
 2429         bd = d->board->sys;
 2430         /* Check for high priority data */
 2431         if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
 2432             NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
 2433                 q = &d->hi_queue;
 2434         else
 2435                 q = &d->lo_queue;
 2436 
 2437         s = splhigh ();
 2438         CX_LOCK (bd);
 2439         IF_LOCK (q);
 2440         if (_IF_QFULL (q)) {
 2441                 _IF_DROP (q);
 2442                 IF_UNLOCK (q);
 2443                 CX_UNLOCK (bd);
 2444                 splx (s);
 2445                 NG_FREE_M (m);
 2446                 return ENOBUFS;
 2447         }
 2448         _IF_ENQUEUE (q, m);
 2449         IF_UNLOCK (q);
 2450         cx_start (d);
 2451         CX_UNLOCK (bd);
 2452         splx (s);
 2453         return 0;
 2454 }
 2455 
 2456 static int ng_cx_rmnode (node_p node)
 2457 {
 2458         drv_t *d = NG_NODE_PRIVATE (node);
 2459         bdrv_t *bd;
 2460 
 2461         CX_DEBUG (d, ("Rmnode\n"));
 2462         if (d && d->running) {
 2463                 int s = splhigh ();
 2464                 bd = d->board->sys;
 2465                 CX_LOCK (bd);
 2466                 cx_down (d);
 2467                 CX_UNLOCK (bd);
 2468                 splx (s);
 2469         }
 2470 #ifdef  KLD_MODULE
 2471         if (node->nd_flags & NGF_REALLY_DIE) {
 2472                 NG_NODE_SET_PRIVATE (node, NULL);
 2473                 NG_NODE_UNREF (node);
 2474         }
 2475         NG_NODE_REVIVE(node);           /* Persistant node */
 2476 #endif
 2477         return 0;
 2478 }
 2479 
 2480 static void ng_cx_watchdog (void *arg)
 2481 {
 2482         drv_t *d = arg;
 2483 
 2484         if (d->timeout == 1)
 2485                 cx_watchdog (d);
 2486         if (d->timeout)
 2487                 d->timeout--;
 2488         callout_reset (&d->timeout_handle, hz, ng_cx_watchdog, d);
 2489 }
 2490 
 2491 static int ng_cx_connect (hook_p hook)
 2492 {
 2493         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2494 
 2495         callout_reset (&d->timeout_handle, hz, ng_cx_watchdog, d);
 2496         return 0;
 2497 }
 2498 
 2499 static int ng_cx_disconnect (hook_p hook)
 2500 {
 2501         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2502         bdrv_t *bd = d->board->sys;
 2503         int s;
 2504 
 2505         s = splhigh ();
 2506         CX_LOCK (bd);
 2507         if (NG_HOOK_PRIVATE (hook))
 2508                 cx_down (d);
 2509         CX_UNLOCK (bd);
 2510         splx (s);
 2511         /* If we were wait it than it reasserted now, just stop it. */
 2512         if (!callout_drain (&d->timeout_handle))
 2513                 callout_stop (&d->timeout_handle);
 2514         return 0;
 2515 }
 2516 #endif /*NETGRAPH*/
 2517 
 2518 static int cx_modevent (module_t mod, int type, void *unused)
 2519 {
 2520         static int load_count = 0;
 2521 
 2522         switch (type) {
 2523         case MOD_LOAD:
 2524 #ifdef NETGRAPH
 2525                 if (ng_newtype (&typestruct))
 2526                         printf ("Failed to register ng_cx\n");
 2527 #endif
 2528                 ++load_count;
 2529 
 2530                 callout_init (&timeout_handle, CALLOUT_MPSAFE);
 2531                 callout_reset (&timeout_handle, hz*5, cx_timeout, 0);
 2532                 /* Software interrupt. */
 2533                 swi_add(&tty_intr_event, "cx", cx_softintr, NULL, SWI_TTY,
 2534                     INTR_MPSAFE, &cx_fast_ih);
 2535                 break;
 2536         case MOD_UNLOAD:
 2537                 if (load_count == 1) {
 2538                         printf ("Removing device entry for Sigma\n");
 2539 #ifdef NETGRAPH
 2540                         ng_rmtype (&typestruct);
 2541 #endif                  
 2542                 }
 2543                 /* If we were wait it than it reasserted now, just stop it. */
 2544                 if (!callout_drain (&timeout_handle))
 2545                         callout_stop (&timeout_handle);
 2546                 swi_remove (cx_fast_ih);
 2547                 --load_count;
 2548                 break;
 2549         case MOD_SHUTDOWN:
 2550                 break;
 2551         }
 2552         return 0;
 2553 }
 2554 
 2555 #ifdef NETGRAPH
 2556 static struct ng_type typestruct = {
 2557         .version        = NG_ABI_VERSION,
 2558         .name           = NG_CX_NODE_TYPE,
 2559         .constructor    = ng_cx_constructor,
 2560         .rcvmsg         = ng_cx_rcvmsg,
 2561         .shutdown       = ng_cx_rmnode,
 2562         .newhook        = ng_cx_newhook,
 2563         .connect        = ng_cx_connect,
 2564         .rcvdata        = ng_cx_rcvdata,
 2565         .disconnect     = ng_cx_disconnect,
 2566 };
 2567 #endif /*NETGRAPH*/
 2568 
 2569 #ifdef NETGRAPH
 2570 MODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
 2571 #else
 2572 MODULE_DEPEND (isa_cx, sppp, 1, 1, 1);
 2573 #endif
 2574 DRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL);
 2575 MODULE_VERSION (cx, 1);

Cache object: c8a4f702bfa074c4ada1337cb125c6fc


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