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.23 2004/02/26 17:56:40 rik Exp $
   23  */
   24 #include <sys/cdefs.h>
   25 __FBSDID("$FreeBSD$");
   26 
   27 #include <sys/param.h>
   28 
   29 #if __FreeBSD_version >= 500000
   30 #   define NCX 1
   31 #else
   32 #   include "cx.h"
   33 #endif
   34 
   35 #if NCX > 0
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/proc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/sockio.h>
   41 #include <sys/malloc.h>
   42 #include <sys/socket.h>
   43 #include <sys/conf.h>
   44 #include <sys/errno.h>
   45 #include <sys/tty.h>
   46 #if __FreeBSD_version >= 400000
   47 #   include <sys/bus.h>
   48 #   include <machine/bus.h>
   49 #   include <sys/rman.h>
   50 #   include <isa/isavar.h>
   51 #endif
   52 #include <sys/fcntl.h>
   53 #include <sys/interrupt.h>
   54 #include <vm/vm.h>
   55 #include <vm/pmap.h>
   56 #include <net/if.h>
   57 #include <machine/cpufunc.h>
   58 #include <machine/cserial.h>
   59 #include <machine/clock.h>
   60 #if __FreeBSD_version < 500000
   61 #include <machine/ipl.h>
   62 #include <i386/isa/isa_device.h>
   63 #endif
   64 #if __FreeBSD_version >= 400000
   65 #   include <machine/resource.h>
   66 #   if __FreeBSD_version <= 501000
   67 #       include <i386/isa/intr_machdep.h>
   68 #   endif
   69 #endif
   70 #if __FreeBSD_version >= 400000
   71 #   include <dev/cx/machdep.h>
   72 #   include <dev/cx/cxddk.h>
   73 #   include <dev/cx/cronyxfw.h>
   74 #else
   75 #   include <i386/isa/cronyx/machdep.h>
   76 #   include <i386/isa/cronyx/cxddk.h>
   77 #   include <i386/isa/cronyx/cronyxfw.h>
   78 #endif
   79 #include "opt_ng_cronyx.h"
   80 #ifdef NETGRAPH_CRONYX
   81 #   include "opt_netgraph.h"
   82 #   include <netgraph/ng_message.h>
   83 #   include <netgraph/netgraph.h>
   84 #   if __FreeBSD_version >= 400000
   85 #       include <dev/cx/ng_cx.h>
   86 #   else
   87 #       include <netgraph/ng_cx.h>
   88 #   endif
   89 #else
   90 #   include <net/if_types.h>
   91 #   if __FreeBSD_version < 500000
   92 #   include "sppp.h"
   93 #   if NSPPP <= 0
   94 #       error The device cx requires sppp or netgraph.
   95 #   endif
   96 #   endif
   97 #   include <net/if_sppp.h>
   98 #   define PP_CISCO IFF_LINK2
   99 #if __FreeBSD_version < 400000
  100 #   include <bpfilter.h>
  101 #   if NBPFILTER > 0
  102 #      include <net/bpf.h>
  103 #   endif
  104 #else
  105 #   if __FreeBSD_version < 500000
  106 #       include <bpf.h>
  107 #   endif
  108 #   include <net/bpf.h>
  109 #   define NBPFILTER NBPF
  110 #endif
  111 #endif
  112 
  113 /* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
  114 #ifndef PP_FR
  115 #define PP_FR 0
  116 #endif
  117 
  118 #define CX_DEBUG(d,s)   ({if (d->chan->debug) {\
  119                                 printf ("%s: ", d->name); printf s;}})
  120 #define CX_DEBUG2(d,s)  ({if (d->chan->debug>1) {\
  121                                 printf ("%s: ", d->name); printf s;}})
  122 
  123 #define UNIT(d)         (minor(d) & 0x3f)
  124 #define IF_CUNIT(d)     (minor(d) & 0x40)
  125 #define UNIT_CTL        0x3f
  126 #define CALLOUT(d)      (minor(d) & 0x80)
  127 #define CDEV_MAJOR      42
  128 
  129 typedef struct _async_q {
  130         int beg;
  131         int end;
  132         #define BF_SZ 14400
  133         int buf[BF_SZ+1];
  134 } async_q;
  135 
  136 #define AQ_GSZ(q)       ((BF_SZ + (q)->end - (q)->beg)%BF_SZ)
  137 #define AQ_PUSH(q,c)    {*((q)->buf + (q)->end) = c;\
  138                         (q)->end = ((q)->end + 1)%BF_SZ;}
  139 #define AQ_POP(q,c)     {c = *((q)->buf + (q)->beg);\
  140                         (q)->beg = ((q)->beg + 1)%BF_SZ;}
  141 
  142 #if __FreeBSD_version >= 400000
  143 static void cx_identify         __P((driver_t *, device_t));
  144 static int cx_probe             __P((device_t));
  145 static int cx_attach            __P((device_t));
  146 static int cx_detach            __P((device_t));
  147 
  148 static device_method_t cx_isa_methods [] = {
  149         DEVMETHOD(device_identify,      cx_identify),
  150         DEVMETHOD(device_probe,         cx_probe),
  151         DEVMETHOD(device_attach,        cx_attach),
  152         DEVMETHOD(device_detach,        cx_detach),
  153         {0, 0}
  154 };
  155 
  156 typedef struct _bdrv_t {
  157         cx_board_t      *board;
  158         struct resource *base_res;
  159         struct resource *drq_res;
  160         struct resource *irq_res;
  161         int             base_rid;
  162         int             drq_rid;
  163         int             irq_rid;
  164         void            *intrhand;
  165 } bdrv_t;
  166 
  167 static driver_t cx_isa_driver = {
  168         "cx",
  169         cx_isa_methods,
  170         sizeof (bdrv_t),
  171 };
  172 
  173 static devclass_t cx_devclass;
  174 #endif
  175 
  176 typedef struct _drv_t {
  177         char name [8];
  178         cx_chan_t *chan;
  179         cx_board_t *board;
  180         cx_buf_t buf;
  181         struct tty tty;
  182         struct callout_handle dcd_timeout_handle;
  183         unsigned dtrwait;
  184         unsigned dtroff;
  185         unsigned callout;
  186         unsigned lock;
  187         int open_dev;
  188         int cd;
  189         int running;
  190         struct  callout_handle dtr_timeout_handle;
  191 #ifdef NETGRAPH
  192         char    nodename [NG_NODELEN+1];
  193         hook_p  hook;
  194         hook_p  debug_hook;
  195         node_p  node;
  196         struct  ifqueue lo_queue;
  197         struct  ifqueue hi_queue;
  198         short   timeout;
  199         struct  callout_handle timeout_handle;
  200 #else
  201         struct sppp pp;
  202 #endif
  203 #if __FreeBSD_version >= 400000
  204         dev_t  devt[3];
  205 #endif
  206         async_q aqueue;
  207         #define CX_READ 1
  208         #define CX_WRITE 2
  209         int intr_action;
  210         short atimeout;
  211 } drv_t;
  212 
  213 extern long csigma_fw_len;
  214 extern const char *csigma_fw_version;
  215 extern const char *csigma_fw_date;
  216 extern const char *csigma_fw_copyright;
  217 extern const cr_dat_tst_t csigma_fw_tvec[];
  218 extern const u_char csigma_fw_data[];
  219 static void cx_oproc (struct tty *tp);
  220 static int cx_param (struct tty *tp, struct termios *t);
  221 static void cx_stop (struct tty *tp, int flag);
  222 static void cx_dtrwakeup (void *a);
  223 static void cx_receive (cx_chan_t *c, char *data, int len);
  224 static void cx_transmit (cx_chan_t *c, void *attachment, int len);
  225 static void cx_error (cx_chan_t *c, int data);
  226 static void cx_modem (cx_chan_t *c);
  227 static void cx_up (drv_t *d);
  228 static void cx_start (drv_t *d);
  229 static void disc_optim(struct tty *tp, struct termios *t);
  230 #if __FreeBSD_version < 500000
  231 static swihand_t cx_softintr;
  232 #else
  233 static void cx_softintr (void *);
  234 static void *cx_fast_ih;
  235 #endif
  236 static void cx_down (drv_t *d);
  237 static void cx_watchdog (drv_t *d);
  238 static void cx_carrier (void *arg);
  239 
  240 #ifdef NETGRAPH
  241 extern struct ng_type typestruct;
  242 #else
  243 static void cx_ifstart (struct ifnet *ifp);
  244 static void cx_tlf (struct sppp *sp);
  245 static void cx_tls (struct sppp *sp);
  246 static void cx_ifwatchdog (struct ifnet *ifp);
  247 static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
  248 static void cx_initialize (void *softc);
  249 #endif
  250 
  251 static cx_board_t *adapter [NCX];
  252 static drv_t *channel [NCX*NCHAN];
  253 static struct callout_handle led_timo [NCX];
  254 static struct callout_handle timeout_handle;
  255 #if __FreeBSD_version >= 400000
  256         extern struct cdevsw cx_cdevsw;
  257 #endif
  258 
  259 static int MY_SOFT_INTR;
  260 
  261 /*
  262  * Print the mbuf chain, for debug purposes only.
  263  */
  264 static void printmbuf (struct mbuf *m)
  265 {
  266         printf ("mbuf:");
  267         for (; m; m=m->m_next) {
  268                 if (m->m_flags & M_PKTHDR)
  269                         printf (" HDR %d:", m->m_pkthdr.len);
  270                 if (m->m_flags & M_EXT)
  271                         printf (" EXT:");
  272                 printf (" %d", m->m_len);
  273         }
  274         printf ("\n");
  275 }
  276 
  277 /*
  278  * Make an mbuf from data.
  279  */
  280 static struct mbuf *makembuf (void *buf, u_int len)
  281 {
  282         struct mbuf *m, *o, *p;
  283 
  284         MGETHDR (m, M_DONTWAIT, MT_DATA);
  285 
  286         if (! m)
  287                 return 0;
  288 
  289         if (len >= MINCLSIZE)
  290                 MCLGET (m, M_DONTWAIT);
  291 
  292         m->m_pkthdr.len = len;
  293         m->m_len = 0;
  294 
  295         p = m;
  296         while (len) {
  297                 u_int n = M_TRAILINGSPACE (p);
  298                 if (n > len)
  299                         n = len;
  300                 if (! n) {
  301                         /* Allocate new mbuf. */
  302                         o = p;
  303                         MGET (p, M_DONTWAIT, MT_DATA);
  304                         if (! p) {
  305                                 m_freem (m);
  306                                 return 0;
  307                         }
  308                         if (len >= MINCLSIZE)
  309                                 MCLGET (p, M_DONTWAIT);
  310                         p->m_len = 0;
  311                         o->m_next = p;
  312 
  313                         n = M_TRAILINGSPACE (p);
  314                         if (n > len)
  315                                 n = len;
  316                 }
  317                 bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
  318 
  319                 p->m_len += n;
  320                 buf = n + (char*) buf;
  321                 len -= n;
  322         }
  323         return m;
  324 }
  325 
  326 /*
  327  * Recover after lost transmit interrupts.
  328  */
  329 static void cx_timeout (void *arg)
  330 {
  331         drv_t *d;
  332         int s, i;
  333 
  334         for (i=0; i<NCX*NCHAN; ++i) {
  335                 d = channel[i];
  336                 if (! d)
  337                         continue;
  338                 s = splhigh ();
  339                 if (d->atimeout == 1 && d->tty.t_state & TS_BUSY) {
  340                         d->tty.t_state &= ~TS_BUSY;
  341                         if (d->tty.t_dev) {
  342                                 d->intr_action |= CX_WRITE;
  343                                 MY_SOFT_INTR = 1;
  344 #if __FreeBSD_version >= 500000
  345                                 swi_sched (cx_fast_ih, 0);
  346 #else
  347                                 setsofttty ();
  348 #endif
  349                         }
  350                         CX_DEBUG (d, ("cx_timeout\n"));
  351                 }
  352                 if (d->atimeout)
  353                         d->atimeout--;
  354                 splx (s);
  355         }
  356         timeout_handle = timeout (cx_timeout, 0, hz*5);
  357 }
  358 
  359 static void cx_led_off (void *arg)
  360 {
  361         cx_board_t *b = arg;
  362         int s = splhigh ();
  363 
  364         cx_led (b, 0);
  365         led_timo[b->num].callout = 0;
  366         splx (s);
  367 }
  368 
  369 /*
  370  * Activate interupt handler from DDK.
  371  */
  372 #if __FreeBSD_version >= 400000
  373 static void cx_intr (void *arg)
  374 {
  375         bdrv_t *bd = arg;
  376         cx_board_t *b = bd->board;
  377 #else
  378 static void cx_intr (int bnum)
  379 {
  380         cx_board_t *b = adapter [bnum];
  381 #endif
  382         int s = splhigh ();
  383 
  384         /* Turn LED on. */
  385         cx_led (b, 1);
  386 
  387         cx_int_handler (b);
  388 
  389         /* Turn LED off 50 msec later. */
  390         if (! led_timo[b->num].callout)
  391                 led_timo[b->num] = timeout (cx_led_off, b, hz/20);
  392         splx (s);
  393 }
  394 
  395 static int probe_irq (cx_board_t *b, int irq)
  396 {
  397         int mask, busy, cnt;
  398 
  399         /* Clear pending irq, if any. */
  400         cx_probe_irq (b, -irq);
  401         DELAY (100);
  402         for (cnt=0; cnt<5; ++cnt) {
  403                 /* Get the mask of pending irqs, assuming they are busy.
  404                  * Activate the adapter on given irq. */
  405                 busy = cx_probe_irq (b, irq);
  406                 DELAY (100);
  407 
  408                 /* Get the mask of active irqs.
  409                  * Deactivate our irq. */
  410                 mask = cx_probe_irq (b, -irq);
  411                 DELAY (100);
  412                 if ((mask & ~busy) == 1 << irq) {
  413                         cx_probe_irq (b, 0);
  414                         /* printf ("cx%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
  415                                 b->num, irq, mask, busy); */
  416                         return 1;
  417                 }
  418         }
  419         /* printf ("cx%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
  420                 b->num, irq, mask, busy); */
  421         cx_probe_irq (b, 0);
  422         return 0;
  423 }
  424 
  425 static short porttab [] = {
  426         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
  427         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
  428 };
  429 static char dmatab [] = { 7, 6, 5, 0 };
  430 static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
  431 
  432 #if __FreeBSD_version >= 400000
  433 static int cx_is_free_res (device_t dev, int rid, int type, u_long start,
  434         u_long end, u_long count)
  435 {
  436         struct resource *res;
  437         
  438         if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
  439             RF_ALLOCATED)))
  440                 return 0;
  441                 
  442         bus_release_resource (dev, type, rid, res);
  443         
  444         return 1;
  445 }
  446 
  447 static void cx_identify (driver_t *driver, device_t dev)
  448 {
  449         u_long iobase, rescount;
  450         int devcount;
  451         device_t *devices;
  452         device_t child;
  453         devclass_t my_devclass;
  454         int i, k;
  455 
  456         if ((my_devclass = devclass_find ("cx")) == NULL)
  457                 return;
  458 
  459         devclass_get_devices (my_devclass, &devices, &devcount);
  460 
  461         if (devcount == 0) {
  462                 /* We should find all devices by our self. We could alter other
  463                  * devices, but we don't have a choise
  464                  */
  465                 for (i = 0; (iobase = porttab [i]) != 0; i++) {
  466                         if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT,
  467                             iobase, iobase + NPORT, NPORT))
  468                                 continue;
  469                         if (cx_probe_board (iobase, -1, -1) == 0)
  470                                 continue;
  471                         
  472                         devcount++;
  473 
  474                         child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "cx",
  475                             -1);
  476 
  477                         if (child == NULL)
  478                                 return;
  479 
  480                         device_set_desc_copy (child, "Cronyx Sigma");
  481                         device_set_driver (child, driver);
  482                         bus_set_resource (child, SYS_RES_IOPORT, 0,
  483                             iobase, NPORT);
  484 
  485                         if (devcount >= NCX)
  486                                 break;
  487                 }
  488         } else {
  489                 static short porttab [] = {
  490                         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
  491                         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
  492                 };
  493                 /* Lets check user choise.
  494                  */
  495                 for (k = 0; k < devcount; k++) {
  496                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
  497                             &iobase, &rescount) != 0)
  498                                 continue;
  499 
  500                         for (i = 0; porttab [i] != 0; i++) {
  501                                 if (porttab [i] != iobase)
  502                                         continue;
  503                                 if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT,
  504                                     iobase, iobase + NPORT, NPORT))
  505                                         continue;
  506                                 if (cx_probe_board (iobase, -1, -1) == 0)
  507                                         continue;
  508                                 porttab [i] = -1;
  509                                 device_set_desc_copy (devices[k], "Cronyx Sigma");
  510                                 break;
  511                         }
  512 
  513                         if (porttab [i] == 0) {
  514                                 device_delete_child (
  515                                     device_get_parent (devices[k]),
  516                                     devices [k]);
  517                                 devices[k] = 0;
  518                                 continue;
  519                         }
  520                 }
  521                 for (k = 0; k < devcount; k++) {
  522                         if (devices[k] == 0)
  523                                 continue;
  524                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
  525                             &iobase, &rescount) == 0)
  526                                 continue;
  527                         for (i = 0; (iobase = porttab [i]) != 0; i++) {
  528                                 if (porttab [i] == -1) {
  529                                         continue;
  530                                 }
  531                                 if (!cx_is_free_res (devices[k], 0, SYS_RES_IOPORT,
  532                                     iobase, iobase + NPORT, NPORT))
  533                                         continue;
  534                                 if (cx_probe_board (iobase, -1, -1) == 0)
  535                                         continue;
  536                         
  537                                 bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
  538                                     iobase, NPORT);
  539                                 porttab [i] = -1;
  540                                 device_set_desc_copy (devices[k], "Cronyx Sigma");
  541                                 break;
  542                         }
  543                         if (porttab [i] == 0) {
  544                                 device_delete_child (
  545                                     device_get_parent (devices[k]),
  546                                     devices [k]);
  547                         }
  548                 }               
  549                 free (devices, M_TEMP);
  550         }
  551         
  552         return;
  553 }
  554 
  555 static int cx_probe (device_t dev)
  556 {
  557         int unit = device_get_unit (dev);
  558         int i;
  559         u_long iobase, rescount;
  560 
  561         if (!device_get_desc (dev) ||
  562             strcmp (device_get_desc (dev), "Cronyx Sigma"))
  563                 return ENXIO;
  564         
  565         if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
  566                 printf ("cx%d: Couldn't get IOPORT\n", unit);
  567                 return ENXIO;
  568         }
  569 
  570         if (!cx_is_free_res (dev, 0, SYS_RES_IOPORT,
  571             iobase, iobase + NPORT, NPORT)) {
  572                 printf ("cx%d: Resource IOPORT isn't free %lx\n", unit, iobase);
  573                 return ENXIO;
  574         }
  575                 
  576         for (i = 0; porttab [i] != 0; i++) {
  577                 if (porttab [i] == iobase) {
  578                         porttab [i] = -1;
  579                         break;
  580                 }
  581         }
  582         
  583         if (porttab [i] == 0) {
  584                 return ENXIO;
  585         }
  586         
  587         if (!cx_probe_board (iobase, -1, -1)) {
  588                 printf ("cx%d: probing for Sigma at %lx faild\n", unit, iobase);
  589                 return ENXIO;
  590         }
  591         
  592         return 0;
  593 }
  594 #else /* __FreeBSD_version < 400000 */
  595 static int cx_probe (struct isa_device *id)
  596 {
  597         cx_board_t *b;
  598         int i;
  599 
  600 #ifndef NETGRAPH
  601         if (! sppp_attach) {
  602                 printf ("cx%d: no synchronous PPP driver configured\n",
  603                         id->id_unit);
  604                 return 0;
  605         }
  606 #endif
  607         if (id->id_iobase < 0) {
  608                 /* Autodetect the adapter. */
  609                 for (i=0; ; i++) {
  610                         if (! porttab[i]) {
  611                                 id->id_iobase = -1;
  612                                 return 0;
  613                         }
  614                         id->id_iobase = porttab[i];
  615                         if (id->id_unit > 0 && adapter[0] && adapter[0]->port == id->id_iobase)
  616                                 continue;
  617                         if (id->id_unit > 1 && adapter[1] && adapter[1]->port == id->id_iobase)
  618                                 continue;
  619                         if (! haveseen_isadev (id, CC_IOADDR | CC_QUIET) &&
  620                             cx_probe_board (id->id_iobase, -1, -1))
  621                                 break;
  622                 }
  623         } else if (! cx_probe_board (id->id_iobase, -1, -1))
  624                 return 0;
  625 
  626         if (id->id_drq < 0) {
  627                 /* Find available 16-bit DRQ. */
  628 
  629                 for (i=0; ; ++i) {
  630                         if (! dmatab[i]) {
  631                                 printf ("cx%d: no available drq found\n",
  632                                         id->id_unit);
  633                                 id->id_drq = -1;
  634                                 return 0;
  635                         }
  636                         id->id_drq = dmatab[i];
  637                         if (! haveseen_isadev (id, CC_DRQ | CC_QUIET)
  638                             && !isa_dma_acquire (id->id_drq))
  639                                 break;
  640                 }
  641         }
  642 
  643         b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK);
  644         if (!b) {
  645                 printf ("cx:%d: Couldn't allocate memory\n", id->id_unit);
  646                 return (ENXIO);
  647         }
  648         adapter[id->id_unit] = b;
  649         bzero (b, sizeof(cx_board_t));
  650 
  651         if (! cx_open_board (b, id->id_unit, id->id_iobase,
  652             id->id_irq ? ffs (id->id_irq) - 1 : -1, id->id_drq)) {
  653                 printf ("cx%d: cannot initialize adapter\n", id->id_unit);
  654                 isa_dma_release (id->id_drq);
  655                 adapter[id->id_unit] = 0;
  656                 free (b, M_DEVBUF);
  657                 return 0;
  658         }
  659 
  660         if (id->id_irq) {
  661                 if (! probe_irq (b, ffs (id->id_irq) - 1))
  662                         printf ("cx%d: irq %d not functional\n",
  663                                 id->id_unit, ffs (id->id_irq) - 1);
  664         } else {
  665                 /* Find available IRQ. */
  666 
  667                 for (i=0; ; ++i) {
  668                         if (! irqtab[i]) {
  669                                 printf ("cx%d: no available irq found\n",
  670                                         id->id_unit);
  671                                 id->id_irq = -1;
  672                                 isa_dma_release (id->id_drq);
  673                                 adapter[id->id_unit] = 0;
  674                                 free (b, M_DEVBUF);
  675                                 return 0;
  676                         }
  677                         id->id_irq = 1 << irqtab[i];
  678                         if (haveseen_isadev (id, CC_IRQ | CC_QUIET))
  679                                 continue;
  680 #ifdef KLD_MODULE
  681                         if (register_intr (irqtab[i], 0, 0, (inthand2_t*)
  682                             cx_intr, &net_imask, id->id_unit) != 0)
  683                                 continue;
  684                         unregister_intr (irqtab[i], (inthand2_t*) cx_intr);
  685 #endif
  686                         if (probe_irq (b, irqtab[i]))
  687                                 break;
  688                 }
  689         }
  690         cx_init (b, b->num, b->port, ffs (id->id_irq) - 1, b->dma);
  691         cx_setup_board (b, 0, 0, 0);
  692 
  693         return 1;
  694 }
  695 #endif /* __FreeBSD_version < 400000 */
  696 
  697 /*
  698  * The adapter is present, initialize the driver structures.
  699  */
  700 #if __FreeBSD_version < 400000
  701 static int cx_attach (struct isa_device *id)
  702 {
  703 #else
  704 static int cx_attach (device_t dev)
  705 {
  706         bdrv_t *bd = device_get_softc (dev);
  707         u_long iobase, drq, irq, rescount;
  708         int unit = device_get_unit (dev);
  709         int i;
  710         int s;
  711 #endif
  712         cx_board_t *b;
  713         cx_chan_t *c;
  714         drv_t *d;
  715 
  716 #if __FreeBSD_version >= 400000
  717         KASSERT ((bd != NULL), ("cx%d: NULL device softc\n", unit));
  718         
  719         bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
  720         bd->base_rid = 0;
  721         bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
  722                 iobase, iobase + NPORT, NPORT, RF_ACTIVE);
  723         if (! bd->base_res) {
  724                 printf ("cx%d: cannot allocate base address\n", unit);
  725                 return ENXIO;
  726         }
  727         
  728         if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
  729                 for (i = 0; (drq = dmatab [i]) != 0; i++) {
  730                         if (!cx_is_free_res (dev, 0, SYS_RES_DRQ,
  731                             drq, drq + 1, 1))
  732                                 continue;
  733                         bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
  734                         break;
  735                 }
  736                 
  737                 if (dmatab[i] == 0) {   
  738                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  739                                 bd->base_res);
  740                         printf ("cx%d: Couldn't get DRQ\n", unit);
  741                         return ENXIO;
  742                 }
  743         }
  744         
  745         bd->drq_rid = 0;
  746         bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
  747                 drq, drq + 1, 1, RF_ACTIVE);
  748         if (! bd->drq_res) {
  749                 printf ("cx%d: cannot allocate drq\n", unit);
  750                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  751                         bd->base_res);
  752                 return ENXIO;
  753         }       
  754         
  755         if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
  756                 for (i = 0; (irq = irqtab [i]) != 0; i++) {
  757                         if (!cx_is_free_res (dev, 0, SYS_RES_IRQ,
  758                             irq, irq + 1, 1))
  759                                 continue;
  760                         bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
  761                         break;
  762                 }
  763                 
  764                 if (irqtab[i] == 0) {   
  765                         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  766                                 bd->drq_res);
  767                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  768                                 bd->base_res);
  769                         printf ("cx%d: Couldn't get IRQ\n", unit);
  770                         return ENXIO;
  771                 }
  772         }
  773         
  774         bd->irq_rid = 0;
  775         bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
  776                 irq, irq + 1, 1, RF_ACTIVE);
  777         if (! bd->irq_res) {
  778                 printf ("cx%d: Couldn't allocate irq\n", unit);
  779                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  780                         bd->drq_res);
  781                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  782                         bd->base_res);
  783                 return ENXIO;
  784         }
  785         
  786         b = malloc (sizeof (cx_board_t), M_DEVBUF, M_WAITOK);
  787         if (!b) {
  788                 printf ("cx:%d: Couldn't allocate memory\n", unit);
  789                 return (ENXIO);
  790         }
  791         adapter[unit] = b;
  792         bzero (b, sizeof(cx_board_t));
  793         
  794         if (! cx_open_board (b, unit, iobase, irq, drq)) {
  795                 printf ("cx%d: error loading firmware\n", unit);
  796                 free (b, M_DEVBUF);
  797                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  798                         bd->irq_res);
  799                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  800                         bd->drq_res);
  801                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  802                         bd->base_res);
  803                 return ENXIO;
  804         }
  805 
  806         bd->board = b;
  807         
  808         if (! probe_irq (b, irq)) {
  809                 printf ("cx%d: irq %ld not functional\n", unit, irq);
  810                 bd->board = 0;
  811                 adapter [unit] = 0;
  812                 free (b, M_DEVBUF);
  813                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  814                         bd->irq_res);
  815                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  816                         bd->drq_res);
  817                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  818                         bd->base_res);
  819                 return ENXIO;
  820         }
  821         
  822         s = splhigh ();
  823         if (bus_setup_intr (dev, bd->irq_res, INTR_TYPE_NET, cx_intr, bd,
  824             &bd->intrhand)) {
  825                 printf ("cx%d: Can't setup irq %ld\n", unit, irq);
  826                 bd->board = 0;
  827                 adapter [unit] = 0;
  828                 free (b, M_DEVBUF);
  829                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
  830                         bd->irq_res);
  831                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
  832                         bd->drq_res);
  833                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
  834                         bd->base_res);
  835                 splx (s);
  836                 return ENXIO;           
  837         }
  838         
  839         cx_init (b, b->num, b->port, irq, drq);
  840         cx_setup_board (b, 0, 0, 0);
  841 #else /* __FreeBSD_version >= 400000 */
  842         b = adapter[id->id_unit];
  843 #endif /* __FreeBSD_version >= 400000 */
  844 
  845         printf ("cx%d: <Cronyx-Sigma-%s>\n", b->num, b->name);
  846 #if __FreeBSD_version < 400000
  847         id->id_ointr = cx_intr;
  848 #endif
  849 
  850         for (c=b->chan; c<b->chan+NCHAN; ++c) {
  851 #if __FreeBSD_version >= 400000
  852                 char *dnmt="tty %x";
  853                 char *dnmc="cua %x";
  854 #endif
  855                 if (c->type == T_NONE)
  856                         continue;
  857                 d = contigmalloc (sizeof(drv_t), M_DEVBUF, M_WAITOK,
  858                         0x100000, 0x1000000, 16, 0);
  859                 channel [b->num*NCHAN + c->num] = d;
  860                 bzero (d, sizeof(drv_t));
  861                 sprintf (d->name, "cx%d.%d", b->num, c->num);
  862                 d->board = b;
  863                 d->chan = c;
  864                 d->tty.t_oproc = cx_oproc;
  865                 d->tty.t_param = cx_param;
  866 #if __FreeBSD_version >= 400000
  867                 d->tty.t_stop  = cx_stop;
  868 #endif
  869                 d->dtrwait = 3 * hz;    /* Default DTR off timeout is 3 seconds. */
  870                 d->open_dev = 0;
  871                 c->sys = d;
  872 
  873                 switch (c->type) {
  874                 case T_SYNC_RS232:
  875                 case T_SYNC_V35:
  876                 case T_SYNC_RS449:
  877                 case T_UNIV:
  878                 case T_UNIV_RS232:
  879                 case T_UNIV_RS449:
  880                 case T_UNIV_V35:
  881 #ifdef NETGRAPH
  882                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
  883                         printf ("%s: cannot make common node\n", d->name);
  884                         channel [b->num*NCHAN + c->num] = 0;
  885                         c->sys = 0;
  886 #if __FreeBSD_version < 400000
  887                         free (d, M_DEVBUF);
  888 #else
  889                         contigfree (d, sizeof (*d), M_DEVBUF);
  890 #endif
  891                         continue;
  892                 }
  893 #if __FreeBSD_version >= 500000
  894                 NG_NODE_SET_PRIVATE (d->node, d);
  895 #else
  896                 d->node->private = d;
  897 #endif
  898                 sprintf (d->nodename, "%s%d", NG_CX_NODE_TYPE,
  899                          c->board->num*NCHAN + c->num);
  900                 if (ng_name_node (d->node, d->nodename)) {
  901                         printf ("%s: cannot name node\n", d->nodename);
  902 #if __FreeBSD_version >= 500000
  903                         NG_NODE_UNREF (d->node);
  904 #else
  905                         ng_rmnode (d->node);
  906                         ng_unref (d->node);
  907 #endif
  908                         channel [b->num*NCHAN + c->num] = 0;
  909                         c->sys = 0;
  910 #if __FreeBSD_version < 400000
  911                         free (d, M_DEVBUF);
  912 #else
  913                         contigfree (d, sizeof (*d), M_DEVBUF);
  914 #endif
  915                         continue;
  916                 }
  917                 d->lo_queue.ifq_maxlen = IFQ_MAXLEN;
  918                 d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
  919 #if __FreeBSD_version >= 500000
  920                 mtx_init (&d->lo_queue.ifq_mtx, "cx_queue_lo", NULL, MTX_DEF);
  921                 mtx_init (&d->hi_queue.ifq_mtx, "cx_queue_hi", NULL, MTX_DEF);
  922 #endif          
  923 #else /*NETGRAPH*/
  924                 d->pp.pp_if.if_softc    = d;
  925 #if __FreeBSD_version > 501000
  926                 if_initname (&d->pp.pp_if, "cx", b->num * NCHAN + c->num);
  927 #else
  928                 d->pp.pp_if.if_unit     = b->num * NCHAN + c->num;
  929                 d->pp.pp_if.if_name     = "cx";
  930 #endif
  931                 d->pp.pp_if.if_mtu      = PP_MTU;
  932                 d->pp.pp_if.if_flags    = IFF_POINTOPOINT | IFF_MULTICAST;
  933                 d->pp.pp_if.if_ioctl    = cx_sioctl;
  934                 d->pp.pp_if.if_start    = cx_ifstart;
  935                 d->pp.pp_if.if_watchdog = cx_ifwatchdog;
  936                 d->pp.pp_if.if_init     = cx_initialize;
  937                 sppp_attach (&d->pp.pp_if);
  938                 if_attach (&d->pp.pp_if);
  939                 d->pp.pp_tlf            = cx_tlf;
  940                 d->pp.pp_tls            = cx_tls;
  941 #if __FreeBSD_version >= 400000 || NBPFILTER > 0
  942                 /* If BPF is in the kernel, call the attach for it.
  943                  * Size of PPP header is 4 bytes. */
  944                 bpfattach (&d->pp.pp_if, DLT_PPP, 4);
  945 #endif
  946 #endif /*NETGRAPH*/
  947                 }
  948                 cx_start_chan (c, &d->buf, vtophys (&d->buf));
  949                 cx_register_receive (c, &cx_receive);
  950                 cx_register_transmit (c, &cx_transmit);
  951                 cx_register_error (c, &cx_error);
  952                 cx_register_modem (c, &cx_modem);
  953 #if __FreeBSD_version >= 400000
  954                 dnmt[3] = 'x'+b->num;
  955                 dnmc[3] = 'x'+b->num;
  956                 d->devt[0] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num, UID_ROOT, GID_WHEEL, 0644, dnmt, b->num*NCHAN + c->num);
  957                 d->devt[1] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 64, UID_ROOT, GID_WHEEL, 0600, "cx%d", b->num*NCHAN + c->num);
  958                 d->devt[2] = make_dev (&cx_cdevsw, b->num*NCHAN + c->num + 128, UID_ROOT, GID_WHEEL, 0660, dnmc, b->num*NCHAN + c->num);
  959         }
  960         splx (s);
  961 
  962         return 0;
  963 #else /* __FreeBSD_version < 400000 */
  964         }
  965 
  966         return 1;
  967 #endif
  968 }
  969 
  970 #if __FreeBSD_version >= 400000
  971 static int cx_detach (device_t dev)
  972 {
  973         bdrv_t *bd = device_get_softc (dev);
  974         cx_board_t *b = bd->board;
  975         cx_chan_t *c;
  976         int s = splhigh ();
  977         
  978         /* Check if the device is busy (open). */
  979         for (c = b->chan; c < b->chan + NCHAN; ++c) {
  980                 drv_t *d = (drv_t*) c->sys;
  981 
  982                 if (!d || d->chan->type == T_NONE)
  983                         continue;
  984                 if (d->lock) {
  985                         splx (s);
  986                         return EBUSY;
  987                 }
  988                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN) &&
  989                     (d->open_dev|0x2)) {
  990                         splx (s);
  991                         return EBUSY;
  992                 }
  993                 if (d->running) {
  994                         splx (s);
  995                         return EBUSY;
  996                 }
  997         }
  998 
  999         /* Deactivate the timeout routine. And soft interrupt*/
 1000         if (led_timo[b->num].callout)
 1001                 untimeout (cx_led_off, b, led_timo[b->num]);
 1002 
 1003         for (c = b->chan; c < b->chan + NCHAN; ++c) {
 1004                 drv_t *d = c->sys;
 1005 
 1006                 if (!d || d->chan->type == T_NONE)
 1007                         continue;
 1008 
 1009                 if (d->dtr_timeout_handle.callout)
 1010                         untimeout (cx_dtrwakeup, d, d->dtr_timeout_handle);
 1011                 if (d->dcd_timeout_handle.callout)
 1012                         untimeout (cx_carrier, c, d->dcd_timeout_handle);
 1013         }
 1014         bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
 1015         bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
 1016         bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
 1017         
 1018         bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
 1019         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
 1020         
 1021         bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res);
 1022         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
 1023 
 1024         cx_close_board (b);
 1025 
 1026         /* Detach the interfaces, free buffer memory. */
 1027         for (c = b->chan; c < b->chan + NCHAN; ++c) {
 1028                 drv_t *d = (drv_t*) c->sys;
 1029 
 1030                 if (!d || d->chan->type == T_NONE)
 1031                         continue;
 1032 #ifdef NETGRAPH
 1033 #if __FreeBSD_version >= 500000
 1034                 if (d->node) {
 1035                         ng_rmnode_self (d->node);
 1036                         NG_NODE_UNREF (d->node);
 1037                         d->node = NULL;
 1038                 }
 1039                 mtx_destroy (&d->lo_queue.ifq_mtx);
 1040                 mtx_destroy (&d->hi_queue.ifq_mtx);
 1041 #else
 1042                 ng_rmnode (d->node);
 1043                 d->node = NULL;
 1044 #endif          
 1045 #else
 1046 #if __FreeBSD_version >= 410000 && NBPFILTER > 0
 1047                 /* Detach from the packet filter list of interfaces. */
 1048                 bpfdetach (&d->pp.pp_if);
 1049 #endif
 1050                 /* Detach from the sync PPP list. */
 1051                 sppp_detach (&d->pp.pp_if);
 1052 
 1053                 if_detach (&d->pp.pp_if);
 1054 #endif          
 1055                 destroy_dev (d->devt[0]);
 1056                 destroy_dev (d->devt[1]);
 1057                 destroy_dev (d->devt[2]);
 1058         }
 1059 
 1060         cx_led_off (b);
 1061         if (led_timo[b->num].callout)
 1062                 untimeout (cx_led_off, b, led_timo[b->num]);
 1063         splx (s);
 1064         
 1065         s = splhigh ();
 1066         for (c = b->chan; c < b->chan + NCHAN; ++c) {
 1067                 drv_t *d = (drv_t*) c->sys;
 1068 
 1069                 if (!d || d->chan->type == T_NONE)
 1070                         continue;
 1071                 
 1072                 /* Deallocate buffers. */
 1073                 contigfree (d, sizeof (*d), M_DEVBUF);
 1074         }
 1075         bd->board = 0;
 1076         adapter [b->num] = 0;
 1077         free (b, M_DEVBUF);
 1078         splx (s);
 1079         
 1080         return 0;       
 1081 }
 1082 #endif
 1083 
 1084 #ifndef NETGRAPH
 1085 static void cx_ifstart (struct ifnet *ifp)
 1086 {
 1087         drv_t *d = ifp->if_softc;
 1088 
 1089         cx_start (d);
 1090 }
 1091 
 1092 static void cx_ifwatchdog (struct ifnet *ifp)
 1093 {
 1094         drv_t *d = ifp->if_softc;
 1095 
 1096         cx_watchdog (d);
 1097 }
 1098 
 1099 static void cx_tlf (struct sppp *sp)
 1100 {
 1101         drv_t *d = sp->pp_if.if_softc;
 1102 
 1103         CX_DEBUG (d, ("cx_tlf\n"));
 1104 /*      cx_set_dtr (d->chan, 0);*/
 1105 /*      cx_set_rts (d->chan, 0);*/
 1106         if (!(d->pp.pp_flags & PP_FR) && !(d->pp.pp_if.if_flags & PP_CISCO))
 1107                 sp->pp_down (sp);
 1108 }
 1109 
 1110 static void cx_tls (struct sppp *sp)
 1111 {
 1112         drv_t *d = sp->pp_if.if_softc;
 1113 
 1114         CX_DEBUG (d, ("cx_tls\n"));
 1115         if (!(d->pp.pp_flags & PP_FR) && !(d->pp.pp_if.if_flags & PP_CISCO))
 1116                 sp->pp_up (sp);
 1117 }
 1118 
 1119 /*
 1120  * Initialization of interface.
 1121  * It seems to be never called by upper level.
 1122  */
 1123 static void cx_initialize (void *softc)
 1124 {
 1125         drv_t *d = softc;
 1126 
 1127         CX_DEBUG (d, ("cx_initialize\n"));
 1128 }
 1129 
 1130 /*
 1131  * Process an ioctl request.
 1132  */
 1133 static int cx_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
 1134 {
 1135         drv_t *d = ifp->if_softc;
 1136         int error, s, was_up, should_be_up;
 1137 
 1138         /* No socket ioctls while the channel is in async mode. */
 1139         if (d->chan->type == T_NONE || d->chan->mode == M_ASYNC)
 1140                 return EBUSY;
 1141 
 1142         /* Socket ioctls on slave subchannels are not allowed. */
 1143         was_up = (ifp->if_flags & IFF_RUNNING) != 0;
 1144         error = sppp_ioctl (ifp, cmd, data);
 1145         if (error)
 1146                 return error;
 1147 
 1148         if (! (ifp->if_flags & IFF_DEBUG))
 1149                 d->chan->debug = 0;
 1150         else if (! d->chan->debug)
 1151                 d->chan->debug = 1;
 1152 
 1153         switch (cmd) {
 1154         default:           CX_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
 1155         case SIOCADDMULTI: CX_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
 1156         case SIOCDELMULTI: CX_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
 1157         case SIOCSIFFLAGS: CX_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
 1158         case SIOCSIFADDR:  CX_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
 1159         }
 1160 
 1161         /* We get here only in case of SIFFLAGS or SIFADDR. */
 1162         s = splhigh ();
 1163         should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
 1164         if (!was_up && should_be_up) {
 1165                 /* Interface goes up -- start it. */
 1166                 cx_up (d);
 1167                 cx_start (d);
 1168         } else if (was_up && !should_be_up) {
 1169                 /* Interface is going down -- stop it. */
 1170                 /* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
 1171                 cx_down (d);
 1172         }
 1173         splx (s);
 1174         return 0;
 1175 }
 1176 #endif /*NETGRAPH*/
 1177 
 1178 /*
 1179  * Stop the interface.  Called on splimp().
 1180  */
 1181 static void cx_down (drv_t *d)
 1182 {
 1183         int s = splhigh ();
 1184         CX_DEBUG (d, ("cx_down\n"));
 1185         cx_set_dtr (d->chan, 0);
 1186         cx_set_rts (d->chan, 0);
 1187         d->running = 0;
 1188         splx (s);
 1189 }
 1190 
 1191 /*
 1192  * Start the interface.  Called on splimp().
 1193  */
 1194 static void cx_up (drv_t *d)
 1195 {
 1196         int s = splhigh ();
 1197         CX_DEBUG (d, ("cx_up\n"));
 1198         cx_set_dtr (d->chan, 1);
 1199         cx_set_rts (d->chan, 1);
 1200         d->running = 1;
 1201         splx (s);
 1202 }
 1203 
 1204 /*
 1205  * Start output on the (slave) interface.  Get another datagram to send
 1206  * off of the interface queue, and copy it to the interface
 1207  * before starting the output.
 1208  */
 1209 static void cx_send (drv_t *d)
 1210 {
 1211         struct mbuf *m;
 1212         u_short len;
 1213 
 1214         CX_DEBUG2 (d, ("cx_send\n"));
 1215 
 1216         /* No output if the interface is down. */
 1217         if (! d->running)
 1218                 return;
 1219 
 1220         /* No output if the modem is off. */
 1221         if (! cx_get_dsr (d->chan) && ! cx_get_loop(d->chan))
 1222                 return;
 1223 
 1224         if (cx_buf_free (d->chan)) {
 1225                 /* Get the packet to send. */
 1226 #ifdef NETGRAPH
 1227                 IF_DEQUEUE (&d->hi_queue, m);
 1228                 if (! m)
 1229                         IF_DEQUEUE (&d->lo_queue, m);
 1230 #else
 1231                 m = sppp_dequeue (&d->pp.pp_if);
 1232 #endif
 1233                 if (! m)
 1234                         return;
 1235 #if (__FreeBSD_version >= 400000 || NBPFILTER > 0) && !defined (NETGRAPH)
 1236                 if (d->pp.pp_if.if_bpf)
 1237 #if __FreeBSD_version >= 500000
 1238                         BPF_MTAP (&d->pp.pp_if, m);
 1239 #else
 1240                         bpf_mtap (&d->pp.pp_if, m);
 1241 #endif
 1242 #endif
 1243                 len = m->m_pkthdr.len;
 1244                 if (! m->m_next)
 1245                         cx_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
 1246                                 len, 0);
 1247                 else {
 1248                         u_char buf [DMABUFSZ];
 1249                         m_copydata (m, 0, len, buf);
 1250                         cx_send_packet (d->chan, buf, len, 0);
 1251                 }
 1252                 m_freem (m);
 1253 
 1254                 /* Set up transmit timeout, 10 seconds. */
 1255 #ifdef NETGRAPH
 1256                 d->timeout = 10;
 1257 #else
 1258                 d->pp.pp_if.if_timer = 10;
 1259 #endif
 1260         }
 1261 #ifndef NETGRAPH
 1262         d->pp.pp_if.if_flags |= IFF_OACTIVE;
 1263 #endif
 1264 }
 1265 
 1266 /*
 1267  * Start output on the interface.
 1268  * Always called on splimp().
 1269  */
 1270 static void cx_start (drv_t *d)
 1271 {
 1272         int s = splhigh ();
 1273         if (d->running) {
 1274                 if (! d->chan->dtr)
 1275                         cx_set_dtr (d->chan, 1);
 1276                 if (! d->chan->rts)
 1277                         cx_set_rts (d->chan, 1);
 1278                 cx_send (d);
 1279         }
 1280         splx (s);
 1281 }
 1282 
 1283 /*
 1284  * Handle transmit timeouts.
 1285  * Recover after lost transmit interrupts.
 1286  * Always called on splimp().
 1287  */
 1288 static void cx_watchdog (drv_t *d)
 1289 {
 1290         int s = splhigh ();
 1291         CX_DEBUG (d, ("device timeout\n"));
 1292         if (d->running) {
 1293                 cx_setup_chan (d->chan);
 1294                 cx_start_chan (d->chan, 0, 0);
 1295                 cx_set_dtr (d->chan, 1);
 1296                 cx_set_rts (d->chan, 1);
 1297                 cx_start (d);
 1298         }
 1299         splx (s);
 1300 }
 1301 
 1302 /*
 1303  * Transmit callback function.
 1304  */
 1305 static void cx_transmit (cx_chan_t *c, void *attachment, int len)
 1306 {
 1307         drv_t *d = c->sys;
 1308 
 1309         if (!d)
 1310                 return;
 1311                 
 1312         if (c->mode == M_ASYNC) {
 1313                 d->tty.t_state &= ~(TS_BUSY | TS_FLUSH);
 1314                 d->atimeout = 0;
 1315                 if (d->tty.t_dev) {
 1316                         d->intr_action |= CX_WRITE;
 1317                         MY_SOFT_INTR = 1;
 1318 #if __FreeBSD_version >= 500000
 1319                         swi_sched (cx_fast_ih, 0);
 1320 #else
 1321                         setsofttty ();
 1322 #endif
 1323                 }
 1324                 return;
 1325         }
 1326 #ifdef NETGRAPH
 1327         d->timeout = 0;
 1328 #else
 1329         ++d->pp.pp_if.if_opackets;
 1330         d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
 1331         d->pp.pp_if.if_timer = 0;
 1332 #endif
 1333         cx_start (d);
 1334 }
 1335 
 1336 /*
 1337  * Process the received packet.
 1338  */
 1339 static void cx_receive (cx_chan_t *c, char *data, int len)
 1340 {
 1341         drv_t *d = c->sys;
 1342         struct mbuf *m;
 1343         char *cc = data;
 1344 #if __FreeBSD_version >= 500000 && defined NETGRAPH
 1345         int error;
 1346 #endif
 1347 
 1348         if (!d)
 1349                 return;
 1350                 
 1351         if (c->mode == M_ASYNC) {
 1352                 if (d->tty.t_state & TS_ISOPEN) {
 1353                         async_q *q = &d->aqueue;
 1354                         int size = BF_SZ - 1 - AQ_GSZ (q);
 1355 
 1356                         if (len <= 0 && !size)
 1357                                 return;
 1358 
 1359                         if (len > size) {
 1360                                 c->ierrs++;
 1361                                 cx_error (c, CX_OVERRUN);
 1362                                 len = size - 1;
 1363                         }
 1364 
 1365                         while (len--) {
 1366                                 AQ_PUSH (q, *(unsigned char *)cc);
 1367                                 cc++;
 1368                         }
 1369 
 1370                         d->intr_action |= CX_READ;
 1371                         MY_SOFT_INTR = 1;
 1372 #if __FreeBSD_version >= 500000
 1373                         swi_sched (cx_fast_ih, 0);
 1374 #else
 1375                         setsofttty ();
 1376 #endif
 1377                 }
 1378                 return;
 1379         }
 1380         if (! d->running)
 1381                 return;
 1382 
 1383         m = makembuf (data, len);
 1384         if (! m) {
 1385                 CX_DEBUG (d, ("no memory for packet\n"));
 1386 #ifndef NETGRAPH
 1387                 ++d->pp.pp_if.if_iqdrops;
 1388 #endif
 1389                 return;
 1390         }
 1391         if (c->debug > 1)
 1392                 printmbuf (m);
 1393 #ifdef NETGRAPH
 1394         m->m_pkthdr.rcvif = 0;
 1395 #if __FreeBSD_version >= 500000
 1396         NG_SEND_DATA_ONLY (error, d->hook, m);
 1397 #else
 1398         ng_queue_data (d->hook, m, 0);
 1399 #endif
 1400 #else
 1401         ++d->pp.pp_if.if_ipackets;
 1402         m->m_pkthdr.rcvif = &d->pp.pp_if;
 1403 #if __FreeBSD_version >= 400000 || NBPFILTER > 0
 1404         /* Check if there's a BPF listener on this interface.
 1405          * If so, hand off the raw packet to bpf. */
 1406         if (d->pp.pp_if.if_bpf)
 1407 #if __FreeBSD_version >= 500000
 1408                 BPF_TAP (&d->pp.pp_if, data, len);
 1409 #else
 1410                 bpf_tap (&d->pp.pp_if, data, len);
 1411 #endif
 1412 #endif
 1413         sppp_input (&d->pp.pp_if, m);
 1414 #endif
 1415 }
 1416 
 1417 #define CONDITION(t,tp) (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))\
 1418             && (!(tp->t_iflag & BRKINT) || (tp->t_iflag & IGNBRK))\
 1419             && (!(tp->t_iflag & PARMRK)\
 1420                 || (tp->t_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))\
 1421             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))\
 1422             && linesw[tp->t_line].l_rint == ttyinput)
 1423 
 1424 /*
 1425  * Error callback function.
 1426  */
 1427 static void cx_error (cx_chan_t *c, int data)
 1428 {
 1429         drv_t *d = c->sys;
 1430         async_q *q;
 1431 
 1432         if (!d)
 1433                 return;
 1434 
 1435         q = &(d->aqueue);
 1436 
 1437         switch (data) {
 1438         case CX_FRAME:
 1439                 CX_DEBUG (d, ("frame error\n"));
 1440                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN)
 1441                         && (AQ_GSZ (q) < BF_SZ - 1)
 1442                         && (!CONDITION((&d->tty.t_termios), (&d->tty))
 1443                         || !(d->tty.t_iflag & (IGNPAR | PARMRK)))) {
 1444                         AQ_PUSH (q, TTY_FE);
 1445                         d->intr_action |= CX_READ;
 1446                         MY_SOFT_INTR = 1;
 1447 #if __FreeBSD_version >= 500000
 1448                         swi_sched (cx_fast_ih, 0);
 1449 #else
 1450                         setsofttty ();
 1451 #endif
 1452                 }
 1453 #ifndef NETGRAPH
 1454                 else
 1455                         ++d->pp.pp_if.if_ierrors;
 1456 #endif
 1457                 break;
 1458         case CX_CRC:
 1459                 CX_DEBUG (d, ("crc error\n"));
 1460                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN)
 1461                         && (AQ_GSZ (q) < BF_SZ - 1)
 1462                         && (!CONDITION((&d->tty.t_termios), (&d->tty))
 1463                         || !(d->tty.t_iflag & INPCK)
 1464                         || !(d->tty.t_iflag & (IGNPAR | PARMRK)))) {
 1465                         AQ_PUSH (q, TTY_PE);
 1466                         d->intr_action |= CX_READ;
 1467                         MY_SOFT_INTR = 1;
 1468 #if __FreeBSD_version >= 500000
 1469                         swi_sched (cx_fast_ih, 0);
 1470 #else
 1471                         setsofttty ();
 1472 #endif
 1473                 }
 1474 #ifndef NETGRAPH
 1475                 else
 1476                         ++d->pp.pp_if.if_ierrors;
 1477 #endif
 1478                 break;
 1479         case CX_OVERRUN:
 1480                 CX_DEBUG (d, ("overrun error\n"));
 1481 #ifdef TTY_OE
 1482                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN)
 1483                         && (AQ_GSZ (q) < BF_SZ - 1)
 1484                         && (!CONDITION((&d->tty.t_termios), (&d->tty)))) {
 1485                         AQ_PUSH (q, TTY_OE);
 1486                         d->intr_action |= CX_READ;
 1487                         MY_SOFT_INTR = 1;
 1488 #if __FreeBSD_version >= 500000
 1489                         swi_sched (cx_fast_ih, 0);
 1490 #else
 1491                         setsofttty ();
 1492 #endif
 1493                 }
 1494 #endif
 1495 #ifndef NETGRAPH
 1496                 else {
 1497                         ++d->pp.pp_if.if_collisions;
 1498                         ++d->pp.pp_if.if_ierrors;
 1499                 }
 1500 #endif
 1501                 break;
 1502         case CX_OVERFLOW:
 1503                 CX_DEBUG (d, ("overflow error\n"));
 1504 #ifndef NETGRAPH
 1505                 if (c->mode != M_ASYNC)
 1506                         ++d->pp.pp_if.if_ierrors;
 1507 #endif
 1508                 break;
 1509         case CX_UNDERRUN:
 1510                 CX_DEBUG (d, ("underrun error\n"));
 1511                 if (c->mode != M_ASYNC) {
 1512 #ifdef NETGRAPH
 1513                         d->timeout = 0;
 1514 #else
 1515                         ++d->pp.pp_if.if_oerrors;
 1516                         d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
 1517                         d->pp.pp_if.if_timer = 0;
 1518                         cx_start (d);
 1519 #endif
 1520                 }
 1521                 break;
 1522         case CX_BREAK:
 1523                 CX_DEBUG (d, ("break error\n"));
 1524                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN)
 1525                         && (AQ_GSZ (q) < BF_SZ - 1)
 1526                         && (!CONDITION((&d->tty.t_termios), (&d->tty))
 1527                         || !(d->tty.t_iflag & (IGNBRK | BRKINT | PARMRK)))) {
 1528                         AQ_PUSH (q, TTY_BI);
 1529                         d->intr_action |= CX_READ;
 1530                         MY_SOFT_INTR = 1;
 1531 #if __FreeBSD_version >= 500000
 1532                         swi_sched (cx_fast_ih, 0);
 1533 #else
 1534                         setsofttty ();
 1535 #endif
 1536                 }
 1537 #ifndef NETGRAPH
 1538                 else
 1539                         ++d->pp.pp_if.if_ierrors;
 1540 #endif
 1541                 break;
 1542         default:
 1543                 CX_DEBUG (d, ("error #%d\n", data));
 1544         }
 1545 }
 1546 
 1547 #if __FreeBSD_version < 500000
 1548 static int cx_open (dev_t dev, int flag, int mode, struct proc *p)
 1549 #else
 1550 static int cx_open (dev_t dev, int flag, int mode, struct thread *td)
 1551 #endif
 1552 {
 1553         int unit = UNIT (dev);
 1554         drv_t *d;
 1555         int error;
 1556 
 1557         if (unit >= NCX*NCHAN || ! (d = channel[unit]))
 1558                 return ENXIO;
 1559         CX_DEBUG2 (d, ("cx_open unit=%d, flag=0x%x, mode=0x%x\n",
 1560                     unit, flag, mode));
 1561 
 1562         if (d->chan->mode != M_ASYNC || IF_CUNIT(dev)) {
 1563                 d->open_dev |= 0x1;
 1564                 return 0;
 1565         }
 1566 #if __FreeBSD_version >= 400000
 1567         dev->si_tty = &d->tty;
 1568 #endif
 1569         d->tty.t_dev = dev;
 1570 again:
 1571         if (d->dtroff) {
 1572                 error = tsleep (&d->dtrwait, TTIPRI | PCATCH, "cxdtr", 0);
 1573                 if (error)
 1574                         return error;
 1575                 goto again;
 1576         }
 1577 
 1578         if ((d->tty.t_state & TS_ISOPEN) && (d->tty.t_state & TS_XCLUDE) &&
 1579 #if __FreeBSD_version >= 500000
 1580                 suser (td))
 1581 #else
 1582             p->p_ucred->cr_uid != 0)
 1583 #endif
 1584                 return EBUSY;
 1585 
 1586         if (d->tty.t_state & TS_ISOPEN) {
 1587                 /*
 1588                  * Cannot open /dev/cua if /dev/tty already opened.
 1589                  */
 1590                 if (CALLOUT (dev) && ! d->callout)
 1591                         return EBUSY;
 1592 
 1593                 /*
 1594                  * Opening /dev/tty when /dev/cua is already opened.
 1595                  * Wait for close, then try again.
 1596                  */
 1597                 if (! CALLOUT (dev) && d->callout) {
 1598                         if (flag & O_NONBLOCK)
 1599                                 return EBUSY;
 1600                         error = tsleep (d, TTIPRI | PCATCH, "cxbi", 0);
 1601                         if (error)
 1602                                 return error;
 1603                         goto again;
 1604                 }
 1605         } else if (d->lock && ! CALLOUT (dev) && (flag & O_NONBLOCK))
 1606                 /*
 1607                  * We try to open /dev/tty in non-blocking mode
 1608                  * while somebody is already waiting for carrier on it.
 1609                  */
 1610                 return EBUSY;
 1611         else {
 1612                 ttychars (&d->tty);
 1613                 if (d->tty.t_ispeed == 0) {
 1614                         d->tty.t_iflag = 0;
 1615                         d->tty.t_oflag = 0;
 1616                         d->tty.t_lflag = 0;
 1617                         d->tty.t_cflag = CREAD | CS8 | HUPCL;
 1618                         d->tty.t_ispeed = d->chan->rxbaud;
 1619                         d->tty.t_ospeed = d->chan->txbaud;
 1620                 }
 1621                 if (CALLOUT (dev))
 1622                         d->tty.t_cflag |= CLOCAL;
 1623                 else
 1624                         d->tty.t_cflag &= ~CLOCAL;
 1625                 cx_param (&d->tty, &d->tty.t_termios);
 1626                 ttsetwater (&d->tty);
 1627         }
 1628 
 1629         splhigh ();
 1630         if (! (d->tty.t_state & TS_ISOPEN)) {
 1631                 cx_start_chan (d->chan, 0, 0);
 1632                 cx_set_dtr (d->chan, 1);
 1633                 cx_set_rts (d->chan, 1);
 1634                 d->cd = cx_get_cd (d->chan);
 1635                 if (CALLOUT (dev) || cx_get_cd (d->chan))
 1636                         (*linesw[d->tty.t_line].l_modem) (&d->tty, 1);
 1637         }
 1638 
 1639         if (! (flag & O_NONBLOCK) && ! (d->tty.t_cflag & CLOCAL) &&
 1640             ! (d->tty.t_state & TS_CARR_ON)) {
 1641                 /* Lock the channel against cxconfig while we are
 1642                  * waiting for carrier. */
 1643                 d->lock++;
 1644                 error = tsleep (&d->tty.t_rawq, TTIPRI | PCATCH, "cxdcd", 0);
 1645                 /* Unlock the channel. */
 1646                 d->lock--;
 1647                 spl0 ();
 1648                 if (error)
 1649                         goto failed;
 1650                 goto again;
 1651         }
 1652 
 1653         error = (*linesw[d->tty.t_line].l_open) (dev, &d->tty);
 1654         disc_optim (&d->tty, &d->tty.t_termios);
 1655         spl0 ();
 1656         if (error) {
 1657 failed:         if (! (d->tty.t_state & TS_ISOPEN)) {
 1658                         splhigh ();
 1659                         cx_set_dtr (d->chan, 0);
 1660                         cx_set_rts (d->chan, 0);
 1661                         if (d->dtrwait) {
 1662                                 d->dtr_timeout_handle =
 1663                                     timeout (cx_dtrwakeup, d, d->dtrwait);
 1664                                 d->dtroff = 1;
 1665                         }
 1666                         spl0 ();
 1667                 }
 1668                 return error;
 1669         }
 1670 
 1671         if (d->tty.t_state & TS_ISOPEN)
 1672                 d->callout = CALLOUT (dev) ? 1 : 0;
 1673 
 1674         d->open_dev |= 0x2;
 1675         CX_DEBUG2 (d, ("cx_open done\n"));
 1676         return 0;
 1677 }
 1678 
 1679 #if __FreeBSD_version < 500000
 1680 static int cx_close (dev_t dev, int flag, int mode, struct proc *p)
 1681 #else
 1682 static int cx_close (dev_t dev, int flag, int mode, struct thread *td)
 1683 #endif
 1684 {
 1685         drv_t *d = channel [UNIT (dev)];
 1686         int s;
 1687 
 1688         CX_DEBUG2 (d, ("cx_close\n"));
 1689         if ((!(d->open_dev&0x2)) || IF_CUNIT(dev)){
 1690                 d->open_dev &= ~0x1;
 1691                 return 0;
 1692         }
 1693         s = splhigh ();
 1694         (*linesw[d->tty.t_line].l_close) (&d->tty, flag);
 1695         disc_optim (&d->tty, &d->tty.t_termios);
 1696 
 1697         /* Disable receiver.
 1698          * Transmitter continues sending the queued data. */
 1699         cx_enable_receive (d->chan, 0);
 1700 
 1701         /* Clear DTR and RTS. */
 1702         if ((d->tty.t_cflag & HUPCL) || ! (d->tty.t_state & TS_ISOPEN)) {
 1703                 cx_set_dtr (d->chan, 0);
 1704                 cx_set_rts (d->chan, 0);
 1705                 if (d->dtrwait) {
 1706                         d->dtr_timeout_handle =
 1707                             timeout (cx_dtrwakeup, d, d->dtrwait);
 1708                         d->dtroff = 1;
 1709                 }
 1710         }
 1711         ttyclose (&d->tty);
 1712         splx (s);
 1713         d->callout = 0;
 1714 
 1715         /* Wake up bidirectional opens. */
 1716         wakeup (d);
 1717         d->open_dev &= ~0x2;
 1718 
 1719         return 0;
 1720 }
 1721 
 1722 static int cx_read (dev_t dev, struct uio *uio, int flag)
 1723 {
 1724         drv_t *d = channel [UNIT (dev)];
 1725 
 1726         if (d)  CX_DEBUG2 (d, ("cx_read\n"));
 1727         if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev))
 1728                 return EBADF;
 1729 
 1730         return (*linesw[d->tty.t_line].l_read) (&d->tty, uio, flag);
 1731 }
 1732 
 1733 static int cx_write (dev_t dev, struct uio *uio, int flag)
 1734 {
 1735         drv_t *d = channel [UNIT (dev)];
 1736 
 1737         if (d) CX_DEBUG2 (d, ("cx_write\n"));
 1738         if (!d || d->chan->mode != M_ASYNC || IF_CUNIT(dev))
 1739                 return EBADF;
 1740 
 1741         return (*linesw[d->tty.t_line].l_write) (&d->tty, uio, flag);
 1742 }
 1743 
 1744 static int cx_modem_status (drv_t *d)
 1745 {
 1746         int status = 0, s = splhigh ();
 1747         /* Already opened by someone or network interface is up? */
 1748         if ((d->chan->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN) &&
 1749             (d->open_dev|0x2)) || (d->chan->mode != M_ASYNC && d->running))
 1750                 status = TIOCM_LE;      /* always enabled while open */
 1751 
 1752         if (cx_get_dsr (d->chan)) status |= TIOCM_DSR;
 1753         if (cx_get_cd  (d->chan)) status |= TIOCM_CD;
 1754         if (cx_get_cts (d->chan)) status |= TIOCM_CTS;
 1755         if (d->chan->dtr)         status |= TIOCM_DTR;
 1756         if (d->chan->rts)         status |= TIOCM_RTS;
 1757         splx (s);
 1758         return status;
 1759 }
 1760 
 1761 #if __FreeBSD_version < 500000
 1762 static int cx_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
 1763 #else
 1764 static int cx_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 1765 #endif
 1766 {
 1767         drv_t *d = channel [UNIT (dev)];
 1768         cx_chan_t *c;
 1769         struct serial_statistics *st;
 1770         int error, s;
 1771         char mask[16];
 1772 
 1773         if (!d || !(c = d->chan))
 1774                 return EINVAL;
 1775                 
 1776         switch (cmd) {
 1777         case SERIAL_GETREGISTERED:
 1778                 CX_DEBUG2 (d, ("ioctl: getregistered\n"));
 1779                 bzero (mask, sizeof(mask));
 1780                 for (s=0; s<NCX*NCHAN; ++s)
 1781                         if (channel [s])
 1782                                 mask [s/8] |= 1 << (s & 7);
 1783                 bcopy (mask, data, sizeof (mask));
 1784                 return 0;
 1785 
 1786         case SERIAL_GETPORT:
 1787                 CX_DEBUG2 (d, ("ioctl: getport\n"));
 1788                 s = splhigh ();
 1789                 *(int *)data = cx_get_port (c);
 1790                 splx (s);
 1791                 if (*(int *)data<0)
 1792                         return (EINVAL);
 1793                 else
 1794                         return 0;
 1795 
 1796         case SERIAL_SETPORT:
 1797                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1798                 /* Only for superuser! */
 1799 #if __FreeBSD_version < 400000
 1800                 error = suser (p->p_ucred, &p->p_acflag);
 1801 #elif __FreeBSD_version < 500000
 1802                 error = suser (p);
 1803 #else /* __FreeBSD_version >= 500000 */
 1804                 error = suser (td);
 1805 #endif /* __FreeBSD_version >= 500000 */
 1806                 if (error)
 1807                         return error;
 1808 
 1809                 s = splhigh ();
 1810                 cx_set_port (c, *(int *)data);
 1811                 splx (s);
 1812                 return 0;
 1813 
 1814 #ifndef NETGRAPH
 1815         case SERIAL_GETPROTO:
 1816                 CX_DEBUG2 (d, ("ioctl: getproto\n"));
 1817                 s = splhigh ();
 1818                 strcpy ((char*)data, (c->mode == M_ASYNC) ? "async" :
 1819                         (d->pp.pp_flags & PP_FR) ? "fr" :
 1820                         (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp");
 1821                 splx (s);
 1822                 return 0;
 1823 
 1824         case SERIAL_SETPROTO:
 1825                 CX_DEBUG2 (d, ("ioctl: setproto\n"));
 1826                 /* Only for superuser! */
 1827 #if __FreeBSD_version < 400000
 1828                 error = suser (p->p_ucred, &p->p_acflag);
 1829 #elif __FreeBSD_version < 500000
 1830                 error = suser (p);
 1831 #else /* __FreeBSD_version >= 500000 */
 1832                 error = suser (td);
 1833 #endif /* __FreeBSD_version >= 500000 */
 1834                 if (error)
 1835                         return error;
 1836                 if (c->mode == M_ASYNC)
 1837                         return EBUSY;
 1838                 if (d->pp.pp_if.if_flags & IFF_RUNNING)
 1839                         return EBUSY;
 1840                 if (! strcmp ("cisco", (char*)data)) {
 1841                         d->pp.pp_flags &= ~(PP_FR);
 1842                         d->pp.pp_flags |= PP_KEEPALIVE;
 1843                         d->pp.pp_if.if_flags |= PP_CISCO;
 1844                 } else if (! strcmp ("fr", (char*)data)) {
 1845                         d->pp.pp_if.if_flags &= ~(PP_CISCO);
 1846                         d->pp.pp_flags |= PP_FR | PP_KEEPALIVE;
 1847                 } else if (! strcmp ("ppp", (char*)data)) {
 1848                         d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE);
 1849                         d->pp.pp_if.if_flags &= ~(PP_CISCO);
 1850                 } else
 1851                         return EINVAL;
 1852                 return 0;
 1853 
 1854         case SERIAL_GETKEEPALIVE:
 1855                 CX_DEBUG2 (d, ("ioctl: getkeepalive\n"));
 1856                 if ((d->pp.pp_flags & PP_FR) ||
 1857                     (d->pp.pp_if.if_flags & PP_CISCO) ||
 1858                     (c->mode == M_ASYNC))
 1859                         return EINVAL;
 1860                 s = splhigh ();
 1861                 *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0;
 1862                 splx (s);
 1863                 return 0;
 1864 
 1865         case SERIAL_SETKEEPALIVE:
 1866                 CX_DEBUG2 (d, ("ioctl: setkeepalive\n"));
 1867                 /* Only for superuser! */
 1868 #if __FreeBSD_version < 400000
 1869                 error = suser (p->p_ucred, &p->p_acflag);
 1870 #elif __FreeBSD_version < 500000
 1871                 error = suser (p);
 1872 #else /* __FreeBSD_version >= 500000 */
 1873                 error = suser (td);
 1874 #endif /* __FreeBSD_version >= 500000 */
 1875                 if (error)
 1876                         return error;
 1877                 if ((d->pp.pp_flags & PP_FR) ||
 1878                         (d->pp.pp_if.if_flags & PP_CISCO))
 1879                         return EINVAL;
 1880                 s = splhigh ();
 1881                 if (*(int*)data)
 1882                         d->pp.pp_flags |= PP_KEEPALIVE;
 1883                 else
 1884                         d->pp.pp_flags &= ~PP_KEEPALIVE;
 1885                 splx (s);
 1886                 return 0;
 1887 #endif /*NETGRAPH*/
 1888 
 1889         case SERIAL_GETMODE:
 1890                 CX_DEBUG2 (d, ("ioctl: getmode\n"));
 1891                 s = splhigh ();
 1892                 *(int*)data = (c->mode == M_ASYNC) ?
 1893                         SERIAL_ASYNC : SERIAL_HDLC;
 1894                 splx (s);
 1895                 return 0;
 1896 
 1897         case SERIAL_SETMODE:
 1898                 CX_DEBUG2 (d, ("ioctl: setmode\n"));
 1899                 /* Only for superuser! */
 1900 #if __FreeBSD_version < 400000
 1901                 error = suser (p->p_ucred, &p->p_acflag);
 1902 #elif __FreeBSD_version < 500000
 1903                 error = suser (p);
 1904 #else /* __FreeBSD_version >= 500000 */
 1905                 error = suser (td);
 1906 #endif /* __FreeBSD_version >= 500000 */
 1907                 if (error)
 1908                         return error;
 1909 
 1910                 /* Somebody is waiting for carrier? */
 1911                 if (d->lock)
 1912                         return EBUSY;
 1913                 /* /dev/ttyXX is already opened by someone? */
 1914                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN) &&
 1915                     (d->open_dev|0x2))
 1916                         return EBUSY;
 1917                 /* Network interface is up?
 1918                  * Cannot change to async mode. */
 1919                 if (c->mode != M_ASYNC && d->running &&
 1920                     (*(int*)data == SERIAL_ASYNC))
 1921                         return EBUSY;
 1922 
 1923                 s = splhigh ();
 1924                 if (c->mode == M_HDLC && *(int*)data == SERIAL_ASYNC) {
 1925                         cx_set_mode (c, M_ASYNC);
 1926                         cx_enable_receive (c, 0);
 1927                         cx_enable_transmit (c, 0);
 1928                 } else if (c->mode == M_ASYNC && *(int*)data == SERIAL_HDLC) {
 1929                         cx_set_mode (c, M_HDLC);
 1930                         cx_enable_receive (c, 1);
 1931                         cx_enable_transmit (c, 1);
 1932                 }
 1933                 splx (s);
 1934                 return 0;
 1935 
 1936         case SERIAL_GETSTAT:
 1937                 CX_DEBUG2 (d, ("ioctl: getestat\n"));
 1938                 st = (struct serial_statistics*) data;
 1939                 s = splhigh ();
 1940                 st->rintr  = c->rintr;
 1941                 st->tintr  = c->tintr;
 1942                 st->mintr  = c->mintr;
 1943                 st->ibytes = c->ibytes;
 1944                 st->ipkts  = c->ipkts;
 1945                 st->ierrs  = c->ierrs;
 1946                 st->obytes = c->obytes;
 1947                 st->opkts  = c->opkts;
 1948                 st->oerrs  = c->oerrs;
 1949                 splx (s);
 1950                 return 0;
 1951 
 1952         case SERIAL_CLRSTAT:
 1953                 CX_DEBUG2 (d, ("ioctl: clrstat\n"));
 1954                 /* Only for superuser! */
 1955 #if __FreeBSD_version < 400000
 1956                 error = suser (p->p_ucred, &p->p_acflag);
 1957 #elif __FreeBSD_version < 500000
 1958                 error = suser (p);
 1959 #else /* __FreeBSD_version >= 500000 */
 1960                 error = suser (td);
 1961 #endif /* __FreeBSD_version >= 500000 */
 1962                 if (error)
 1963                         return error;
 1964                 s = splhigh ();
 1965                 c->rintr = 0;
 1966                 c->tintr = 0;
 1967                 c->mintr = 0;
 1968                 c->ibytes = 0;
 1969                 c->ipkts = 0;
 1970                 c->ierrs = 0;
 1971                 c->obytes = 0;
 1972                 c->opkts = 0;
 1973                 c->oerrs = 0;
 1974                 splx (s);
 1975                 return 0;
 1976 
 1977         case SERIAL_GETBAUD:
 1978                 CX_DEBUG2 (d, ("ioctl: getbaud\n"));
 1979                 if (c->mode == M_ASYNC)
 1980                         return EINVAL;
 1981                 s = splhigh ();
 1982                 *(long*)data = cx_get_baud(c);
 1983                 splx (s);
 1984                 return 0;
 1985 
 1986         case SERIAL_SETBAUD:
 1987                 CX_DEBUG2 (d, ("ioctl: setbaud\n"));
 1988                 /* Only for superuser! */
 1989 #if __FreeBSD_version < 400000
 1990                 error = suser (p->p_ucred, &p->p_acflag);
 1991 #elif __FreeBSD_version < 500000
 1992                 error = suser (p);
 1993 #else /* __FreeBSD_version >= 500000 */
 1994                 error = suser (td);
 1995 #endif /* __FreeBSD_version >= 500000 */
 1996                 if (error)
 1997                         return error;
 1998                 if (c->mode == M_ASYNC)
 1999                         return EINVAL;
 2000                 s = splhigh ();
 2001                 cx_set_baud (c, *(long*)data);
 2002                 splx (s);
 2003                 return 0;
 2004 
 2005         case SERIAL_GETLOOP:
 2006                 CX_DEBUG2 (d, ("ioctl: getloop\n"));
 2007                 if (c->mode == M_ASYNC)
 2008                         return EINVAL;
 2009                 s = splhigh ();
 2010                 *(int*)data = cx_get_loop (c);
 2011                 splx (s);
 2012                 return 0;
 2013 
 2014         case SERIAL_SETLOOP:
 2015                 CX_DEBUG2 (d, ("ioctl: setloop\n"));
 2016                 /* Only for superuser! */
 2017 #if __FreeBSD_version < 400000
 2018                 error = suser (p->p_ucred, &p->p_acflag);
 2019 #elif __FreeBSD_version < 500000
 2020                 error = suser (p);
 2021 #else /* __FreeBSD_version >= 500000 */
 2022                 error = suser (td);
 2023 #endif /* __FreeBSD_version >= 500000 */
 2024                 if (error)
 2025                         return error;
 2026                 if (c->mode == M_ASYNC)
 2027                         return EINVAL;
 2028                 s = splhigh ();
 2029                 cx_set_loop (c, *(int*)data);
 2030                 splx (s);
 2031                 return 0;
 2032 
 2033         case SERIAL_GETDPLL:
 2034                 CX_DEBUG2 (d, ("ioctl: getdpll\n"));
 2035                 if (c->mode == M_ASYNC)
 2036                         return EINVAL;
 2037                 s = splhigh ();
 2038                 *(int*)data = cx_get_dpll (c);
 2039                 splx (s);
 2040                 return 0;
 2041 
 2042         case SERIAL_SETDPLL:
 2043                 CX_DEBUG2 (d, ("ioctl: setdpll\n"));
 2044                 /* Only for superuser! */
 2045 #if __FreeBSD_version < 400000
 2046                 error = suser (p->p_ucred, &p->p_acflag);
 2047 #elif __FreeBSD_version < 500000
 2048                 error = suser (p);
 2049 #else /* __FreeBSD_version >= 500000 */
 2050                 error = suser (td);
 2051 #endif /* __FreeBSD_version >= 500000 */
 2052                 if (error)
 2053                         return error;
 2054                 if (c->mode == M_ASYNC)
 2055                         return EINVAL;
 2056                 s = splhigh ();
 2057                 cx_set_dpll (c, *(int*)data);
 2058                 splx (s);
 2059                 return 0;
 2060 
 2061         case SERIAL_GETNRZI:
 2062                 CX_DEBUG2 (d, ("ioctl: getnrzi\n"));
 2063                 if (c->mode == M_ASYNC)
 2064                         return EINVAL;
 2065                 s = splhigh ();
 2066                 *(int*)data = cx_get_nrzi (c);
 2067                 splx (s);
 2068                 return 0;
 2069 
 2070         case SERIAL_SETNRZI:
 2071                 CX_DEBUG2 (d, ("ioctl: setnrzi\n"));
 2072                 /* Only for superuser! */
 2073 #if __FreeBSD_version < 400000
 2074                 error = suser (p->p_ucred, &p->p_acflag);
 2075 #elif __FreeBSD_version < 500000
 2076                 error = suser (p);
 2077 #else /* __FreeBSD_version >= 500000 */
 2078                 error = suser (td);
 2079 #endif /* __FreeBSD_version >= 500000 */
 2080                 if (error)
 2081                         return error;
 2082                 if (c->mode == M_ASYNC)
 2083                         return EINVAL;
 2084                 s = splhigh ();
 2085                 cx_set_nrzi (c, *(int*)data);
 2086                 splx (s);
 2087                 return 0;
 2088 
 2089         case SERIAL_GETDEBUG:
 2090                 CX_DEBUG2 (d, ("ioctl: getdebug\n"));
 2091                 s = splhigh ();
 2092                 *(int*)data = c->debug;
 2093                 splx (s);
 2094                 return 0;
 2095 
 2096         case SERIAL_SETDEBUG:
 2097                 CX_DEBUG2 (d, ("ioctl: setdebug\n"));
 2098                 /* Only for superuser! */
 2099 #if __FreeBSD_version < 400000
 2100                 error = suser (p->p_ucred, &p->p_acflag);
 2101 #elif __FreeBSD_version < 500000
 2102                 error = suser (p);
 2103 #else /* __FreeBSD_version >= 500000 */
 2104                 error = suser (td);
 2105 #endif /* __FreeBSD_version >= 500000 */
 2106                 if (error)
 2107                         return error;
 2108                 s = splhigh ();
 2109                 c->debug = *(int*)data;
 2110                 splx (s);
 2111 #ifndef NETGRAPH
 2112                 if (d->chan->debug)
 2113                         d->pp.pp_if.if_flags |= IFF_DEBUG;
 2114                 else
 2115                         d->pp.pp_if.if_flags &= (~IFF_DEBUG);
 2116 #endif
 2117                 return 0;
 2118         }
 2119 
 2120         if (c->mode == M_ASYNC) {
 2121 #if __FreeBSD_version >= 500000
 2122                 error = (*linesw[d->tty.t_line].l_ioctl) (&d->tty, cmd, data, flag, td);
 2123 #else
 2124                 error = (*linesw[d->tty.t_line].l_ioctl) (&d->tty, cmd, data, flag, p);
 2125 #endif
 2126                 disc_optim (&d->tty, &d->tty.t_termios);
 2127                 if (error != ENOIOCTL) {
 2128                         if (error)
 2129                         CX_DEBUG2 (d, ("l_ioctl: 0x%lx, error %d\n", cmd, error));
 2130                         return error;
 2131                 }
 2132                 error = ttioctl (&d->tty, cmd, data, flag);
 2133                 disc_optim (&d->tty, &d->tty.t_termios);
 2134                 if (error != ENOIOCTL) {
 2135                         if (error)
 2136                         CX_DEBUG2 (d, ("ttioctl: 0x%lx, error %d\n", cmd, error));
 2137                         return error;
 2138                 }
 2139         }
 2140 
 2141         switch (cmd) {
 2142         case TIOCSBRK:          /* Start sending line break */
 2143                 CX_DEBUG2 (d, ("ioctl: tiocsbrk\n"));
 2144                 s = splhigh ();
 2145                 cx_send_break (c, 500);
 2146                 splx (s);
 2147                 return 0;
 2148 
 2149         case TIOCCBRK:          /* Stop sending line break */
 2150                 CX_DEBUG2 (d, ("ioctl: tioccbrk\n"));
 2151                 return 0;
 2152 
 2153         case TIOCSDTR:          /* Set DTR */
 2154                 CX_DEBUG2 (d, ("ioctl: tiocsdtr\n"));
 2155                 s = splhigh ();
 2156                 cx_set_dtr (c, 1);
 2157                 splx (s);
 2158                 return 0;
 2159 
 2160         case TIOCCDTR:          /* Clear DTR */
 2161                 CX_DEBUG2 (d, ("ioctl: tioccdtr\n"));
 2162                 s = splhigh ();
 2163                 cx_set_dtr (c, 0);
 2164                 splx (s);
 2165                 return 0;
 2166 
 2167         case TIOCMSET:          /* Set DTR/RTS */
 2168                 CX_DEBUG2 (d, ("ioctl: tiocmset\n"));
 2169                 s = splhigh ();
 2170                 cx_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
 2171                 cx_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
 2172                 splx (s);
 2173                 return 0;
 2174 
 2175         case TIOCMBIS:          /* Add DTR/RTS */
 2176                 CX_DEBUG2 (d, ("ioctl: tiocmbis\n"));
 2177                 s = splhigh ();
 2178                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 1);
 2179                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 1);
 2180                 splx (s);
 2181                 return 0;
 2182 
 2183         case TIOCMBIC:          /* Clear DTR/RTS */
 2184                 CX_DEBUG2 (d, ("ioctl: tiocmbic\n"));
 2185                 s = splhigh ();
 2186                 if (*(int*)data & TIOCM_DTR) cx_set_dtr (c, 0);
 2187                 if (*(int*)data & TIOCM_RTS) cx_set_rts (c, 0);
 2188                 splx (s);
 2189                 return 0;
 2190 
 2191         case TIOCMGET:          /* Get modem status */
 2192                 CX_DEBUG2 (d, ("ioctl: tiocmget\n"));
 2193                 *(int*)data = cx_modem_status (d);
 2194                 return 0;
 2195 
 2196 #ifdef TIOCMSDTRWAIT
 2197         case TIOCMSDTRWAIT:
 2198                 CX_DEBUG2 (d, ("ioctl: tiocmsdtrwait\n"));
 2199                 /* Only for superuser! */
 2200 #if __FreeBSD_version < 400000
 2201                 error = suser (p->p_ucred, &p->p_acflag);
 2202 #elif __FreeBSD_version < 500000
 2203                 error = suser (p);
 2204 #else /* __FreeBSD_version >= 500000 */
 2205                 error = suser (td);
 2206 #endif /* __FreeBSD_version >= 500000 */
 2207                 if (error)
 2208                         return error;
 2209                 s = splhigh ();
 2210                 d->dtrwait = *(int*)data * hz / 100;
 2211                 splx (s);
 2212                 return 0;
 2213 #endif
 2214 
 2215 #ifdef TIOCMGDTRWAIT
 2216         case TIOCMGDTRWAIT:
 2217                 CX_DEBUG2 (d, ("ioctl: tiocmgdtrwait\n"));
 2218                 s = splhigh ();
 2219                 *(int*)data = d->dtrwait * 100 / hz;
 2220                 splx (s);
 2221                 return 0;
 2222 #endif
 2223         }
 2224         CX_DEBUG2 (d, ("ioctl: 0x%lx\n", cmd));
 2225         return ENOTTY;
 2226 }
 2227 
 2228 /*
 2229  * Wake up opens() waiting for DTR ready.
 2230  */
 2231 static void cx_dtrwakeup (void *arg)
 2232 {
 2233         drv_t *d = arg;
 2234 
 2235         d->dtroff = 0;
 2236         wakeup (&d->dtrwait);
 2237 }
 2238 
 2239 
 2240 static void
 2241 disc_optim(tp, t)
 2242         struct tty      *tp;
 2243         struct termios  *t;
 2244 {
 2245         if (CONDITION(t,tp))
 2246                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2247         else
 2248                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2249 }
 2250 
 2251 #if __FreeBSD_version >= 500000
 2252 void cx_softintr (void *unused)
 2253 #else
 2254 void cx_softintr ()
 2255 #endif
 2256 {
 2257         drv_t *d;
 2258         async_q *q;
 2259         int i, s, ic, k;
 2260         while (MY_SOFT_INTR) {
 2261                 MY_SOFT_INTR = 0;
 2262                 for (i=0; i<NCX*NCHAN; ++i) {
 2263                         d = channel [i];
 2264                         if (!d || !d->chan || d->chan->type == T_NONE
 2265                             || d->chan->mode != M_ASYNC || !d->tty.t_dev)
 2266                                 continue;
 2267                         s = splhigh ();
 2268                         if (d->intr_action & CX_READ) {
 2269                                 q = &(d->aqueue);
 2270                                 if (d->tty.t_state & TS_CAN_BYPASS_L_RINT) {
 2271                                         k = AQ_GSZ(q);
 2272                                         if (d->tty.t_rawq.c_cc + k >
 2273                                                 d->tty.t_ihiwat
 2274                                             && (d->tty.t_cflag & CRTS_IFLOW
 2275                                                 || d->tty.t_iflag & IXOFF)
 2276                                             && !(d->tty.t_state & TS_TBLOCK))
 2277                                                 ttyblock(&d->tty);
 2278                                         d->tty.t_rawcc += k;
 2279                                         while (k>0) {
 2280                                                 k--;
 2281                                                 AQ_POP (q, ic);
 2282                                                 splx (s);
 2283                                                 putc (ic, &d->tty.t_rawq);
 2284                                                 s = splhigh ();
 2285                                         }
 2286                                         ttwakeup(&d->tty);
 2287                                         if (d->tty.t_state & TS_TTSTOP
 2288                                             && (d->tty.t_iflag & IXANY
 2289                                                 || d->tty.t_cc[VSTART] ==
 2290                                                 d->tty.t_cc[VSTOP])) {
 2291                                                 d->tty.t_state &= ~TS_TTSTOP;
 2292                                                 d->tty.t_lflag &= ~FLUSHO;
 2293                                                 d->intr_action |= CX_WRITE;
 2294                                         }
 2295                                 } else {
 2296                                         while (q->end != q->beg) {
 2297                                                 AQ_POP (q, ic);
 2298                                                 splx (s);
 2299                                                 (*linesw[d->tty.t_line].l_rint)
 2300                                                         (ic, &d->tty);
 2301                                                 s = splhigh ();
 2302                                         }
 2303                                 }
 2304                                 d->intr_action &= ~CX_READ;
 2305                         }
 2306                         splx (s);
 2307 
 2308                         s = splhigh ();
 2309                         if (d->intr_action & CX_WRITE) {
 2310                                 if (d->tty.t_line)
 2311                                         (*linesw[d->tty.t_line].l_start) (&d->tty);
 2312                                 else
 2313                                         cx_oproc (&d->tty);
 2314                                 d->intr_action &= ~CX_WRITE;
 2315                         }
 2316                         splx (s);
 2317 
 2318                 }
 2319         }
 2320 }
 2321 
 2322 /*
 2323  * Fill transmitter buffer with data.
 2324  */
 2325 static void cx_oproc (struct tty *tp)
 2326 {
 2327         int s = splhigh (), k;
 2328         drv_t *d = channel [UNIT (tp->t_dev)];
 2329         static u_char buf[DMABUFSZ];
 2330         u_char *p;
 2331         u_short len = 0, sublen = 0;
 2332 
 2333         if (!d) {
 2334                 splx (s);
 2335                 return;
 2336         }
 2337                 
 2338         CX_DEBUG2 (d, ("cx_oproc\n"));
 2339         if (tp->t_cflag & CRTSCTS && (tp->t_state & TS_TBLOCK) && d->chan->rts)
 2340                 cx_set_rts (d->chan, 0);
 2341         else if (tp->t_cflag & CRTSCTS && ! (tp->t_state & TS_TBLOCK) && ! d->chan->rts)
 2342                 cx_set_rts (d->chan, 1);
 2343 
 2344         if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
 2345                 /* Start transmitter. */
 2346                 cx_enable_transmit (d->chan, 1);
 2347 
 2348                 /* Is it busy? */
 2349                 if (! cx_buf_free (d->chan)) {
 2350                         tp->t_state |= TS_BUSY;
 2351                         splx (s);
 2352                         return;
 2353                 }
 2354                 if (tp->t_iflag & IXOFF) {
 2355                         p = (buf + (DMABUFSZ/2));
 2356                         sublen = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2357                         k = sublen;
 2358                         while (k--) {
 2359                                 /* Send XON/XOFF out of band. */
 2360                                 if (*p == tp->t_cc[VSTOP]) {
 2361                                         cx_xflow_ctl (d->chan, 0);
 2362                                         p++;
 2363                                         continue;
 2364                                 }
 2365                                 if (*p == tp->t_cc[VSTART]) {
 2366                                         cx_xflow_ctl (d->chan, 1);
 2367                                         p++;
 2368                                         continue;
 2369                                 }
 2370                                 buf[len] = *p;
 2371                                 len++;
 2372                                 p++;
 2373                         }
 2374                 } else {
 2375                         p = buf;
 2376                         len = q_to_b (&tp->t_outq, p, (DMABUFSZ/2));
 2377                 }
 2378                 if (len) {
 2379                         cx_send_packet (d->chan, buf, len, 0);
 2380                         tp->t_state |= TS_BUSY;
 2381                         d->atimeout = 10;
 2382                         CX_DEBUG2 (d, ("out %d bytes\n", len));
 2383                 }
 2384         }
 2385         ttwwakeup (tp);
 2386         splx (s);
 2387 }
 2388 
 2389 static int cx_param (struct tty *tp, struct termios *t)
 2390 {
 2391         drv_t *d = channel [UNIT (tp->t_dev)];
 2392         int s, bits, parity;
 2393 
 2394         if (!d)
 2395                 return EINVAL;
 2396                 
 2397         s = splhigh ();
 2398         if (t->c_ospeed == 0) {
 2399                 /* Clear DTR and RTS. */
 2400                 cx_set_dtr (d->chan, 0);
 2401                 splx (s);
 2402                 CX_DEBUG2 (d, ("cx_param (hangup)\n"));
 2403                 return 0;
 2404         }
 2405         CX_DEBUG2 (d, ("cx_param\n"));
 2406 
 2407         /* Check requested parameters. */
 2408         if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) {
 2409                 splx (s);
 2410                 return EINVAL;
 2411         }
 2412         if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) {
 2413                 splx (s);
 2414                 return EINVAL;
 2415         }
 2416 
 2417         /* And copy them to tty and channel structures. */
 2418         tp->t_ispeed = t->c_ispeed = tp->t_ospeed = t->c_ospeed;
 2419         tp->t_cflag = t->c_cflag;
 2420 
 2421         /* Set character length and parity mode. */
 2422         switch (t->c_cflag & CSIZE) {
 2423         default:
 2424         case CS8: bits = 8; break;
 2425         case CS7: bits = 7; break;
 2426         case CS6: bits = 6; break;
 2427         case CS5: bits = 5; break;
 2428         }
 2429 
 2430         parity = ((t->c_cflag & PARENB) ? 1 : 0) *
 2431                  (1 + ((t->c_cflag & PARODD) ? 0 : 1));
 2432 
 2433         /* Set current channel number. */
 2434         if (! d->chan->dtr)
 2435                 cx_set_dtr (d->chan, 1);
 2436 
 2437         disc_optim (&d->tty, &d->tty.t_termios);
 2438         cx_set_async_param (d->chan, t->c_ospeed, bits, parity, (t->c_cflag & CSTOPB),
 2439                 !(t->c_cflag & PARENB), (t->c_cflag & CRTSCTS),
 2440                 (t->c_iflag & IXON), (t->c_iflag & IXANY),
 2441                 t->c_cc[VSTART], t->c_cc[VSTOP]);
 2442         splx (s);
 2443         return 0;
 2444 }
 2445 
 2446 #if __FreeBSD_version < 400000
 2447 static struct tty *cx_devtotty (dev_t dev)
 2448 {
 2449         int unit = UNIT (dev);
 2450 
 2451         if (unit == UNIT_CTL || unit >= NCX*NCHAN || ! channel[unit])
 2452                 return 0;
 2453         return &channel[unit]->tty;
 2454 }
 2455 #endif
 2456 
 2457 /*
 2458  * Stop output on a line
 2459  */
 2460 static void cx_stop (struct tty *tp, int flag)
 2461 {
 2462         drv_t *d = channel [UNIT (tp->t_dev)];
 2463         int s;
 2464 
 2465         if (!d)
 2466                 return;
 2467                 
 2468         s = splhigh ();
 2469 
 2470         if (tp->t_state & TS_BUSY) {
 2471                 /* Stop transmitter */
 2472                 CX_DEBUG2 (d, ("cx_stop\n"));
 2473                 cx_transmitter_ctl (d->chan, 0);
 2474         }
 2475         splx (s);
 2476 }
 2477 
 2478 /*
 2479  * Process the (delayed) carrier signal setup.
 2480  */
 2481 static void cx_carrier (void *arg)
 2482 {
 2483         drv_t *d = arg;
 2484         cx_chan_t *c = d->chan;
 2485         int s, cd;
 2486 
 2487         s = splhigh ();
 2488         cd = cx_get_cd (c);
 2489         if (d->cd != cd) {
 2490                 if (cd) {
 2491                         CX_DEBUG (d, ("carrier on\n"));
 2492                         d->cd = 1;
 2493                         splx (s);
 2494                         (*linesw[d->tty.t_line].l_modem) (&d->tty, 1);
 2495                 } else {
 2496                         CX_DEBUG (d, ("carrier loss\n"));
 2497                         d->cd = 0;
 2498                         splx (s);
 2499                         (*linesw[d->tty.t_line].l_modem) (&d->tty, 0);
 2500                 }
 2501         }
 2502 }
 2503 
 2504 /*
 2505  * Modem signal callback function.
 2506  */
 2507 static void cx_modem (cx_chan_t *c)
 2508 {
 2509         drv_t *d = c->sys;
 2510 
 2511         if (!d || c->mode != M_ASYNC)
 2512                 return;
 2513         /* Handle carrier detect/loss. */
 2514         untimeout (cx_carrier, c, d->dcd_timeout_handle);
 2515         /* Carrier changed - delay processing DCD for a while
 2516          * to give both sides some time to initialize. */
 2517         d->dcd_timeout_handle = timeout (cx_carrier, d, hz/2);
 2518 }
 2519 
 2520 #if __FreeBSD_version < 400000
 2521 struct isa_driver cxdriver = { cx_probe, cx_attach, "cx" };
 2522 static struct cdevsw cx_cdevsw = {
 2523         cx_open,        cx_close,       cx_read,        cx_write,
 2524         cx_ioctl,       cx_stop,        noreset,        cx_devtotty,
 2525         ttpoll,         nommap,         NULL,           "cx",
 2526         NULL,           -1,
 2527 };
 2528 #elif  __FreeBSD_version < 500000
 2529 static struct cdevsw cx_cdevsw = {
 2530         cx_open,        cx_close,       cx_read,        cx_write,
 2531         cx_ioctl,       ttypoll,        nommap,         nostrategy,
 2532         "cx",           CDEV_MAJOR,     nodump,         nopsize,
 2533         D_TTY,          -1
 2534 };
 2535 #elif __FreeBSD_version == 500000
 2536 static struct cdevsw cx_cdevsw = {
 2537         cx_open,        cx_close,       cx_read,        cx_write,
 2538         cx_ioctl,       ttypoll,        nommap,         nostrategy,
 2539         "cx",           CDEV_MAJOR,     nodump,         nopsize,
 2540         D_TTY,
 2541         };
 2542 #elif __FreeBSD_version <= 501000 
 2543 static struct cdevsw cx_cdevsw = {
 2544         .d_open     = cx_open,
 2545         .d_close    = cx_close,
 2546         .d_read     = cx_read,
 2547         .d_write    = cx_write,
 2548         .d_ioctl    = cx_ioctl,
 2549         .d_poll     = ttypoll,
 2550         .d_mmap     = nommap,
 2551         .d_strategy = nostrategy,
 2552         .d_name     = "cx",
 2553         .d_maj      = CDEV_MAJOR,
 2554         .d_dump     = nodump,
 2555         .d_flags    = D_TTY,
 2556 };
 2557 #elif __FreeBSD_version < 502103
 2558 static struct cdevsw cx_cdevsw = {
 2559         .d_open     = cx_open,
 2560         .d_close    = cx_close,
 2561         .d_read     = cx_read,
 2562         .d_write    = cx_write,
 2563         .d_ioctl    = cx_ioctl,
 2564         .d_poll     = ttypoll,
 2565         .d_name     = "cx",
 2566         .d_maj      = CDEV_MAJOR,
 2567         .d_flags    = D_TTY,
 2568 };
 2569 #else /* __FreeBSD_version >= 502103 */
 2570 static struct cdevsw cx_cdevsw = {
 2571         .d_version  = D_VERSION,
 2572         .d_open     = cx_open,
 2573         .d_close    = cx_close,
 2574         .d_read     = cx_read,
 2575         .d_write    = cx_write,
 2576         .d_ioctl    = cx_ioctl,
 2577         .d_name     = "cx",
 2578         .d_maj      = CDEV_MAJOR,
 2579         .d_flags    = D_TTY | D_NEEDGIANT,
 2580 };
 2581 #endif
 2582 
 2583 #ifdef NETGRAPH
 2584 #if __FreeBSD_version >= 500000
 2585 static int ng_cx_constructor (node_p node)
 2586 {
 2587         drv_t *d = NG_NODE_PRIVATE (node);
 2588 #else
 2589 static int ng_cx_constructor (node_p *node)
 2590 {
 2591         drv_t *d = (*node)->private;
 2592 #endif
 2593         CX_DEBUG (d, ("Constructor\n"));
 2594         return EINVAL;
 2595 }
 2596 
 2597 static int ng_cx_newhook (node_p node, hook_p hook, const char *name)
 2598 {
 2599         int s;
 2600 #if __FreeBSD_version >= 500000
 2601         drv_t *d = NG_NODE_PRIVATE (node);
 2602 #else
 2603         drv_t *d = node->private;
 2604 #endif
 2605 
 2606         if (d->chan->mode == M_ASYNC)
 2607                 return EINVAL;
 2608 
 2609         /* Attach debug hook */
 2610         if (strcmp (name, NG_CX_HOOK_DEBUG) == 0) {
 2611 #if __FreeBSD_version >= 500000
 2612                 NG_HOOK_SET_PRIVATE (hook, NULL);
 2613 #else
 2614                 hook->private = 0;
 2615 #endif
 2616                 d->debug_hook = hook;
 2617                 return 0;
 2618         }
 2619 
 2620         /* Check for raw hook */
 2621         if (strcmp (name, NG_CX_HOOK_RAW) != 0)
 2622                 return EINVAL;
 2623 
 2624 #if __FreeBSD_version >= 500000
 2625         NG_HOOK_SET_PRIVATE (hook, d);
 2626 #else
 2627         hook->private = d;
 2628 #endif
 2629         d->hook = hook;
 2630         s = splhigh ();
 2631         cx_up (d);
 2632         splx (s);
 2633         return 0;
 2634 }
 2635 
 2636 static int print_modems (char *s, cx_chan_t *c, int need_header)
 2637 {
 2638         int status = cx_modem_status (c->sys);
 2639         int length = 0;
 2640 
 2641         if (need_header)
 2642                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
 2643         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
 2644                 status & TIOCM_LE  ? "On" : "-",
 2645                 status & TIOCM_DTR ? "On" : "-",
 2646                 status & TIOCM_DSR ? "On" : "-",
 2647                 status & TIOCM_RTS ? "On" : "-",
 2648                 status & TIOCM_CTS ? "On" : "-",
 2649                 status & TIOCM_CD  ? "On" : "-");
 2650         return length;
 2651 }
 2652 
 2653 static int print_stats (char *s, cx_chan_t *c, int need_header)
 2654 {
 2655         int length = 0;
 2656 
 2657         if (need_header)
 2658                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
 2659         length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
 2660                 c->rintr, c->tintr, c->mintr, c->ibytes, c->ipkts,
 2661                 c->ierrs, c->obytes, c->opkts, c->oerrs);
 2662         return length;
 2663 }
 2664 
 2665 static int print_chan (char *s, cx_chan_t *c)
 2666 {
 2667         drv_t *d = c->sys;
 2668         int length = 0;
 2669 
 2670         length += sprintf (s + length, "cx%d", c->board->num * NCHAN + c->num);
 2671         if (d->chan->debug)
 2672                 length += sprintf (s + length, " debug=%d", d->chan->debug);
 2673 
 2674         if (cx_get_baud (c))
 2675                 length += sprintf (s + length, " %ld", cx_get_baud (c));
 2676         else
 2677                 length += sprintf (s + length, " extclock");
 2678 
 2679         if (c->mode == M_HDLC) {
 2680                 length += sprintf (s + length, " dpll=%s", cx_get_dpll (c) ? "on" : "off");
 2681                 length += sprintf (s + length, " nrzi=%s", cx_get_nrzi (c) ? "on" : "off");
 2682         }
 2683 
 2684         length += sprintf (s + length, " loop=%s", cx_get_loop (c) ? "on\n" : "off\n");
 2685         return length;
 2686 }
 2687 
 2688 #if __FreeBSD_version >= 500000
 2689 static int ng_cx_rcvmsg (node_p node, item_p item, hook_p lasthook)
 2690 {
 2691         drv_t *d = NG_NODE_PRIVATE (node);
 2692         struct ng_mesg *msg;
 2693 #else
 2694 static int ng_cx_rcvmsg (node_p node, struct ng_mesg *msg,
 2695         const char *retaddr, struct ng_mesg **rptr)
 2696 {
 2697         drv_t *d = node->private;
 2698 #endif
 2699         struct ng_mesg *resp = NULL;
 2700         int error = 0;
 2701 
 2702         if (!d)
 2703                 return EINVAL;
 2704                 
 2705         CX_DEBUG (d, ("Rcvmsg\n"));
 2706 #if __FreeBSD_version >= 500000
 2707         NGI_GET_MSG (item, msg);
 2708 #endif
 2709         switch (msg->header.typecookie) {
 2710         default:
 2711                 error = EINVAL;
 2712                 break;
 2713 
 2714         case NGM_CX_COOKIE:
 2715                 printf ("Don't forget to implement\n");
 2716                 error = EINVAL;
 2717                 break;
 2718 
 2719         case NGM_GENERIC_COOKIE:
 2720                 switch (msg->header.cmd) {
 2721                 default:
 2722                         error = EINVAL;
 2723                         break;
 2724 
 2725                 case NGM_TEXT_STATUS: {
 2726                         char *s;
 2727                         int l = 0;
 2728                         int dl = sizeof (struct ng_mesg) + 730;
 2729 
 2730 #if __FreeBSD_version >= 500000 
 2731                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
 2732                         if (! resp) {
 2733                                 error = ENOMEM;
 2734                                 break;
 2735                         }
 2736 #else
 2737                         MALLOC (resp, struct ng_mesg *, dl,
 2738                                 M_NETGRAPH, M_NOWAIT);
 2739                         if (! resp) {
 2740                                 error = ENOMEM;
 2741                                 break;
 2742                         }
 2743 #endif
 2744                         bzero (resp, dl);
 2745                         s = (resp)->data;
 2746                         l += print_chan (s + l, d->chan);
 2747                         l += print_stats (s + l, d->chan, 1);
 2748                         l += print_modems (s + l, d->chan, 1);
 2749 #if __FreeBSD_version < 500000
 2750                         (resp)->header.version = NG_VERSION;
 2751                         (resp)->header.arglen = strlen (s) + 1;
 2752                         (resp)->header.token = msg->header.token;
 2753                         (resp)->header.typecookie = NGM_CX_COOKIE;
 2754                         (resp)->header.cmd = msg->header.cmd;
 2755 #endif
 2756                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
 2757                         }
 2758                         break;
 2759                 }
 2760                 break;
 2761         }
 2762 #if __FreeBSD_version >= 500000
 2763         NG_RESPOND_MSG (error, node, item, resp);
 2764         NG_FREE_MSG (msg);
 2765 #else
 2766         *rptr = resp;
 2767         FREE (msg, M_NETGRAPH);
 2768 #endif
 2769         return error;
 2770 }
 2771 
 2772 #if __FreeBSD_version >= 500000
 2773 static int ng_cx_rcvdata (hook_p hook, item_p item)
 2774 {
 2775         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
 2776         struct mbuf *m;
 2777         meta_p meta;
 2778 #else
 2779 static int ng_cx_rcvdata (hook_p hook, struct mbuf *m, meta_p meta)
 2780 {
 2781         drv_t *d = hook->node->private;
 2782 #endif
 2783         struct ifqueue *q;
 2784         int s;
 2785 
 2786 #if __FreeBSD_version >= 500000
 2787         NGI_GET_M (item, m);
 2788         NGI_GET_META (item, meta);
 2789         NG_FREE_ITEM (item);
 2790         if (! NG_HOOK_PRIVATE (hook) || ! d) {
 2791                 NG_FREE_M (m);
 2792                 NG_FREE_META (meta);
 2793 #else
 2794         if (! hook->private || ! d) {
 2795                 NG_FREE_DATA (m,meta);
 2796 #endif
 2797                 return ENETDOWN;
 2798         }
 2799         q = (meta && meta->priority > 0) ? &d->hi_queue : &d->lo_queue;
 2800         s = splhigh ();
 2801 #if __FreeBSD_version >= 500000
 2802         IF_LOCK (q);
 2803         if (_IF_QFULL (q)) {
 2804                 _IF_DROP (q);
 2805                 IF_UNLOCK (q);
 2806                 splx (s);
 2807                 NG_FREE_M (m);
 2808                 NG_FREE_META (meta);
 2809                 return ENOBUFS;
 2810         }
 2811         _IF_ENQUEUE (q, m);
 2812         IF_UNLOCK (q);
 2813 #else
 2814         if (IF_QFULL (q)) {
 2815                 IF_DROP (q);
 2816                 splx (s);
 2817                 NG_FREE_DATA (m, meta);
 2818                 return ENOBUFS;
 2819         }
 2820         IF_ENQUEUE (q, m);
 2821 #endif
 2822         cx_start (d);
 2823         splx (s);
 2824         return 0;
 2825 }
 2826 
 2827 static int ng_cx_rmnode (node_p node)
 2828 {
 2829 #if __FreeBSD_version >= 500000
 2830         drv_t *d = NG_NODE_PRIVATE (node);
 2831 
 2832         CX_DEBUG (d, ("Rmnode\n"));
 2833         if (d && d->running) {
 2834                 int s = splhigh ();
 2835                 cx_down (d);
 2836                 splx (s);
 2837         }
 2838 #ifdef  KLD_MODULE
 2839         if (node->nd_flags & NG_REALLY_DIE) {
 2840                 NG_NODE_SET_PRIVATE (node, NULL);
 2841                 NG_NODE_UNREF (node);
 2842         }
 2843         node->nd_flags &= ~NG_INVALID;
 2844 #endif
 2845 #else /* __FreeBSD_version < 500000 */
 2846         drv_t *d = node->private;
 2847         int s;
 2848 
 2849         s = splhigh ();
 2850         cx_down (d);
 2851         splx (s);
 2852         node->flags |= NG_INVALID;
 2853         ng_cutlinks (node);
 2854 #ifdef  KLD_MODULE
 2855         ng_unname (node);
 2856         ng_unref (node);
 2857 #else
 2858         node->flags &= ~NG_INVALID;
 2859 #endif
 2860 #endif
 2861         return 0;
 2862 }
 2863 
 2864 static void ng_cx_watchdog (void *arg)
 2865 {
 2866         drv_t *d = arg;
 2867 
 2868         if (d->timeout == 1)
 2869                 cx_watchdog (d);
 2870         if (d->timeout)
 2871                 d->timeout--;
 2872         d->timeout_handle = timeout (ng_cx_watchdog, d, hz);
 2873 }
 2874 
 2875 static int ng_cx_connect (hook_p hook)
 2876 {
 2877 #if __FreeBSD_version >= 500000
 2878         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2879 #else
 2880         drv_t *d = hook->node->private;
 2881 #endif
 2882 
 2883         d->timeout_handle = timeout (ng_cx_watchdog, d, hz);
 2884         return 0;
 2885 }
 2886 
 2887 static int ng_cx_disconnect (hook_p hook)
 2888 {
 2889 #if __FreeBSD_version >= 500000
 2890         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
 2891 #else
 2892         drv_t *d = hook->node->private;
 2893 #endif
 2894         int s;
 2895 
 2896         s = splhigh ();
 2897 #if __FreeBSD_version >= 500000
 2898         if (NG_HOOK_PRIVATE (hook))
 2899 #else
 2900         if (hook->private)
 2901 #endif
 2902                 cx_down (d);
 2903         splx (s);
 2904         untimeout (ng_cx_watchdog, d, d->timeout_handle);
 2905         return 0;
 2906 }
 2907 #endif /*NETGRAPH*/
 2908 
 2909 #ifdef KLD_MODULE
 2910 #if __FreeBSD_version < 400000
 2911 /*
 2912  * Function called when loading the driver.
 2913  */
 2914 static int cx_load (void)
 2915 {
 2916         int i;
 2917 
 2918         for (i=0;i<NCX; ++i) {
 2919                 struct isa_device id = {-1, &cxdriver, -1, 0, -1, 0, 0, (inthand2_t *)cx_intr, i, 0, 0, 0, 0 ,0 ,1 ,0 ,0};
 2920 
 2921                 disable_intr();
 2922                 if (!cx_probe (&id)) {
 2923                         enable_intr();
 2924                         break;
 2925                 }
 2926                 cx_attach (&id);
 2927                 register_intr ((adapter [i])->irq, 0, 0, (inthand2_t*) cx_intr,
 2928                                 &net_imask, id.id_unit);
 2929                 enable_intr();
 2930         }
 2931         if (!i) {
 2932                 /* Deactivate the timeout routine. And soft interrupt*/
 2933                 untimeout (cx_timeout, 0, timeout_handle);
 2934                 unregister_swi (SWI_TTY, cx_softintr);
 2935                 return ENXIO;
 2936         }
 2937         return 0;
 2938 }
 2939 
 2940 /*
 2941  * Function called when unloading the driver.
 2942  */
 2943 static int cx_unload (void)
 2944 {
 2945         int i, s;
 2946 
 2947         /* Check if the device is busy (open). */
 2948         for (i=0; i<NCX*NCHAN; ++i) {
 2949                 drv_t *d = channel[i];
 2950                 cx_chan_t *c;
 2951 
 2952                 if (!d || (c=d->chan)->type == T_NONE)
 2953                         continue;
 2954                 if (d->lock)
 2955                         return EBUSY;
 2956                 if (c->mode == M_ASYNC && (d->tty.t_state & TS_ISOPEN) &&
 2957                         (d->open_dev|0x2))
 2958                                 return EBUSY;
 2959                 if (d->running)
 2960                                 return EBUSY;
 2961 
 2962         }
 2963 
 2964         s = splhigh ();
 2965 
 2966         /* Deactivate the timeout routine. And soft interrupt*/
 2967         for (i=0; i<NCX; ++i) {
 2968                 cx_board_t *b = adapter [i];
 2969 
 2970                 if (!b || ! b->port)
 2971                         continue;
 2972                 untimeout (cx_timeout, 0, timeout_handle);
 2973                 unregister_swi (SWI_TTY, cx_softintr);
 2974                 break;
 2975         }
 2976 
 2977         for (i=0; i<NCX*NCHAN; ++i) {
 2978                 drv_t *d = channel[i];
 2979                 cx_chan_t *c;
 2980 
 2981                 if (!d || (c=d->chan)->type == T_NONE)
 2982                         continue;
 2983 
 2984                 if (d->dtr_timeout_handle.callout)
 2985                         untimeout (cx_dtrwakeup, d, d->dtr_timeout_handle);
 2986                 if (d->dcd_timeout_handle.callout)
 2987                         untimeout (cx_carrier, c, d->dcd_timeout_handle);
 2988         }
 2989 
 2990         /* Close all active boards. */
 2991         for (i=0; i<NCX; ++i) {
 2992                 cx_board_t *b = adapter [i];
 2993 
 2994                 if (!b || ! b->port)
 2995                         continue;
 2996 
 2997                 cx_close_board (b);
 2998         }
 2999 
 3000         for (i=0; i<NCX; ++i) {
 3001                 cx_board_t *b = adapter [i];
 3002 
 3003                 if (!b || ! b->port)
 3004                         continue;
 3005 
 3006                 if (led_timo[i].callout)
 3007                         untimeout (cx_led_off, b, led_timo[i]);
 3008         }
 3009 
 3010         /* OK to unload the driver, unregister the interrupt first. */
 3011         for (i=0; i<NCX; ++i) {
 3012                 cx_board_t *b = adapter [i];
 3013 
 3014                 if (!b || ! b->port)
 3015                         continue;
 3016                 /* Disable the interrupt request. */
 3017                 disable_intr();
 3018                 unregister_intr (b->irq, (inthand2_t *)cx_intr);
 3019                 isa_dma_release (b->dma);
 3020                 enable_intr();
 3021         }
 3022         splx (s);
 3023 
 3024         s = splhigh ();
 3025         /* Detach the interfaces, free buffer memory. */
 3026         for (i=0; i<NCX*NCHAN; ++i) {
 3027                 drv_t *d = channel[i];
 3028                 cx_chan_t *c;
 3029 
 3030                 if (!d || (c=d->chan)->type == T_NONE)
 3031                         continue;
 3032 
 3033 #ifndef NETGRAPH
 3034 #if NBPFILTER > 0
 3035                 /* Detach from the packet filter list of interfaces. */
 3036                 {
 3037                         struct bpf_if *q, **b = &bpf_iflist;
 3038 
 3039                         while ((q = *b)) {
 3040                                 if (q->bif_ifp == d->pp.pp_if) {
 3041                                         *b = q->bif_next;
 3042                                         free (q, M_DEVBUF);
 3043                                 }
 3044                                 b = &(q->bif_next);
 3045                         }
 3046                 }
 3047 #endif /* NBPFILTER */
 3048                 /* Detach from the sync PPP list. */
 3049                 sppp_detach (&d->pp.pp_if);
 3050 
 3051                 /* Detach from the system list of interfaces. */
 3052                 {
 3053                         struct ifaddr *ifa;
 3054                         TAILQ_FOREACH (ifa, &d->pp.pp_if.if_addrhead, ifa_link) {
 3055                                 TAILQ_REMOVE (&d->pp.pp_if.if_addrhead, ifa, ifa_link);
 3056                                 free (ifa, M_IFADDR);
 3057                         }
 3058                         TAILQ_REMOVE (&ifnet, &d->pp.pp_if, if_link);
 3059                 }
 3060 #endif /* !NETGRAPH */
 3061                 /* Deallocate buffers. */
 3062 /*              free (d, M_DEVBUF);*/
 3063         }
 3064 
 3065         for (i=0; i<NCX; ++i) {
 3066                 cx_board_t *b = adapter [i];
 3067                 if (!b)
 3068                         continue;
 3069                 adapter [b->num] = 0;
 3070                 free (b, M_DEVBUF);
 3071         }
 3072 
 3073         splx (s);
 3074 
 3075         return 0;
 3076 }
 3077 
 3078 #define devsw(a)        cdevsw[major((a))]
 3079 #endif /* __FreeBSD_version < 400000 */
 3080 #endif /* KLD_MODULE */
 3081 
 3082 #if __FreeBSD_version < 400000
 3083 #ifdef KLD_MODULE
 3084 static int cx_modevent (module_t mod, int type, void *unused)
 3085 {
 3086         dev_t dev;
 3087         int result;
 3088         static int load_count = 0;
 3089 
 3090         dev = makedev (CDEV_MAJOR, 0);
 3091         switch (type) {
 3092         case MOD_LOAD:
 3093                 if (devsw(dev))
 3094                         return (ENXIO);
 3095                 load_count ++;
 3096                 cdevsw_add (&dev, &cx_cdevsw, NULL);
 3097                 timeout_handle = timeout (cx_timeout, 0, hz*5);
 3098 
 3099                 /* Software interrupt. */
 3100                 register_swi (SWI_TTY, cx_softintr);
 3101 
 3102                 result = cx_load ();
 3103                 return result;
 3104         case MOD_UNLOAD:
 3105                 result = cx_unload ();
 3106                 if (result)
 3107                         return result;
 3108                 if (devsw(dev)&&!(load_count-1)) {
 3109                 cdevsw_add (&dev, NULL, NULL);
 3110                 }
 3111                 load_count --;
 3112                 return result;
 3113         case MOD_SHUTDOWN:
 3114                 break;
 3115         }
 3116         return 0;
 3117 }
 3118 #endif /* KLD_MODULE */
 3119 #else /* __FreeBSD_version >= 400000 */
 3120 static int cx_modevent (module_t mod, int type, void *unused)
 3121 {
 3122         dev_t dev;
 3123         static int load_count = 0;
 3124         struct cdevsw *cdsw;
 3125 
 3126 #if __FreeBSD_version >= 502103
 3127         dev = udev2dev (makeudev(CDEV_MAJOR, 0));
 3128 #else
 3129         dev = makedev (CDEV_MAJOR, 0);
 3130 #endif
 3131         switch (type) {
 3132         case MOD_LOAD:
 3133                 if (dev != NODEV &&
 3134                     (cdsw = devsw (dev)) &&
 3135                     cdsw->d_maj == CDEV_MAJOR) {
 3136                         printf ("Sigma driver is already in system\n");
 3137                         return (EEXIST);
 3138                 }
 3139 #if __FreeBSD_version >= 500000 && defined NETGRAPH
 3140                 if (ng_newtype (&typestruct))
 3141                         printf ("Failed to register ng_cx\n");
 3142 #endif
 3143                 ++load_count;
 3144 #if __FreeBSD_version <= 500000
 3145                 cdevsw_add (&cx_cdevsw);
 3146 #endif
 3147                 timeout_handle = timeout (cx_timeout, 0, hz*5);
 3148                 /* Software interrupt. */
 3149 #if __FreeBSD_version < 500000
 3150                 register_swi (SWI_TTY, cx_softintr);
 3151 #else
 3152                 swi_add(&tty_ithd, "tty:cx", cx_softintr, NULL, SWI_TTY, 0,
 3153                     &cx_fast_ih);
 3154 #endif
 3155                 break;
 3156         case MOD_UNLOAD:
 3157                 if (load_count == 1) {
 3158                         printf ("Removing device entry for Sigma\n");
 3159 #if __FreeBSD_version <= 500000
 3160                         cdevsw_remove (&cx_cdevsw);
 3161 #endif
 3162 #if __FreeBSD_version >= 500000 && defined NETGRAPH
 3163                         ng_rmtype (&typestruct);
 3164 #endif                  
 3165                 }
 3166                 if (timeout_handle.callout)
 3167                         untimeout (cx_timeout, 0, timeout_handle);
 3168 #if __FreeBSD_version >= 500000
 3169                 ithread_remove_handler (cx_fast_ih);
 3170 #else
 3171                 unregister_swi (SWI_TTY, cx_softintr);
 3172 #endif
 3173                 --load_count;
 3174                 break;
 3175         case MOD_SHUTDOWN:
 3176                 break;
 3177         }
 3178         return 0;
 3179 }
 3180 #endif  /* __FreeBSD_version >= 400000 */
 3181 
 3182 #ifdef NETGRAPH
 3183 static struct ng_type typestruct = {
 3184 #if __FreeBSD_version >= 500000
 3185         NG_ABI_VERSION,
 3186 #else
 3187         NG_VERSION,
 3188 #endif
 3189         NG_CX_NODE_TYPE,
 3190 #if __FreeBSD_version < 500000 && defined KLD_MODULE
 3191         cx_modevent,
 3192 #else
 3193         NULL,
 3194 #endif
 3195         ng_cx_constructor,
 3196         ng_cx_rcvmsg,
 3197         ng_cx_rmnode,
 3198         ng_cx_newhook,
 3199         NULL,
 3200         ng_cx_connect,
 3201         ng_cx_rcvdata,
 3202 #if __FreeBSD_version < 500000
 3203         NULL,
 3204 #endif
 3205         ng_cx_disconnect
 3206 };
 3207 
 3208 #if __FreeBSD_version < 400000
 3209 NETGRAPH_INIT_ORDERED (cx, &typestruct, SI_SUB_DRIVERS,\
 3210         SI_ORDER_MIDDLE + CDEV_MAJOR);
 3211 #endif
 3212 #endif /*NETGRAPH*/
 3213 
 3214 #if __FreeBSD_version >= 500000
 3215 #ifdef NETGRAPH
 3216 MODULE_DEPEND (ng_cx, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
 3217 #else
 3218 MODULE_DEPEND (isa_cx, sppp, 1, 1, 1);
 3219 #endif
 3220 #ifdef KLD_MODULE
 3221 DRIVER_MODULE (cxmod, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL);
 3222 #else
 3223 DRIVER_MODULE (cx, isa, cx_isa_driver, cx_devclass, cx_modevent, NULL);
 3224 #endif
 3225 #elif __FreeBSD_version >= 400000
 3226 #ifdef NETGRAPH
 3227 DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, ng_mod_event, &typestruct);
 3228 #else
 3229 DRIVER_MODULE(cx, isa, cx_isa_driver, cx_devclass, cx_modevent, 0);
 3230 #endif
 3231 #else /* __FreeBSD_version < 400000 */
 3232 #ifdef KLD_MODULE
 3233 #ifndef NETGRAPH
 3234 static moduledata_t cxmod = { "cx", cx_modevent, NULL};
 3235 DECLARE_MODULE (cx, cxmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR);
 3236 #endif
 3237 #else /* KLD_MODULE */
 3238 
 3239 /*
 3240  * Now for some driver initialisation.
 3241  * Occurs ONCE during boot (very early).
 3242  * This is if we are NOT a loadable module.
 3243  */
 3244 static void cx_drvinit (void *unused)
 3245 {
 3246 #if __FreeBSD_version < 400000
 3247         dev_t dev;
 3248 
 3249         dev = makedev (CDEV_MAJOR, 0);
 3250         cdevsw_add (&dev, &cx_cdevsw, NULL);
 3251 #else
 3252         cdevsw_add (&cx_cdevsw);
 3253 #endif
 3254 
 3255         /* Activate the timeout routine. */
 3256         timeout_handle = timeout (cx_timeout, 0, hz*5);
 3257 
 3258         /* Software interrupt. */
 3259         register_swi (SWI_TTY, cx_softintr);
 3260 #ifdef NETGRAPH
 3261 #if 0
 3262         /* Register our node type in netgraph */
 3263         if (ng_newtype (&typestruct))
 3264                 printf ("Failed to register ng_cx\n");
 3265 #endif
 3266 #endif
 3267 }
 3268 
 3269 SYSINIT (cxdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, cx_drvinit, 0)
 3270 
 3271 #endif /* KLD_MODULE */
 3272 #endif /*  __FreeBSD_version < 400000 */
 3273 #endif /* NCX */

Cache object: 1e7102683268b6b391827e8e59f6b625


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