]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ctau/if_ct.c
Remove dependency on deprecated if_watchdog ABI.
[FreeBSD/FreeBSD.git] / sys / dev / ctau / if_ct.c
1 /*-
2  * Cronyx-Tau 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  * Author: Roman Kurakin, <rik@cronyx.ru>
12  *
13  * This software is distributed with NO WARRANTIES, not even the implied
14  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * Authors grant any other persons or organisations a permission to use,
17  * modify and redistribute this software in source and binary forms,
18  * as long as this message is kept with the software, all derivative
19  * works or modified versions.
20  *
21  * Cronyx Id: if_ct.c,v 1.1.2.31 2004/06/23 17:09:13 rik Exp $
22  */
23
24 #include <sys/cdefs.h>
25 __FBSDID("$FreeBSD$");
26
27 #include <sys/param.h>
28 #include <sys/proc.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/module.h>
32 #include <sys/mbuf.h>
33 #include <sys/sockio.h>
34 #include <sys/malloc.h>
35 #include <sys/priv.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
38 #include <sys/conf.h>
39 #include <sys/errno.h>
40 #include <sys/tty.h>
41 #include <sys/bus.h>
42 #include <machine/bus.h>
43 #include <sys/rman.h>
44 #include <isa/isavar.h>
45 #include <sys/interrupt.h>
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <net/if.h>
49 #include <machine/cpufunc.h>
50 #include <machine/cserial.h>
51 #include <machine/resource.h>
52 #include <dev/cx/machdep.h>
53 #include <dev/ctau/ctddk.h>
54 #include <dev/cx/cronyxfw.h>
55 #include "opt_ng_cronyx.h"
56 #ifdef NETGRAPH_CRONYX
57 #   include "opt_netgraph.h"
58 #   include <netgraph/ng_message.h>
59 #   include <netgraph/netgraph.h>
60 #   include <dev/ctau/ng_ct.h>
61 #else
62 #   include <net/if_types.h>
63 #   include <net/if_sppp.h>
64 #   define PP_CISCO IFF_LINK2
65 #   include <net/bpf.h>
66 #endif
67  
68 #define NCTAU 1
69
70 /* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
71 #ifndef PP_FR
72 #define PP_FR 0
73 #endif
74
75 #define CT_DEBUG(d,s)   ({if (d->chan->debug) {\
76                                 printf ("%s: ", d->name); printf s;}})
77 #define CT_DEBUG2(d,s)  ({if (d->chan->debug>1) {\
78                                 printf ("%s: ", d->name); printf s;}})
79
80 #define CT_LOCK_NAME    "ctX"
81
82 static  int     ct_mpsafenet = 1;
83 TUNABLE_INT("debug.ctau.mpsafenet", &ct_mpsafenet);
84 SYSCTL_NODE(_debug, OID_AUTO, ctau, CTLFLAG_RD, 0, "Cronyx Tau-ISA Adapters");
85 SYSCTL_INT(_debug_ctau, OID_AUTO, mpsafenet, CTLFLAG_RD, &ct_mpsafenet, 0,
86         "Enable/disable MPSAFE network support for Cronyx Tau-ISA Adapters");
87
88 #define CT_LOCK(_bd)            do { \
89                                     if (ct_mpsafenet) \
90                                         mtx_lock (&(_bd)->ct_mtx); \
91                                 } while (0)
92 #define CT_UNLOCK(_bd)          do { \
93                                     if (ct_mpsafenet) \
94                                         mtx_unlock (&(_bd)->ct_mtx); \
95                                 } while (0)
96 #define CT_LOCK_ASSERT(_bd)     do { \
97                                     if (ct_mpsafenet) \
98                                         mtx_assert (&(_bd)->ct_mtx, MA_OWNED); \
99                                 } while (0)
100
101 static void ct_identify         __P((driver_t *, device_t));
102 static int ct_probe             __P((device_t));
103 static int ct_attach            __P((device_t));
104 static int ct_detach            __P((device_t));
105
106 static device_method_t ct_isa_methods [] = {
107         DEVMETHOD(device_identify,      ct_identify),
108         DEVMETHOD(device_probe,         ct_probe),
109         DEVMETHOD(device_attach,        ct_attach),
110         DEVMETHOD(device_detach,        ct_detach),
111         {0, 0}
112 };
113
114 typedef struct _ct_dma_mem_t {
115         unsigned long   phys;
116         void            *virt;
117         size_t          size;
118         bus_dma_tag_t   dmat;
119         bus_dmamap_t    mapp;
120 } ct_dma_mem_t;
121
122 typedef struct _drv_t {
123         char name [8];
124         ct_chan_t *chan;
125         ct_board_t *board;
126         struct _bdrv_t *bd;
127         ct_dma_mem_t dmamem;
128         int running;
129 #ifdef NETGRAPH
130         char    nodename [NG_NODELEN+1];
131         hook_p  hook;
132         hook_p  debug_hook;
133         node_p  node;
134         struct  ifqueue queue;
135         struct  ifqueue hi_queue;
136         short   timeout;
137         struct  callout timeout_handle;
138 #else
139         struct  ifqueue queue;
140         struct  ifnet *ifp;
141 #endif
142         struct  cdev *devt;
143 } drv_t;
144
145 typedef struct _bdrv_t {
146         ct_board_t      *board;
147         struct resource *base_res;
148         struct resource *drq_res;
149         struct resource *irq_res;
150         int             base_rid;
151         int             drq_rid;
152         int             irq_rid;
153         void            *intrhand;
154         drv_t           channel [NCHAN];
155         struct mtx      ct_mtx;
156 } bdrv_t;
157
158 static driver_t ct_isa_driver = {
159         "ct",
160         ct_isa_methods,
161         sizeof (bdrv_t),
162 };
163
164 static devclass_t ct_devclass;
165
166 static void ct_receive (ct_chan_t *c, char *data, int len);
167 static void ct_transmit (ct_chan_t *c, void *attachment, int len);
168 static void ct_error (ct_chan_t *c, int data);
169 static void ct_up (drv_t *d);
170 static void ct_start (drv_t *d);
171 static void ct_down (drv_t *d);
172 static void ct_watchdog (drv_t *d);
173 #ifdef NETGRAPH
174 extern struct ng_type typestruct;
175 #else
176 static void ct_ifstart (struct ifnet *ifp);
177 static void ct_tlf (struct sppp *sp);
178 static void ct_tls (struct sppp *sp);
179 static void ct_ifwatchdog (struct ifnet *ifp);
180 static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
181 static void ct_initialize (void *softc);
182 #endif
183
184 static ct_board_t *adapter [NCTAU];
185 static drv_t *channel [NCTAU*NCHAN];
186 static struct callout led_timo [NCTAU];
187 static struct callout timeout_handle;
188
189 static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td);
190 static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td);
191 static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
192 static struct cdevsw ct_cdevsw = {
193         .d_version  = D_VERSION,
194         .d_open     = ct_open,
195         .d_close    = ct_close,
196         .d_ioctl    = ct_ioctl,
197         .d_name     = "ct",
198         .d_flags    = D_NEEDGIANT,
199 };
200
201 /*
202  * Print the mbuf chain, for debug purposes only.
203  */
204 static void printmbuf (struct mbuf *m)
205 {
206         printf ("mbuf:");
207         for (; m; m=m->m_next) {
208                 if (m->m_flags & M_PKTHDR)
209                         printf (" HDR %d:", m->m_pkthdr.len);
210                 if (m->m_flags & M_EXT)
211                         printf (" EXT:");
212                 printf (" %d", m->m_len);
213         }
214         printf ("\n");
215 }
216
217 /*
218  * Make an mbuf from data.
219  */
220 static struct mbuf *makembuf (void *buf, u_int len)
221 {
222         struct mbuf *m;
223
224         MGETHDR (m, M_DONTWAIT, MT_DATA);
225         if (! m)
226                 return 0;
227         MCLGET (m, M_DONTWAIT);
228         if (! (m->m_flags & M_EXT)) {
229                 m_freem (m);
230                 return 0;
231         }
232         m->m_pkthdr.len = m->m_len = len;
233         bcopy (buf, mtod (m, caddr_t), len);
234         return m;
235 }
236
237 static void ct_timeout (void *arg)
238 {
239         drv_t *d;
240         int s, i, k;
241
242         for (i = 0; i < NCTAU; ++i) {
243                 if (adapter[i] == NULL)
244                         continue;
245                 for (k = 0; k < NCHAN; k++) {
246                         d = channel[i * NCHAN + k];
247                         if (! d)
248                                 continue;
249                         if (d->chan->mode != M_G703)
250                                 continue;
251                         s = splimp ();
252                         CT_LOCK ((bdrv_t *)d->bd);
253                         ct_g703_timer (d->chan);
254                         CT_UNLOCK ((bdrv_t *)d->bd);
255                         splx (s);
256                 }
257         }
258         
259         callout_reset (&timeout_handle, hz, ct_timeout, 0);
260 }
261
262 static void ct_led_off (void *arg)
263 {
264         ct_board_t *b = arg;
265         bdrv_t *bd = ((drv_t *)b->chan->sys)->bd;
266         int s = splimp ();
267
268         CT_LOCK (bd);
269         ct_led (b, 0);
270         CT_UNLOCK (bd);
271         splx (s);
272 }
273
274 /*
275  * Activate interupt handler from DDK.
276  */
277 static void ct_intr (void *arg)
278 {
279         bdrv_t *bd = arg;
280         ct_board_t *b = bd->board;
281 #ifndef NETGRAPH
282         int i;
283 #endif
284         int s = splimp ();
285
286         CT_LOCK (bd);
287         /* Turn LED on. */
288         ct_led (b, 1);
289
290         ct_int_handler (b);
291
292         /* Turn LED off 50 msec later. */
293         callout_reset (&led_timo[b->num], hz/20, ct_led_off, b);
294         CT_UNLOCK (bd);
295         splx (s);
296
297 #ifndef NETGRAPH
298         /* Pass packets in a lock-free state */
299         for (i = 0; i < NCHAN && b->chan[i].type; i++) {
300                 drv_t *d = b->chan[i].sys;
301                 struct mbuf *m;
302                 if (!d || !d->running)
303                         continue;
304                 while (_IF_QLEN(&d->queue)) {
305                         IF_DEQUEUE (&d->queue,m);
306                         if (!m)
307                                 continue;
308                         sppp_input (d->ifp, m); 
309                 }
310         }
311 #endif
312 }
313
314 static int probe_irq (ct_board_t *b, int irq)
315 {
316         int mask, busy, cnt;
317
318         /* Clear pending irq, if any. */
319         ct_probe_irq (b, -irq);
320         DELAY (100);
321         for (cnt=0; cnt<5; ++cnt) {
322                 /* Get the mask of pending irqs, assuming they are busy.
323                  * Activate the adapter on given irq. */
324                 busy = ct_probe_irq (b, irq);
325                 DELAY (1000);
326
327                 /* Get the mask of active irqs.
328                  * Deactivate our irq. */
329                 mask = ct_probe_irq (b, -irq);
330                 DELAY (100);
331                 if ((mask & ~busy) == 1 << irq) {
332                         ct_probe_irq (b, 0);
333                         /* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
334                                 b->num, irq, mask, busy); */
335                         return 1;
336                 }
337         }
338         /* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
339                 b->num, irq, mask, busy); */
340         ct_probe_irq (b, 0);
341         return 0;
342 }
343
344 static  short porttab [] = {
345                 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
346                 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
347         };
348 static  char dmatab [] = { 7, 6, 5, 0 };
349 static  char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
350
351 static int ct_is_free_res (device_t dev, int rid, int type, u_long start,
352         u_long end, u_long count)
353 {
354         struct resource *res;
355         
356         if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
357             RF_ALLOCATED)))
358                 return 0;
359                 
360         bus_release_resource (dev, type, rid, res);
361         
362         return 1;
363 }
364
365 static void ct_identify (driver_t *driver, device_t dev)
366 {
367         u_long iobase, rescount;
368         int devcount;
369         device_t *devices;
370         device_t child;
371         devclass_t my_devclass;
372         int i, k;
373
374         if ((my_devclass = devclass_find ("ct")) == NULL)
375                 return;
376
377         devclass_get_devices (my_devclass, &devices, &devcount);
378
379         if (devcount == 0) {
380                 /* We should find all devices by our self. We could alter other
381                  * devices, but we don't have a choise
382                  */
383                 for (i = 0; (iobase = porttab [i]) != 0; i++) {
384                         if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
385                             iobase, iobase + NPORT, NPORT))
386                                 continue;
387                         if (ct_probe_board (iobase, -1, -1) == 0)
388                                 continue;
389                         
390                         devcount++;
391                         child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct",
392                             -1);
393
394                         if (child == NULL)
395                                 return;
396
397                         device_set_desc_copy (child, "Cronyx Tau-ISA");
398                         device_set_driver (child, driver);
399                         bus_set_resource (child, SYS_RES_IOPORT, 0,
400                             iobase, NPORT);
401
402                         if (devcount >= NCTAU)
403                                 break;
404                 }
405         } else {
406                 static  short porttab [] = {
407                         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
408                         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
409                 };
410                 /* Lets check user choise.
411                  */
412                 for (k = 0; k < devcount; k++) {
413                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
414                             &iobase, &rescount) != 0)
415                                 continue;
416
417                         for (i = 0; porttab [i] != 0; i++) {
418                                 if (porttab [i] != iobase)
419                                         continue;
420                                         
421                                 if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
422                                     iobase, iobase + NPORT, NPORT))
423                                         continue;
424
425                                 if (ct_probe_board (iobase, -1, -1) == 0)
426                                         continue;
427                                 porttab [i] = -1;
428                                 device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
429                                 break;
430                         }
431                         if (porttab [i] == 0) {
432                                 device_delete_child (
433                                     device_get_parent (devices[k]),
434                                     devices [k]);
435                                 devices[k] = 0;
436                                 continue;
437                         }
438                 }
439                 for (k = 0; k < devcount; k++) {
440                         if (devices[k] == 0)
441                                 continue;
442                         if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
443                             &iobase, &rescount) == 0)
444                                 continue;
445                         for (i = 0; (iobase = porttab [i]) != 0; i++) {
446                                 if (porttab [i] == -1)
447                                         continue;
448                                 if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
449                                     iobase, iobase + NPORT, NPORT))
450                                         continue;
451                                 if (ct_probe_board (iobase, -1, -1) == 0)
452                                         continue;
453                         
454                                 bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
455                                     iobase, NPORT);
456                                 porttab [i] = -1;
457                                 device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
458                                 break;
459                         }
460                         if (porttab [i] == 0) {
461                                 device_delete_child (
462                                     device_get_parent (devices[k]),
463                                     devices [k]);
464                         }
465                 }               
466                 free (devices, M_TEMP);
467         }
468         
469         return;
470 }
471
472 static int ct_probe (device_t dev)
473 {
474         int unit = device_get_unit (dev);
475         u_long iobase, rescount;
476
477         if (!device_get_desc (dev) ||
478             strcmp (device_get_desc (dev), "Cronyx Tau-ISA"))
479                 return ENXIO;
480
481 /*      KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/
482         if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
483                 printf ("ct%d: Couldn't get IOPORT\n", unit);
484                 return ENXIO;
485         }
486
487         if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
488             iobase, iobase + NPORT, NPORT)) {
489                 printf ("ct%d: Resource IOPORT isn't free\n", unit);
490                 return ENXIO;
491         }
492                 
493         if (!ct_probe_board (iobase, -1, -1)) {
494                 printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
495                 return ENXIO;
496         }
497         
498         return 0;
499 }
500
501 static void
502 ct_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
503 {
504         unsigned long *addr;
505
506         if (error)
507                 return;
508
509         KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
510         addr = arg;
511         *addr = segs->ds_addr;
512 }
513
514 static int
515 ct_bus_dma_mem_alloc (int bnum, int cnum, ct_dma_mem_t *dmem)
516 {
517         int error;
518
519         error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT,
520                 BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
521                 dmem->size, 0, NULL, NULL, &dmem->dmat);
522         if (error) {
523                 if (cnum >= 0)  printf ("ct%d-%d: ", bnum, cnum);
524                 else            printf ("ct%d: ", bnum);
525                 printf ("couldn't allocate tag for dma memory\n");
526                 return 0;
527         }
528         error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
529                 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
530         if (error) {
531                 if (cnum >= 0)  printf ("ct%d-%d: ", bnum, cnum);
532                 else            printf ("ct%d: ", bnum);
533                 printf ("couldn't allocate mem for dma memory\n");
534                 bus_dma_tag_destroy (dmem->dmat);
535                 return 0;
536         }
537         error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
538                 dmem->size, ct_bus_dmamap_addr, &dmem->phys, 0);
539         if (error) {
540                 if (cnum >= 0)  printf ("ct%d-%d: ", bnum, cnum);
541                 else            printf ("ct%d: ", bnum);
542                 printf ("couldn't load mem map for dma memory\n");
543                 bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
544                 bus_dma_tag_destroy (dmem->dmat);
545                 return 0;
546         }
547         return 1;
548 }
549
550 static void
551 ct_bus_dma_mem_free (ct_dma_mem_t *dmem)
552 {
553         bus_dmamap_unload (dmem->dmat, dmem->mapp);
554         bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
555         bus_dma_tag_destroy (dmem->dmat);
556 }
557
558 /*
559  * The adapter is present, initialize the driver structures.
560  */
561 static int ct_attach (device_t dev)
562 {
563         bdrv_t *bd = device_get_softc (dev);
564         u_long iobase, drq, irq, rescount;
565         int unit = device_get_unit (dev);
566         char *ct_ln = CT_LOCK_NAME;
567         ct_board_t *b;
568         ct_chan_t *c;
569         drv_t *d;
570         int i;
571         int s;
572
573         KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));
574         
575         bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
576         bd->base_rid = 0;
577         bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
578                 iobase, iobase + NPORT, NPORT, RF_ACTIVE);
579         if (! bd->base_res) {
580                 printf ("ct%d: cannot alloc base address\n", unit);
581                 return ENXIO;
582         }
583         
584         if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
585                 for (i = 0; (drq = dmatab [i]) != 0; i++) {
586                         if (!ct_is_free_res (dev, 0, SYS_RES_DRQ,
587                             drq, drq + 1, 1))
588                                 continue;
589                         bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
590                         break;
591                 }
592                 
593                 if (dmatab[i] == 0) {   
594                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
595                                 bd->base_res);
596                         printf ("ct%d: Couldn't get DRQ\n", unit);
597                         return ENXIO;
598                 }
599         }
600         
601         bd->drq_rid = 0;
602         bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
603                 drq, drq + 1, 1, RF_ACTIVE);
604         if (! bd->drq_res) {
605                 printf ("ct%d: cannot allocate drq\n", unit);
606                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
607                         bd->base_res);
608                 return ENXIO;
609         }       
610         
611         if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
612                 for (i = 0; (irq = irqtab [i]) != 0; i++) {
613                         if (!ct_is_free_res (dev, 0, SYS_RES_IRQ,
614                             irq, irq + 1, 1))
615                                 continue;
616                         bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
617                         break;
618                 }
619                 
620                 if (irqtab[i] == 0) {   
621                         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
622                                 bd->drq_res);
623                         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
624                                 bd->base_res);
625                         printf ("ct%d: Couldn't get IRQ\n", unit);
626                         return ENXIO;
627                 }
628         }
629         
630         bd->irq_rid = 0;
631         bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
632                 irq, irq + 1, 1, RF_ACTIVE);
633         if (! bd->irq_res) {
634                 printf ("ct%d: Couldn't allocate irq\n", unit);
635                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
636                         bd->drq_res);
637                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
638                         bd->base_res);
639                 return ENXIO;
640         }
641         
642         b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
643         if (!b) {
644                 printf ("ct:%d: Couldn't allocate memory\n", unit);
645                 return (ENXIO);
646         }
647         adapter[unit] = b;
648         bzero (b, sizeof(ct_board_t));
649         
650         if (! ct_open_board (b, unit, iobase, irq, drq)) {
651                 printf ("ct%d: error loading firmware\n", unit);
652                 free (b, M_DEVBUF);
653                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
654                         bd->irq_res);
655                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
656                         bd->drq_res);
657                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
658                         bd->base_res);
659                 return ENXIO;
660         }
661
662         bd->board = b;
663         
664         ct_ln[2] = '0' + unit;
665         mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
666         if (! probe_irq (b, irq)) {
667                 printf ("ct%d: irq %ld not functional\n", unit, irq);
668                 bd->board = 0;
669                 adapter [unit] = 0;
670                 free (b, M_DEVBUF);
671                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
672                         bd->irq_res);
673                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
674                         bd->drq_res);
675                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
676                         bd->base_res);
677                 mtx_destroy (&bd->ct_mtx);
678                 return ENXIO;
679         }
680         
681         callout_init (&led_timo[unit], ct_mpsafenet ? CALLOUT_MPSAFE : 0);
682         s = splimp ();
683         if (bus_setup_intr (dev, bd->irq_res,
684                            INTR_TYPE_NET|(ct_mpsafenet?INTR_MPSAFE:0),
685                            ct_intr, bd, &bd->intrhand)) {
686                 printf ("ct%d: Can't setup irq %ld\n", unit, irq);
687                 bd->board = 0;
688                 adapter [unit] = 0;
689                 free (b, M_DEVBUF);
690                 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
691                         bd->irq_res);
692                 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
693                         bd->drq_res);
694                 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
695                         bd->base_res);
696                 mtx_destroy (&bd->ct_mtx);
697                 splx (s);
698                 return ENXIO;           
699         }
700
701         CT_LOCK (bd);
702         ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc);
703         ct_setup_board (b, 0, 0, 0);
704         CT_UNLOCK (bd);
705
706         printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name,
707                 b->osc == 20000000 ? "20" : "16.384");
708
709         for (c = b->chan; c < b->chan + NCHAN; ++c) {
710                 d = &bd->channel[c->num];
711                 d->dmamem.size = sizeof(ct_buf_t);
712                 if (! ct_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
713                         continue;
714                 d->board = b;
715                 d->chan = c;
716                 d->bd = bd;
717                 c->sys = d;
718                 channel [b->num*NCHAN + c->num] = d;
719                 sprintf (d->name, "ct%d.%d", b->num, c->num);
720
721 #ifdef NETGRAPH
722                 if (ng_make_node_common (&typestruct, &d->node) != 0) {
723                         printf ("%s: cannot make common node\n", d->name);
724                         channel [b->num*NCHAN + c->num] = 0;
725                         c->sys = 0;             
726                         ct_bus_dma_mem_free (&d->dmamem);
727                         continue;
728                 }
729                 NG_NODE_SET_PRIVATE (d->node, d);
730                 sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE,
731                          c->board->num*NCHAN + c->num);
732                 if (ng_name_node (d->node, d->nodename)) {
733                         printf ("%s: cannot name node\n", d->nodename);
734                         NG_NODE_UNREF (d->node);
735                         channel [b->num*NCHAN + c->num] = 0;
736                         c->sys = 0;             
737                         ct_bus_dma_mem_free (&d->dmamem);
738                         continue;
739                 }
740                 d->queue.ifq_maxlen = IFQ_MAXLEN;
741                 d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
742                 mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
743                 mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF);          
744                 callout_init (&d->timeout_handle,
745                              ct_mpsafenet ? CALLOUT_MPSAFE : 0);
746 #else /*NETGRAPH*/
747                 d->ifp = if_alloc(IFT_PPP);
748                 if (d->ifp == NULL) {
749                         printf ("%s: cannot if_alloc common interface\n",
750                             d->name);
751                         channel [b->num*NCHAN + c->num] = 0;
752                         c->sys = 0;             
753                         ct_bus_dma_mem_free (&d->dmamem);
754                         continue;
755                 }
756                 d->ifp->if_softc        = d;
757                 if_initname (d->ifp, "ct", b->num * NCHAN + c->num);
758                 d->ifp->if_mtu          = PP_MTU;
759                 d->ifp->if_flags        = IFF_POINTOPOINT | IFF_MULTICAST;
760                 if (!ct_mpsafenet)
761                         d->ifp->if_flags |= IFF_NEEDSGIANT;
762                 d->ifp->if_ioctl        = ct_sioctl;
763                 d->ifp->if_start        = ct_ifstart;
764                 d->ifp->if_watchdog     = ct_ifwatchdog;
765                 d->ifp->if_init         = ct_initialize;
766                 d->queue.ifq_maxlen     = NBUF;
767                 mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
768                 sppp_attach (d->ifp);
769                 if_attach (d->ifp);
770                 IFP2SP(d->ifp)->pp_tlf  = ct_tlf;
771                 IFP2SP(d->ifp)->pp_tls  = ct_tls;
772                 /* If BPF is in the kernel, call the attach for it.
773                  * Header size is 4 bytes. */
774                 bpfattach (d->ifp, DLT_PPP, 4);
775 #endif /*NETGRAPH*/
776                 CT_LOCK (bd);
777                 ct_start_chan (c, d->dmamem.virt, d->dmamem.phys);
778                 ct_register_receive (c, &ct_receive);
779                 ct_register_transmit (c, &ct_transmit);
780                 ct_register_error (c, &ct_error);
781                 CT_UNLOCK (bd);
782                 d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
783                                 GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num);
784         }
785         splx (s);
786         
787         return 0;
788 }
789
790 static int ct_detach (device_t dev)
791 {
792         bdrv_t *bd = device_get_softc (dev);
793         ct_board_t *b = bd->board;
794         ct_chan_t *c;
795         int s;
796         
797         KASSERT (mtx_initialized (&bd->ct_mtx), ("ct mutex not initialized"));
798
799         s = splimp ();
800         CT_LOCK (bd);
801         /* Check if the device is busy (open). */
802         for (c = b->chan; c < b->chan + NCHAN; ++c) {
803                 drv_t *d = (drv_t*) c->sys;
804
805                 if (!d || !d->chan->type)
806                         continue;
807
808                 if (d->running) {
809                         CT_UNLOCK (bd);
810                         splx (s);
811                         return EBUSY;
812                 }
813         }
814
815         /* Deactivate the timeout routine. */
816         callout_stop (&led_timo[b->num]);
817
818         CT_UNLOCK (bd);
819         
820         bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
821         bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
822         bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
823         
824         bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
825         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
826         
827         bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res);
828         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
829
830         CT_LOCK (bd);
831         ct_close_board (b);
832         CT_UNLOCK (bd);
833
834         /* Detach the interfaces, free buffer memory. */
835         for (c = b->chan; c < b->chan + NCHAN; ++c) {
836                 drv_t *d = (drv_t*) c->sys;
837
838                 if (!d || !d->chan->type)
839                         continue;
840
841 #ifdef NETGRAPH
842                 if (d->node) {
843                         ng_rmnode_self (d->node);
844                         NG_NODE_UNREF (d->node);
845                         d->node = NULL;
846                 }
847                 mtx_destroy (&d->queue.ifq_mtx);
848                 mtx_destroy (&d->hi_queue.ifq_mtx);
849 #else
850                 /* Detach from the packet filter list of interfaces. */
851                 bpfdetach (d->ifp);
852
853                 /* Detach from the sync PPP list. */
854                 sppp_detach (d->ifp);
855
856                 if_detach (d->ifp);
857                 if_free (d->ifp);
858                 IF_DRAIN (&d->queue);
859                 mtx_destroy (&d->queue.ifq_mtx);
860 #endif          
861                 destroy_dev (d->devt);
862         }
863
864         CT_LOCK (bd);
865         ct_led_off (b);
866         CT_UNLOCK (bd);
867         callout_drain (&led_timo[b->num]);
868         splx (s);
869         
870         s = splimp ();
871         for (c = b->chan; c < b->chan + NCHAN; ++c) {
872                 drv_t *d = (drv_t*) c->sys;
873
874                 if (!d || !d->chan->type)
875                         continue;
876                 
877                 /* Deallocate buffers. */
878                 ct_bus_dma_mem_free (&d->dmamem);
879         }
880         bd->board = 0;
881         adapter [b->num] = 0;
882         free (b, M_DEVBUF);
883         splx (s);
884         
885         mtx_destroy (&bd->ct_mtx);
886
887         return 0;       
888 }
889
890 #ifndef NETGRAPH
891 static void ct_ifstart (struct ifnet *ifp)
892 {
893         drv_t *d = ifp->if_softc;
894         bdrv_t *bd = d->bd;
895         
896         CT_LOCK (bd);
897         ct_start (d);
898         CT_UNLOCK (bd);
899 }
900
901 static void ct_ifwatchdog (struct ifnet *ifp)
902 {
903         drv_t *d = ifp->if_softc;
904
905         ct_watchdog (d);
906 }
907
908 static void ct_tlf (struct sppp *sp)
909 {
910         drv_t *d = SP2IFP(sp)->if_softc;
911
912         CT_DEBUG (d, ("ct_tlf\n"));
913 /*      ct_set_dtr (d->chan, 0);*/
914 /*      ct_set_rts (d->chan, 0);*/
915         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
916                 sp->pp_down (sp);
917 }
918
919 static void ct_tls (struct sppp *sp)
920 {
921         drv_t *d = SP2IFP(sp)->if_softc;
922
923         CT_DEBUG (d, ("ct_tls\n"));
924         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
925                 sp->pp_up (sp);
926 }
927
928 /*
929  * Initialization of interface.
930  * Ii seems to be never called by upper level.
931  */
932 static void ct_initialize (void *softc)
933 {
934         drv_t *d = softc;
935
936         CT_DEBUG (d, ("ct_initialize\n"));
937 }
938
939 /*
940  * Process an ioctl request.
941  */
942 static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
943 {
944         drv_t *d = ifp->if_softc;
945         bdrv_t *bd = d->bd;
946         int error, s, was_up, should_be_up;
947
948         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
949         error = sppp_ioctl (ifp, cmd, data);
950         if (error)
951                 return error;
952
953         if (! (ifp->if_flags & IFF_DEBUG))
954                 d->chan->debug = 0;
955         else if (! d->chan->debug)
956                 d->chan->debug = 1;
957
958         switch (cmd) {
959         default:           CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
960         case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
961         case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
962         case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
963         case SIOCSIFADDR:  CT_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
964         }
965
966         /* We get here only in case of SIFFLAGS or SIFADDR. */
967         s = splimp ();
968         CT_LOCK (bd);
969         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
970         if (! was_up && should_be_up) {
971                 /* Interface goes up -- start it. */
972                 ct_up (d);
973                 ct_start (d);
974         } else if (was_up && ! should_be_up) {
975                 /* Interface is going down -- stop it. */
976                 /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
977                 ct_down (d);
978         }
979         CT_UNLOCK (bd);
980         splx (s);
981         return 0;
982 }
983 #endif /*NETGRAPH*/
984
985 /*
986  * Stop the interface.  Called on splimp().
987  */
988 static void ct_down (drv_t *d)
989 {
990         int s = splimp ();
991         CT_DEBUG (d, ("ct_down\n"));
992         ct_set_dtr (d->chan, 0);
993         ct_set_rts (d->chan, 0);
994         d->running = 0;
995         splx (s);
996 }
997
998 /*
999  * Start the interface.  Called on splimp().
1000  */
1001 static void ct_up (drv_t *d)
1002 {
1003         int s = splimp ();
1004         CT_DEBUG (d, ("ct_up\n"));
1005         ct_set_dtr (d->chan, 1);
1006         ct_set_rts (d->chan, 1);
1007         d->running = 1;
1008         splx (s);
1009 }
1010
1011 /*
1012  * Start output on the (slave) interface.  Get another datagram to send
1013  * off of the interface queue, and copy it to the interface
1014  * before starting the output.
1015  */
1016 static void ct_send (drv_t *d)
1017 {
1018         struct mbuf *m;
1019         u_short len;
1020
1021         CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
1022
1023         /* No output if the interface is down. */
1024         if (! d->running)
1025                 return;
1026
1027         /* No output if the modem is off. */
1028         if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
1029                 return;
1030
1031         while (ct_buf_free (d->chan)) {
1032                 /* Get the packet to send. */
1033 #ifdef NETGRAPH
1034                 IF_DEQUEUE (&d->hi_queue, m);
1035                 if (! m)
1036                         IF_DEQUEUE (&d->queue, m);
1037 #else
1038                 m = sppp_dequeue (d->ifp);
1039 #endif
1040                 if (! m)
1041                         return;
1042 #ifndef NETGRAPH
1043                 if (d->ifp->if_bpf)
1044                         BPF_MTAP (d->ifp, m);
1045 #endif
1046                 len = m_length (m, NULL);
1047                 if (! m->m_next)
1048                         ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
1049                                 len, 0);
1050                 else {
1051                         m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
1052                         ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
1053                                 len, 0);
1054                 }
1055                 m_freem (m);
1056
1057                 /* Set up transmit timeout, if the transmit ring is not empty.
1058                  * Transmit timeout is 10 seconds. */
1059 #ifdef NETGRAPH
1060                 d->timeout = 10;
1061 #else
1062                 d->ifp->if_timer = 10;
1063 #endif
1064         }
1065 #ifndef NETGRAPH
1066         d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1067 #endif
1068 }
1069
1070 /*
1071  * Start output on the interface.
1072  * Always called on splimp().
1073  */
1074 static void ct_start (drv_t *d)
1075 {
1076         int s = splimp ();
1077
1078         if (d->running) {
1079                 if (! d->chan->dtr)
1080                         ct_set_dtr (d->chan, 1);
1081                 if (! d->chan->rts)
1082                         ct_set_rts (d->chan, 1);
1083                 ct_send (d);
1084         }
1085
1086         splx (s);
1087 }
1088
1089 /*
1090  * Handle transmit timeouts.
1091  * Recover after lost transmit interrupts.
1092  * Always called on splimp().
1093  */
1094 static void ct_watchdog (drv_t *d)
1095 {
1096         bdrv_t *bd = d->bd;
1097         int s;
1098
1099         s = splimp ();
1100         CT_LOCK (bd);
1101         CT_DEBUG (d, ("device timeout\n"));
1102         if (d->running) {
1103                 ct_setup_chan (d->chan);
1104                 ct_start_chan (d->chan, 0, 0);
1105                 ct_set_dtr (d->chan, 1);
1106                 ct_set_rts (d->chan, 1);
1107                 ct_start (d);
1108         }
1109         CT_UNLOCK (bd);
1110         splx (s);
1111 }
1112
1113 /*
1114  * Transmit callback function.
1115  */
1116 static void ct_transmit (ct_chan_t *c, void *attachment, int len)
1117 {
1118         drv_t *d = c->sys;
1119
1120         if (!d)
1121                 return;
1122 #ifdef NETGRAPH
1123         d->timeout = 0;
1124 #else
1125         ++d->ifp->if_opackets;
1126         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1127         d->ifp->if_timer = 0;
1128 #endif
1129         ct_start (d);
1130 }
1131
1132 /*
1133  * Process the received packet.
1134  */
1135 static void ct_receive (ct_chan_t *c, char *data, int len)
1136 {
1137         drv_t *d = c->sys;
1138         struct mbuf *m;
1139 #ifdef NETGRAPH
1140         int error;
1141 #endif
1142
1143         if (!d || !d->running)
1144                 return;
1145
1146         m = makembuf (data, len);
1147         if (! m) {
1148                 CT_DEBUG (d, ("no memory for packet\n"));
1149 #ifndef NETGRAPH
1150                 ++d->ifp->if_iqdrops;
1151 #endif
1152                 return;
1153         }
1154         if (c->debug > 1)
1155                 printmbuf (m);
1156 #ifdef NETGRAPH
1157         m->m_pkthdr.rcvif = 0;
1158         NG_SEND_DATA_ONLY (error, d->hook, m);
1159 #else
1160         ++d->ifp->if_ipackets;
1161         m->m_pkthdr.rcvif = d->ifp;
1162         /* Check if there's a BPF listener on this interface.
1163          * If so, hand off the raw packet to bpf. */
1164         if (d->ifp->if_bpf)
1165                 BPF_TAP (d->ifp, data, len);
1166         IF_ENQUEUE (&d->queue, m);
1167 #endif
1168 }
1169
1170 /*
1171  * Error callback function.
1172  */
1173 static void ct_error (ct_chan_t *c, int data)
1174 {
1175         drv_t *d = c->sys;
1176
1177         if (!d)
1178                 return;
1179
1180         switch (data) {
1181         case CT_FRAME:
1182                 CT_DEBUG (d, ("frame error\n"));
1183 #ifndef NETGRAPH
1184                 ++d->ifp->if_ierrors;
1185 #endif
1186                 break;
1187         case CT_CRC:
1188                 CT_DEBUG (d, ("crc error\n"));
1189 #ifndef NETGRAPH
1190                 ++d->ifp->if_ierrors;
1191 #endif
1192                 break;
1193         case CT_OVERRUN:
1194                 CT_DEBUG (d, ("overrun error\n"));
1195 #ifndef NETGRAPH
1196                 ++d->ifp->if_collisions;
1197                 ++d->ifp->if_ierrors;
1198 #endif
1199                 break;
1200         case CT_OVERFLOW:
1201                 CT_DEBUG (d, ("overflow error\n"));
1202 #ifndef NETGRAPH
1203                 ++d->ifp->if_ierrors;
1204 #endif
1205                 break;
1206         case CT_UNDERRUN:
1207                 CT_DEBUG (d, ("underrun error\n"));
1208 #ifdef NETGRAPH
1209                 d->timeout = 0;
1210 #else
1211                 ++d->ifp->if_oerrors;
1212                 d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1213                 d->ifp->if_timer = 0;
1214 #endif
1215                 ct_start (d);
1216                 break;
1217         default:
1218                 CT_DEBUG (d, ("error #%d\n", data));
1219         }
1220 }
1221
1222 static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1223 {
1224         drv_t *d;
1225
1226         if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)]))
1227                 return ENXIO;
1228                 
1229         CT_DEBUG2 (d, ("ct_open\n"));
1230         return 0;
1231 }
1232
1233 static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1234 {
1235         drv_t *d = channel [minor(dev)];
1236
1237         if (!d)
1238                 return 0;
1239
1240         CT_DEBUG2 (d, ("ct_close\n"));
1241         return 0;
1242 }
1243
1244 static int ct_modem_status (ct_chan_t *c)
1245 {
1246         drv_t *d = c->sys;
1247         bdrv_t *bd;
1248         int status, s;
1249
1250         if (!d)
1251                 return 0;
1252
1253         bd = d->bd;
1254         
1255         status = d->running ? TIOCM_LE : 0;
1256         s = splimp ();
1257         CT_LOCK (bd);
1258         if (ct_get_cd  (c)) status |= TIOCM_CD;
1259         if (ct_get_cts (c)) status |= TIOCM_CTS;
1260         if (ct_get_dsr (c)) status |= TIOCM_DSR;
1261         if (c->dtr)         status |= TIOCM_DTR;
1262         if (c->rts)         status |= TIOCM_RTS;
1263         CT_UNLOCK (bd);
1264         splx (s);
1265         return status;
1266 }
1267
1268 /*
1269  * Process an ioctl request on /dev/cronyx/ctauN.
1270  */
1271 static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1272 {
1273         drv_t *d = channel [minor (dev)];
1274         bdrv_t *bd;
1275         ct_chan_t *c;
1276         struct serial_statistics *st;
1277         struct e1_statistics *opte1;
1278         int error, s;
1279         char mask[16];
1280
1281         if (!d || !d->chan)
1282                 return 0;
1283
1284         bd = d->bd;
1285         c = d->chan;
1286
1287         switch (cmd) {
1288         case SERIAL_GETREGISTERED:
1289                 bzero (mask, sizeof(mask));
1290                 for (s=0; s<NCTAU*NCHAN; ++s)
1291                         if (channel [s])
1292                                 mask [s/8] |= 1 << (s & 7);
1293                 bcopy (mask, data, sizeof (mask));
1294                 return 0;
1295
1296 #ifndef NETGRAPH
1297         case SERIAL_GETPROTO:
1298                 strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1299                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1300                 return 0;
1301
1302         case SERIAL_SETPROTO:
1303                 /* Only for superuser! */
1304                 error = priv_check (td, PRIV_DRIVER);
1305                 if (error)
1306                         return error;
1307                 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
1308                         return EBUSY;
1309                 if (! strcmp ("cisco", (char*)data)) {
1310                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1311                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1312                         d->ifp->if_flags |= PP_CISCO;
1313                 } else if (! strcmp ("fr", (char*)data)) {
1314                         d->ifp->if_flags &= ~(PP_CISCO);
1315                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1316                 } else if (! strcmp ("ppp", (char*)data)) {
1317                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1318                         d->ifp->if_flags &= ~(PP_CISCO);
1319                 } else
1320                         return EINVAL;
1321                 return 0;
1322
1323         case SERIAL_GETKEEPALIVE:
1324                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1325                         (d->ifp->if_flags & PP_CISCO))
1326                         return EINVAL;
1327                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1328                 return 0;
1329
1330         case SERIAL_SETKEEPALIVE:
1331                 /* Only for superuser! */
1332                 error = priv_check (td, PRIV_DRIVER);
1333                 if (error)
1334                         return error;
1335                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1336                         (d->ifp->if_flags & PP_CISCO))
1337                         return EINVAL;
1338                 if (*(int*)data)
1339                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1340                 else
1341                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1342                 return 0;
1343 #endif /*NETGRAPH*/
1344
1345         case SERIAL_GETMODE:
1346                 *(int*)data = SERIAL_HDLC;
1347                 return 0;
1348
1349         case SERIAL_GETCFG:
1350                 if (c->mode == M_HDLC)
1351                         return EINVAL;
1352                 switch (ct_get_config (c->board)) {
1353                 default:    *(char*)data = 'a'; break;
1354                 case CFG_B: *(char*)data = 'b'; break;
1355                 case CFG_C: *(char*)data = 'c'; break;
1356                 }
1357                 return 0;
1358
1359         case SERIAL_SETCFG:
1360                 /* Only for superuser! */
1361                 error = priv_check (td, PRIV_DRIVER);
1362                 if (error)
1363                         return error;
1364                 if (c->mode == M_HDLC)
1365                         return EINVAL;
1366                 s = splimp ();
1367                 CT_LOCK (bd);
1368                 switch (*(char*)data) {
1369                 case 'a': ct_set_config (c->board, CFG_A); break;
1370                 case 'b': ct_set_config (c->board, CFG_B); break;
1371                 case 'c': ct_set_config (c->board, CFG_C); break;
1372                 }
1373                 CT_UNLOCK (bd);
1374                 splx (s);
1375                 return 0;
1376
1377         case SERIAL_GETSTAT:
1378                 st = (struct serial_statistics*) data;
1379                 st->rintr  = c->rintr;
1380                 st->tintr  = c->tintr;
1381                 st->mintr  = c->mintr;
1382                 st->ibytes = c->ibytes;
1383                 st->ipkts  = c->ipkts;
1384                 st->ierrs  = c->ierrs;
1385                 st->obytes = c->obytes;
1386                 st->opkts  = c->opkts;
1387                 st->oerrs  = c->oerrs;
1388                 return 0;
1389
1390         case SERIAL_GETESTAT:
1391                 opte1 = (struct e1_statistics*)data;
1392                 opte1->status      = c->status;
1393                 opte1->cursec      = c->cursec;
1394                 opte1->totsec      = c->totsec + c->cursec;
1395
1396                 opte1->currnt.bpv   = c->currnt.bpv;
1397                 opte1->currnt.fse   = c->currnt.fse;
1398                 opte1->currnt.crce  = c->currnt.crce;
1399                 opte1->currnt.rcrce = c->currnt.rcrce;
1400                 opte1->currnt.uas   = c->currnt.uas;
1401                 opte1->currnt.les   = c->currnt.les;
1402                 opte1->currnt.es    = c->currnt.es;
1403                 opte1->currnt.bes   = c->currnt.bes;
1404                 opte1->currnt.ses   = c->currnt.ses;
1405                 opte1->currnt.oofs  = c->currnt.oofs;
1406                 opte1->currnt.css   = c->currnt.css;
1407                 opte1->currnt.dm    = c->currnt.dm;
1408
1409                 opte1->total.bpv   = c->total.bpv   + c->currnt.bpv;
1410                 opte1->total.fse   = c->total.fse   + c->currnt.fse;
1411                 opte1->total.crce  = c->total.crce  + c->currnt.crce;
1412                 opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1413                 opte1->total.uas   = c->total.uas   + c->currnt.uas;
1414                 opte1->total.les   = c->total.les   + c->currnt.les;
1415                 opte1->total.es    = c->total.es    + c->currnt.es;
1416                 opte1->total.bes   = c->total.bes   + c->currnt.bes;
1417                 opte1->total.ses   = c->total.ses   + c->currnt.ses;
1418                 opte1->total.oofs  = c->total.oofs  + c->currnt.oofs;
1419                 opte1->total.css   = c->total.css   + c->currnt.css;
1420                 opte1->total.dm    = c->total.dm    + c->currnt.dm;
1421                 for (s=0; s<48; ++s) {
1422                         opte1->interval[s].bpv   = c->interval[s].bpv;
1423                         opte1->interval[s].fse   = c->interval[s].fse;
1424                         opte1->interval[s].crce  = c->interval[s].crce;
1425                         opte1->interval[s].rcrce = c->interval[s].rcrce;
1426                         opte1->interval[s].uas   = c->interval[s].uas;
1427                         opte1->interval[s].les   = c->interval[s].les;
1428                         opte1->interval[s].es    = c->interval[s].es;
1429                         opte1->interval[s].bes   = c->interval[s].bes;
1430                         opte1->interval[s].ses   = c->interval[s].ses;
1431                         opte1->interval[s].oofs  = c->interval[s].oofs;
1432                         opte1->interval[s].css   = c->interval[s].css;
1433                         opte1->interval[s].dm    = c->interval[s].dm;
1434                 }
1435                 return 0;
1436
1437         case SERIAL_CLRSTAT:
1438                 /* Only for superuser! */
1439                 error = priv_check (td, PRIV_DRIVER);
1440                 if (error)
1441                         return error;
1442                 c->rintr = 0;
1443                 c->tintr = 0;
1444                 c->mintr = 0;
1445                 c->ibytes = 0;
1446                 c->ipkts = 0;
1447                 c->ierrs = 0;
1448                 c->obytes = 0;
1449                 c->opkts = 0;
1450                 c->oerrs = 0;
1451                 bzero (&c->currnt, sizeof (c->currnt));
1452                 bzero (&c->total, sizeof (c->total));
1453                 bzero (c->interval, sizeof (c->interval));
1454                 return 0;
1455
1456         case SERIAL_GETBAUD:
1457                 *(long*)data = ct_get_baud(c);
1458                 return 0;
1459
1460         case SERIAL_SETBAUD:
1461                 /* Only for superuser! */
1462                 error = priv_check (td, PRIV_DRIVER);
1463                 if (error)
1464                         return error;
1465                 s = splimp ();
1466                 CT_LOCK (bd);
1467                 ct_set_baud (c, *(long*)data);
1468                 CT_UNLOCK (bd);
1469                 splx (s);
1470                 return 0;
1471
1472         case SERIAL_GETLOOP:
1473                 *(int*)data = ct_get_loop (c);
1474                 return 0;
1475
1476         case SERIAL_SETLOOP:
1477                 /* Only for superuser! */
1478                 error = priv_check (td, PRIV_DRIVER);
1479                 if (error)
1480                         return error;
1481                 s = splimp ();
1482                 CT_LOCK (bd);
1483                 ct_set_loop (c, *(int*)data);
1484                 CT_UNLOCK (bd);
1485                 splx (s);
1486                 return 0;
1487
1488         case SERIAL_GETDPLL:
1489                 if (c->mode == M_E1 || c->mode == M_G703)
1490                         return EINVAL;
1491                 *(int*)data = ct_get_dpll (c);
1492                 return 0;
1493
1494         case SERIAL_SETDPLL:
1495                 /* Only for superuser! */
1496                 error = priv_check (td, PRIV_DRIVER);
1497                 if (error)
1498                         return error;
1499                 if (c->mode == M_E1 || c->mode == M_G703)
1500                         return EINVAL;
1501                 s = splimp ();
1502                 CT_LOCK (bd);
1503                 ct_set_dpll (c, *(int*)data);
1504                 CT_UNLOCK (bd);
1505                 splx (s);
1506                 return 0;
1507
1508         case SERIAL_GETNRZI:
1509                 if (c->mode == M_E1 || c->mode == M_G703)
1510                         return EINVAL;
1511                 *(int*)data = ct_get_nrzi (c);
1512                 return 0;
1513
1514         case SERIAL_SETNRZI:
1515                 /* Only for superuser! */
1516                 error = priv_check (td, PRIV_DRIVER);
1517                 if (error)
1518                         return error;
1519                 if (c->mode == M_E1 || c->mode == M_G703)
1520                         return EINVAL;
1521                 s = splimp ();
1522                 CT_LOCK (bd);
1523                 ct_set_nrzi (c, *(int*)data);
1524                 CT_UNLOCK (bd);
1525                 splx (s);
1526                 return 0;
1527
1528         case SERIAL_GETDEBUG:
1529                 *(int*)data = c->debug;
1530                 return 0;
1531
1532         case SERIAL_SETDEBUG:
1533                 /* Only for superuser! */
1534                 error = priv_check (td, PRIV_DRIVER);
1535                 if (error)
1536                         return error;
1537                 c->debug = *(int*)data;
1538 #ifndef NETGRAPH
1539                 if (d->chan->debug)
1540                         d->ifp->if_flags |= IFF_DEBUG;
1541                 else
1542                         d->ifp->if_flags &= (~IFF_DEBUG);
1543 #endif
1544                 return 0;
1545
1546         case SERIAL_GETHIGAIN:
1547                 if (c->mode != M_E1)
1548                         return EINVAL;
1549                 *(int*)data = ct_get_higain (c);
1550                 return 0;
1551
1552         case SERIAL_SETHIGAIN:
1553                 /* Only for superuser! */
1554                 error = priv_check (td, PRIV_DRIVER);
1555                 if (error)
1556                         return error;
1557                 s = splimp ();
1558                 CT_LOCK (bd);
1559                 ct_set_higain (c, *(int*)data);
1560                 CT_UNLOCK (bd);
1561                 splx (s);
1562                 return 0;
1563
1564         case SERIAL_GETPHONY:
1565                 CT_DEBUG2 (d, ("ioctl: getphony\n"));
1566                 if (c->mode != M_E1)
1567                         return EINVAL;
1568                 *(int*)data = c->gopt.phony;
1569                 return 0;
1570
1571         case SERIAL_SETPHONY:
1572                 CT_DEBUG2 (d, ("ioctl: setphony\n"));
1573                 if (c->mode != M_E1)
1574                         return EINVAL;
1575                 /* Only for superuser! */
1576                 error = priv_check (td, PRIV_DRIVER);
1577                 if (error)
1578                         return error;
1579                 s = splimp ();
1580                 CT_LOCK (bd);
1581                 ct_set_phony (c, *(int*)data);
1582                 CT_UNLOCK (bd);
1583                 splx (s);
1584                 return 0;
1585
1586         case SERIAL_GETCLK:
1587                 if (c->mode != M_E1 && c->mode != M_G703)
1588                         return EINVAL;
1589                 switch (ct_get_clk(c)) {
1590                 default:         *(int*)data = E1CLK_INTERNAL;          break;
1591                 case GCLK_RCV:   *(int*)data = E1CLK_RECEIVE;           break;
1592                 case GCLK_RCLKO: *(int*)data = c->num ?
1593                         E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1;      break;
1594                 }
1595                 return 0;
1596
1597         case SERIAL_SETCLK:
1598                 /* Only for superuser! */
1599                 error = priv_check (td, PRIV_DRIVER);
1600                 if (error)
1601                         return error;
1602                 s = splimp ();
1603                 CT_LOCK (bd);
1604                 switch (*(int*)data) {
1605                 default:                    ct_set_clk (c, GCLK_INT);   break;
1606                 case E1CLK_RECEIVE:         ct_set_clk (c, GCLK_RCV);   break;
1607                 case E1CLK_RECEIVE_CHAN0:
1608                 case E1CLK_RECEIVE_CHAN1:
1609                                             ct_set_clk (c, GCLK_RCLKO); break;
1610                 }
1611                 CT_UNLOCK (bd);
1612                 splx (s);
1613                 return 0;
1614
1615         case SERIAL_GETTIMESLOTS:
1616                 if (c->mode != M_E1)
1617                         return EINVAL;
1618                 *(long*)data = ct_get_ts (c);
1619                 return 0;
1620
1621         case SERIAL_SETTIMESLOTS:
1622                 /* Only for superuser! */
1623                 error = priv_check (td, PRIV_DRIVER);
1624                 if (error)
1625                         return error;
1626                 s = splimp ();
1627                 CT_LOCK (bd);
1628                 ct_set_ts (c, *(long*)data);
1629                 CT_UNLOCK (bd);
1630                 splx (s);
1631                 return 0;
1632
1633         case SERIAL_GETSUBCHAN:
1634                 if (c->mode != M_E1)
1635                         return EINVAL;
1636                 *(long*)data = ct_get_subchan (c->board);
1637                 return 0;
1638
1639         case SERIAL_SETSUBCHAN:
1640                 /* Only for superuser! */
1641                 error = priv_check (td, PRIV_DRIVER);
1642                 if (error)
1643                         return error;
1644                 s = splimp ();
1645                 CT_LOCK (bd);
1646                 ct_set_subchan (c->board, *(long*)data);
1647                 CT_UNLOCK (bd);
1648                 splx (s);
1649                 return 0;
1650
1651         case SERIAL_GETINVCLK:
1652         case SERIAL_GETINVTCLK:
1653                 if (c->mode == M_E1 || c->mode == M_G703)
1654                         return EINVAL;
1655                 *(int*)data = ct_get_invtxc (c);
1656                 return 0;
1657
1658         case SERIAL_GETINVRCLK:
1659                 if (c->mode == M_E1 || c->mode == M_G703)
1660                         return EINVAL;
1661                 *(int*)data = ct_get_invrxc (c);
1662                 return 0;
1663
1664         case SERIAL_SETINVCLK:
1665         case SERIAL_SETINVTCLK:
1666                 /* Only for superuser! */
1667                 error = priv_check (td, PRIV_DRIVER);
1668                 if (error)
1669                         return error;
1670                 if (c->mode == M_E1 || c->mode == M_G703)
1671                         return EINVAL;
1672                 s = splimp ();
1673                 CT_LOCK (bd);
1674                 ct_set_invtxc (c, *(int*)data);
1675                 CT_UNLOCK (bd);
1676                 splx (s);
1677                 return 0;
1678
1679         case SERIAL_SETINVRCLK:
1680                 /* Only for superuser! */
1681                 error = priv_check (td, PRIV_DRIVER);
1682                 if (error)
1683                         return error;
1684                 if (c->mode == M_E1 || c->mode == M_G703)
1685                         return EINVAL;
1686                 s = splimp ();
1687                 CT_LOCK (bd);
1688                 ct_set_invrxc (c, *(int*)data);
1689                 CT_UNLOCK (bd);
1690                 splx (s);
1691                 return 0;
1692
1693         case SERIAL_GETLEVEL:
1694                 if (c->mode != M_G703)
1695                         return EINVAL;
1696                 s = splimp ();
1697                 CT_LOCK (bd);
1698                 *(int*)data = ct_get_lq (c);
1699                 CT_UNLOCK (bd);
1700                 splx (s);
1701                 return 0;
1702
1703         case TIOCSDTR:  /* Set DTR */
1704                 s = splimp ();
1705                 CT_LOCK (bd);
1706                 ct_set_dtr (c, 1);
1707                 CT_UNLOCK (bd);
1708                 splx (s);
1709                 return 0;
1710
1711         case TIOCCDTR:  /* Clear DTR */
1712                 s = splimp ();
1713                 CT_LOCK (bd);
1714                 ct_set_dtr (c, 0);
1715                 CT_UNLOCK (bd);
1716                 splx (s);
1717                 return 0;
1718
1719         case TIOCMSET:  /* Set DTR/RTS */
1720                 s = splimp ();
1721                 CT_LOCK (bd);
1722                 ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1723                 ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1724                 CT_UNLOCK (bd);
1725                 splx (s);
1726                 return 0;
1727
1728         case TIOCMBIS:  /* Add DTR/RTS */
1729                 s = splimp ();
1730                 CT_LOCK (bd);
1731                 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1);
1732                 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1);
1733                 CT_UNLOCK (bd);
1734                 splx (s);
1735                 return 0;
1736
1737         case TIOCMBIC:  /* Clear DTR/RTS */
1738                 s = splimp ();
1739                 CT_LOCK (bd);
1740                 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0);
1741                 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0);
1742                 CT_UNLOCK (bd);
1743                 splx (s);
1744                 return 0;
1745
1746         case TIOCMGET:  /* Get modem status */
1747                 *(int*)data = ct_modem_status (c);
1748                 return 0;
1749         }
1750         return ENOTTY;
1751 }
1752
1753 #ifdef NETGRAPH
1754 static int ng_ct_constructor (node_p node)
1755 {
1756         drv_t *d = NG_NODE_PRIVATE (node);
1757         CT_DEBUG (d, ("Constructor\n"));
1758         return EINVAL;
1759 }
1760
1761 static int ng_ct_newhook (node_p node, hook_p hook, const char *name)
1762 {
1763         int s;
1764         drv_t *d = NG_NODE_PRIVATE (node);
1765
1766         if (!d)
1767                 return EINVAL;
1768                 
1769         bdrv_t *bd = d->bd;
1770         
1771         /* Attach debug hook */
1772         if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) {
1773                 NG_HOOK_SET_PRIVATE (hook, NULL);
1774                 d->debug_hook = hook;
1775                 return 0;
1776         }
1777
1778         /* Check for raw hook */
1779         if (strcmp (name, NG_CT_HOOK_RAW) != 0)
1780                 return EINVAL;
1781
1782         NG_HOOK_SET_PRIVATE (hook, d);
1783         d->hook = hook;
1784         s = splimp ();
1785         CT_LOCK (bd);
1786         ct_up (d);
1787         CT_UNLOCK (bd);
1788         splx (s);
1789         return 0;
1790 }
1791
1792 static char *format_timeslots (u_long s)
1793 {
1794         static char buf [100];
1795         char *p = buf;
1796         int i;
1797
1798         for (i=1; i<32; ++i)
1799                 if ((s >> i) & 1) {
1800                         int prev = (i > 1)  & (s >> (i-1));
1801                         int next = (i < 31) & (s >> (i+1));
1802
1803                         if (prev) {
1804                                 if (next)
1805                                         continue;
1806                                 *p++ = '-';
1807                         } else if (p > buf)
1808                                 *p++ = ',';
1809
1810                         if (i >= 10)
1811                                 *p++ = '0' + i / 10;
1812                         *p++ = '0' + i % 10;
1813                 }
1814         *p = 0;
1815         return buf;
1816 }
1817
1818 static int print_modems (char *s, ct_chan_t *c, int need_header)
1819 {
1820         int status = ct_modem_status (c);
1821         int length = 0;
1822
1823         if (need_header)
1824                 length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1825         length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1826                 status & TIOCM_LE  ? "On" : "-",
1827                 status & TIOCM_DTR ? "On" : "-",
1828                 status & TIOCM_DSR ? "On" : "-",
1829                 status & TIOCM_RTS ? "On" : "-",
1830                 status & TIOCM_CTS ? "On" : "-",
1831                 status & TIOCM_CD  ? "On" : "-");
1832         return length;
1833 }
1834
1835 static int print_stats (char *s, ct_chan_t *c, int need_header)
1836 {
1837         struct serial_statistics st;
1838         int length = 0;
1839
1840         st.rintr  = c->rintr;
1841         st.tintr  = c->tintr;
1842         st.mintr  = c->mintr;
1843         st.ibytes = c->ibytes;
1844         st.ipkts  = c->ipkts;
1845         st.ierrs  = c->ierrs;
1846         st.obytes = c->obytes;
1847         st.opkts  = c->opkts;
1848         st.oerrs  = c->oerrs;
1849         if (need_header)
1850                 length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1851         length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
1852                 st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts,
1853                 st.ierrs, st.obytes, st.opkts, st.oerrs);
1854         return length;
1855 }
1856
1857 static char *format_e1_status (u_char status)
1858 {
1859         static char buf [80];
1860
1861         if (status & E1_NOALARM)
1862                 return "Ok";
1863         buf[0] = 0;
1864         if (status & E1_LOS)     strcat (buf, ",LOS");
1865         if (status & E1_AIS)     strcat (buf, ",AIS");
1866         if (status & E1_LOF)     strcat (buf, ",LOF");
1867         if (status & E1_LOMF)    strcat (buf, ",LOMF");
1868         if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
1869         if (status & E1_AIS16)   strcat (buf, ",AIS16");
1870         if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
1871         if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
1872         if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
1873         if (buf[0] == ',')
1874                 return buf+1;
1875         return "Unknown";
1876 }
1877
1878 static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
1879 {
1880         int n, length = 0;
1881
1882         if (numerator < 1 || divider < 1) {
1883                 length += sprintf (s+length, leftalign ? "/-   " : "    -");
1884                 return length;
1885         }
1886         n = (int) (0.5 + 1000.0 * numerator / divider);
1887         if (n < 1000) {
1888                 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
1889                 return length;
1890         }
1891         *(s + length) = leftalign ? '/' : ' ';
1892         length ++;
1893
1894         if     (n >= 1000000) n = (n+500) / 1000 * 1000;
1895         else if (n >= 100000)  n = (n+50)  / 100 * 100;
1896         else if (n >= 10000)   n = (n+5)   / 10 * 10;
1897
1898         switch (n) {
1899         case 1000:    length += printf (s+length, ".999"); return length;
1900         case 10000:   n = 9990;   break;
1901         case 100000:  n = 99900;  break;
1902         case 1000000: n = 999000; break;
1903         }
1904         if (n < 10000)        length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
1905         else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
1906         else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
1907         else                  length += sprintf (s+length, "%d", n/1000);
1908
1909         return length;
1910 }
1911
1912 static int print_e1_stats (char *s, ct_chan_t *c)
1913 {
1914         struct e1_counters total;
1915         u_long totsec;
1916         int length = 0;
1917
1918         totsec          = c->totsec + c->cursec;
1919         total.bpv       = c->total.bpv   + c->currnt.bpv;
1920         total.fse       = c->total.fse   + c->currnt.fse;
1921         total.crce      = c->total.crce  + c->currnt.crce;
1922         total.rcrce     = c->total.rcrce + c->currnt.rcrce;
1923         total.uas       = c->total.uas   + c->currnt.uas;
1924         total.les       = c->total.les   + c->currnt.les;
1925         total.es        = c->total.es    + c->currnt.es;
1926         total.bes       = c->total.bes   + c->currnt.bes;
1927         total.ses       = c->total.ses   + c->currnt.ses;
1928         total.oofs      = c->total.oofs  + c->currnt.oofs;
1929         total.css       = c->total.css   + c->currnt.css;
1930         total.dm        = c->total.dm    + c->currnt.dm;
1931
1932         length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
1933
1934         /* Unavailable seconds, degraded minutes */
1935         length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
1936         length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
1937
1938         /* Bipolar violations, frame sync errors */
1939         length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
1940         length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
1941
1942         /* CRC errors, remote CRC errors (E-bit) */
1943         length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
1944         length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
1945
1946         /* Errored seconds, line errored seconds */
1947         length += print_frac (s + length, 0, c->currnt.es, c->cursec);
1948         length += print_frac (s + length, 1, c->currnt.les, c->cursec);
1949
1950         /* Severely errored seconds, burst errored seconds */
1951         length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
1952         length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
1953
1954         /* Out of frame seconds, controlled slip seconds */
1955         length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
1956         length += print_frac (s + length, 1, c->currnt.css, c->cursec);
1957
1958         length += sprintf (s + length, " %s\n", format_e1_status (c->status));
1959
1960         /* Print total statistics. */
1961         length += print_frac (s + length, 0, total.uas, totsec);
1962         length += print_frac (s + length, 1, 60 * total.dm, totsec);
1963
1964         length += print_frac (s + length, 0, total.bpv, totsec);
1965         length += print_frac (s + length, 1, total.fse, totsec);
1966
1967         length += print_frac (s + length, 0, total.crce, totsec);
1968         length += print_frac (s + length, 1, total.rcrce, totsec);
1969
1970         length += print_frac (s + length, 0, total.es, totsec);
1971         length += print_frac (s + length, 1, total.les, totsec);
1972
1973         length += print_frac (s + length, 0, total.ses, totsec);
1974         length += print_frac (s + length, 1, total.bes, totsec);
1975
1976         length += print_frac (s + length, 0, total.oofs, totsec);
1977         length += print_frac (s + length, 1, total.css, totsec);
1978
1979         length += sprintf (s + length, " -- Total\n");
1980         return length;
1981 }
1982
1983 static int print_chan (char *s, ct_chan_t *c)
1984 {
1985         drv_t *d = c->sys;
1986         bdrv_t *bd = d->bd;
1987         int length = 0;
1988
1989         length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num);
1990         if (d->chan->debug)
1991                 length += sprintf (s + length, " debug=%d", d->chan->debug);
1992
1993         switch (ct_get_config (c->board)) {
1994         case CFG_A:     length += sprintf (s + length, " cfg=A");       break;
1995         case CFG_B:     length += sprintf (s + length, " cfg=B");       break;
1996         case CFG_C:     length += sprintf (s + length, " cfg=C");       break;
1997         default:        length += sprintf (s + length, " cfg=unknown"); break;
1998         }
1999
2000         if (ct_get_baud (c))
2001                 length += sprintf (s + length, " %ld", ct_get_baud (c));
2002         else
2003                 length += sprintf (s + length, " extclock");
2004
2005         if (c->mode == M_E1 || c->mode == M_G703)
2006                 switch (ct_get_clk(c)) {
2007                 case GCLK_INT   : length += sprintf (s + length, " syn=int");     break;
2008                 case GCLK_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2009                 case GCLK_RCLKO  : length += sprintf (s + length, " syn=xrcv");    break;
2010                 }
2011         if (c->mode == M_HDLC) {
2012                 length += sprintf (s + length, " dpll=%s",   ct_get_dpll (c)   ? "on" : "off");
2013                 length += sprintf (s + length, " nrzi=%s",   ct_get_nrzi (c)   ? "on" : "off");
2014                 length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off");
2015                 length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off");
2016         }
2017         if (c->mode == M_E1)
2018                 length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off");
2019
2020         length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off");
2021
2022         if (c->mode == M_E1)
2023                 length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c)));
2024         if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A)
2025                 length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board)));
2026         if (c->mode == M_G703) {
2027                 int lq, x;
2028
2029                 x = splimp ();
2030                 CT_LOCK (bd);
2031                 lq = ct_get_lq (c);
2032                 CT_UNLOCK (bd);
2033                 splx (x);
2034                 length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2035         }
2036         length += sprintf (s + length, "\n");
2037         return length;
2038 }
2039
2040 static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook)
2041 {
2042         drv_t *d = NG_NODE_PRIVATE (node);
2043         struct ng_mesg *msg;
2044         struct ng_mesg *resp = NULL;
2045         int error = 0;
2046
2047         if (!d)
2048                 return EINVAL;
2049                 
2050         CT_DEBUG (d, ("Rcvmsg\n"));
2051         NGI_GET_MSG (item, msg);
2052         switch (msg->header.typecookie) {
2053         default:
2054                 error = EINVAL;
2055                 break;
2056
2057         case NGM_CT_COOKIE:
2058                 printf ("Don't forget to implement\n");
2059                 error = EINVAL;
2060                 break;
2061
2062         case NGM_GENERIC_COOKIE:
2063                 switch (msg->header.cmd) {
2064                 default:
2065                         error = EINVAL;
2066                         break;
2067
2068                 case NGM_TEXT_STATUS: {
2069                         char *s;
2070                         int l = 0;
2071                         int dl = sizeof (struct ng_mesg) + 730;
2072
2073                         NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2074                         if (! resp) {
2075                                 error = ENOMEM;
2076                                 break;
2077                         }
2078                         s = (resp)->data;
2079                         l += print_chan (s + l, d->chan);
2080                         l += print_stats (s + l, d->chan, 1);
2081                         l += print_modems (s + l, d->chan, 1);
2082                         l += print_e1_stats (s + l, d->chan);
2083                         strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2084                         }
2085                         break;
2086                 }
2087                 break;
2088         }
2089         NG_RESPOND_MSG (error, node, item, resp);
2090         NG_FREE_MSG (msg);
2091         return error;
2092 }
2093
2094 static int ng_ct_rcvdata (hook_p hook, item_p item)
2095 {
2096         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2097         struct mbuf *m;
2098         struct ng_tag_prio *ptag;
2099         bdrv_t *bd;
2100         struct ifqueue *q;
2101         int s;
2102
2103         if (!d)
2104                 return ENETDOWN;
2105                 
2106         bd = d->bd;
2107         NGI_GET_M (item, m);
2108         NG_FREE_ITEM (item);
2109         if (! NG_HOOK_PRIVATE (hook) || ! d) {
2110                 NG_FREE_M (m);
2111                 return ENETDOWN;
2112         }
2113
2114         /* Check for high priority data */
2115         if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2116             NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2117                 q = &d->hi_queue;
2118         else
2119                 q = &d->queue;
2120
2121         s = splimp ();
2122         CT_LOCK (bd);
2123         IF_LOCK (q);
2124         if (_IF_QFULL (q)) {
2125                 _IF_DROP (q);
2126                 IF_UNLOCK (q);
2127                 CT_UNLOCK (bd);
2128                 splx (s);
2129                 NG_FREE_M (m);
2130                 return ENOBUFS;
2131         }
2132         _IF_ENQUEUE (q, m);
2133         IF_UNLOCK (q);
2134         ct_start (d);
2135         CT_UNLOCK (bd);
2136         splx (s);
2137         return 0;
2138 }
2139
2140 static int ng_ct_rmnode (node_p node)
2141 {
2142         drv_t *d = NG_NODE_PRIVATE (node);
2143         bdrv_t *bd;
2144
2145         CT_DEBUG (d, ("Rmnode\n"));
2146         if (d && d->running) {
2147                 bd = d->bd;
2148                 int s = splimp ();
2149                 CT_LOCK (bd);
2150                 ct_down (d);
2151                 CT_UNLOCK (bd);
2152                 splx (s);
2153         }
2154 #ifdef  KLD_MODULE
2155         if (node->nd_flags & NGF_REALLY_DIE) {
2156                 NG_NODE_SET_PRIVATE (node, NULL);
2157                 NG_NODE_UNREF (node);
2158         }
2159         NG_NODE_REVIVE(node);           /* Persistant node */
2160 #endif
2161         return 0;
2162 }
2163
2164 static void ng_ct_watchdog (void *arg)
2165 {
2166         drv_t *d = arg;
2167
2168         if (!d)
2169                 return;
2170                 
2171         if (d->timeout == 1)
2172                 ct_watchdog (d);
2173         if (d->timeout)
2174                 d->timeout--;
2175         callout_reset (&d->timeout_handle, hz, ng_ct_watchdog, d);
2176 }
2177
2178 static int ng_ct_connect (hook_p hook)
2179 {
2180         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2181
2182         if (!d)
2183                 return 0;
2184                 
2185         callout_reset (&d->timeout_handle, hz, ng_ct_watchdog, d);
2186         return 0;
2187 }
2188
2189 static int ng_ct_disconnect (hook_p hook)
2190 {
2191         drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2192         bdrv_t *bd;
2193         
2194         if (!d)
2195                 return 0;
2196         
2197         bd = d->bd;
2198         
2199         CT_LOCK (bd);
2200         if (NG_HOOK_PRIVATE (hook))
2201                 ct_down (d);
2202         CT_UNLOCK (bd);
2203         /* If we were wait it than it reasserted now, just stop it. */
2204         if (!callout_drain (&d->timeout_handle))
2205                 callout_stop (&d->timeout_handle);
2206         return 0;
2207 }
2208 #endif
2209
2210 static int ct_modevent (module_t mod, int type, void *unused)
2211 {
2212         static int load_count = 0;
2213
2214         if (!debug_mpsafenet && ct_mpsafenet) {
2215                 printf ("WORNING! Network stack is not MPSAFE. "
2216                         "Turning off debug.ct.mpsafenet.\n");
2217                 ct_mpsafenet = 0;
2218         }
2219         if (ct_mpsafenet)
2220                 ct_cdevsw.d_flags &= ~D_NEEDGIANT;
2221
2222         switch (type) {
2223         case MOD_LOAD:
2224 #ifdef NETGRAPH
2225                 if (ng_newtype (&typestruct))
2226                         printf ("Failed to register ng_ct\n");
2227 #endif
2228                 ++load_count;
2229                 callout_init (&timeout_handle, ct_mpsafenet?CALLOUT_MPSAFE:0);
2230                 callout_reset (&timeout_handle, hz*5, ct_timeout, 0);
2231                 break;
2232         case MOD_UNLOAD:
2233                 if (load_count == 1) {
2234                         printf ("Removing device entry for Tau-ISA\n");
2235 #ifdef NETGRAPH
2236                         ng_rmtype (&typestruct);
2237 #endif                  
2238                 }
2239                 /* If we were wait it than it reasserted now, just stop it. */
2240                 if (!callout_drain (&timeout_handle))
2241                         callout_stop (&timeout_handle);
2242                 --load_count;
2243                 break;
2244         case MOD_SHUTDOWN:
2245                 break;
2246         }
2247         return 0;
2248 }
2249
2250 #ifdef NETGRAPH
2251 static struct ng_type typestruct = {
2252         .version        = NG_ABI_VERSION,
2253         .name           = NG_CT_NODE_TYPE,
2254         .constructor    = ng_ct_constructor,
2255         .rcvmsg         = ng_ct_rcvmsg,
2256         .shutdown       = ng_ct_rmnode,
2257         .newhook        = ng_ct_newhook,
2258         .connect        = ng_ct_connect,
2259         .rcvdata        = ng_ct_rcvdata,
2260         .disconnect     = ng_ct_disconnect,
2261 };
2262 #endif /*NETGRAPH*/
2263
2264 #ifdef NETGRAPH
2265 MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2266 #else
2267 MODULE_DEPEND (ct, sppp, 1, 1, 1);
2268 #endif
2269 DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2270 MODULE_VERSION (ct, 1);