]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ctau/if_ct.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 interrupt 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                            NULL, 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_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
822         
823         bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
824         
825         bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
826
827         CT_LOCK (bd);
828         ct_close_board (b);
829         CT_UNLOCK (bd);
830
831         /* Detach the interfaces, free buffer memory. */
832         for (c = b->chan; c < b->chan + NCHAN; ++c) {
833                 drv_t *d = (drv_t*) c->sys;
834
835                 if (!d || !d->chan->type)
836                         continue;
837
838 #ifdef NETGRAPH
839                 if (d->node) {
840                         ng_rmnode_self (d->node);
841                         NG_NODE_UNREF (d->node);
842                         d->node = NULL;
843                 }
844                 mtx_destroy (&d->queue.ifq_mtx);
845                 mtx_destroy (&d->hi_queue.ifq_mtx);
846 #else
847                 /* Detach from the packet filter list of interfaces. */
848                 bpfdetach (d->ifp);
849
850                 /* Detach from the sync PPP list. */
851                 sppp_detach (d->ifp);
852
853                 if_detach (d->ifp);
854                 if_free (d->ifp);
855                 IF_DRAIN (&d->queue);
856                 mtx_destroy (&d->queue.ifq_mtx);
857 #endif          
858                 destroy_dev (d->devt);
859         }
860
861         CT_LOCK (bd);
862         ct_led_off (b);
863         CT_UNLOCK (bd);
864         callout_drain (&led_timo[b->num]);
865         splx (s);
866         
867         s = splimp ();
868         for (c = b->chan; c < b->chan + NCHAN; ++c) {
869                 drv_t *d = (drv_t*) c->sys;
870
871                 if (!d || !d->chan->type)
872                         continue;
873                 
874                 /* Deallocate buffers. */
875                 ct_bus_dma_mem_free (&d->dmamem);
876         }
877         bd->board = 0;
878         adapter [b->num] = 0;
879         free (b, M_DEVBUF);
880         splx (s);
881         
882         mtx_destroy (&bd->ct_mtx);
883
884         return 0;       
885 }
886
887 #ifndef NETGRAPH
888 static void ct_ifstart (struct ifnet *ifp)
889 {
890         drv_t *d = ifp->if_softc;
891         bdrv_t *bd = d->bd;
892         
893         CT_LOCK (bd);
894         ct_start (d);
895         CT_UNLOCK (bd);
896 }
897
898 static void ct_ifwatchdog (struct ifnet *ifp)
899 {
900         drv_t *d = ifp->if_softc;
901
902         ct_watchdog (d);
903 }
904
905 static void ct_tlf (struct sppp *sp)
906 {
907         drv_t *d = SP2IFP(sp)->if_softc;
908
909         CT_DEBUG (d, ("ct_tlf\n"));
910 /*      ct_set_dtr (d->chan, 0);*/
911 /*      ct_set_rts (d->chan, 0);*/
912         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
913                 sp->pp_down (sp);
914 }
915
916 static void ct_tls (struct sppp *sp)
917 {
918         drv_t *d = SP2IFP(sp)->if_softc;
919
920         CT_DEBUG (d, ("ct_tls\n"));
921         if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
922                 sp->pp_up (sp);
923 }
924
925 /*
926  * Initialization of interface.
927  * Ii seems to be never called by upper level.
928  */
929 static void ct_initialize (void *softc)
930 {
931         drv_t *d = softc;
932
933         CT_DEBUG (d, ("ct_initialize\n"));
934 }
935
936 /*
937  * Process an ioctl request.
938  */
939 static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
940 {
941         drv_t *d = ifp->if_softc;
942         bdrv_t *bd = d->bd;
943         int error, s, was_up, should_be_up;
944
945         was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
946         error = sppp_ioctl (ifp, cmd, data);
947         if (error)
948                 return error;
949
950         if (! (ifp->if_flags & IFF_DEBUG))
951                 d->chan->debug = 0;
952         else
953                 d->chan->debug = d->chan->debug_shadow;
954
955         switch (cmd) {
956         default:           CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
957         case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
958         case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
959         case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
960         case SIOCSIFADDR:  CT_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
961         }
962
963         /* We get here only in case of SIFFLAGS or SIFADDR. */
964         s = splimp ();
965         CT_LOCK (bd);
966         should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
967         if (! was_up && should_be_up) {
968                 /* Interface goes up -- start it. */
969                 ct_up (d);
970                 ct_start (d);
971         } else if (was_up && ! should_be_up) {
972                 /* Interface is going down -- stop it. */
973                 /* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
974                 ct_down (d);
975         }
976         CT_UNLOCK (bd);
977         splx (s);
978         return 0;
979 }
980 #endif /*NETGRAPH*/
981
982 /*
983  * Stop the interface.  Called on splimp().
984  */
985 static void ct_down (drv_t *d)
986 {
987         int s = splimp ();
988         CT_DEBUG (d, ("ct_down\n"));
989         ct_set_dtr (d->chan, 0);
990         ct_set_rts (d->chan, 0);
991         d->running = 0;
992         splx (s);
993 }
994
995 /*
996  * Start the interface.  Called on splimp().
997  */
998 static void ct_up (drv_t *d)
999 {
1000         int s = splimp ();
1001         CT_DEBUG (d, ("ct_up\n"));
1002         ct_set_dtr (d->chan, 1);
1003         ct_set_rts (d->chan, 1);
1004         d->running = 1;
1005         splx (s);
1006 }
1007
1008 /*
1009  * Start output on the (slave) interface.  Get another datagram to send
1010  * off of the interface queue, and copy it to the interface
1011  * before starting the output.
1012  */
1013 static void ct_send (drv_t *d)
1014 {
1015         struct mbuf *m;
1016         u_short len;
1017
1018         CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
1019
1020         /* No output if the interface is down. */
1021         if (! d->running)
1022                 return;
1023
1024         /* No output if the modem is off. */
1025         if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
1026                 return;
1027
1028         while (ct_buf_free (d->chan)) {
1029                 /* Get the packet to send. */
1030 #ifdef NETGRAPH
1031                 IF_DEQUEUE (&d->hi_queue, m);
1032                 if (! m)
1033                         IF_DEQUEUE (&d->queue, m);
1034 #else
1035                 m = sppp_dequeue (d->ifp);
1036 #endif
1037                 if (! m)
1038                         return;
1039 #ifndef NETGRAPH
1040                 BPF_MTAP (d->ifp, m);
1041 #endif
1042                 len = m_length (m, NULL);
1043                 if (! m->m_next)
1044                         ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
1045                                 len, 0);
1046                 else {
1047                         m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
1048                         ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
1049                                 len, 0);
1050                 }
1051                 m_freem (m);
1052
1053                 /* Set up transmit timeout, if the transmit ring is not empty.
1054                  * Transmit timeout is 10 seconds. */
1055 #ifdef NETGRAPH
1056                 d->timeout = 10;
1057 #else
1058                 d->ifp->if_timer = 10;
1059 #endif
1060         }
1061 #ifndef NETGRAPH
1062         d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1063 #endif
1064 }
1065
1066 /*
1067  * Start output on the interface.
1068  * Always called on splimp().
1069  */
1070 static void ct_start (drv_t *d)
1071 {
1072         int s = splimp ();
1073
1074         if (d->running) {
1075                 if (! d->chan->dtr)
1076                         ct_set_dtr (d->chan, 1);
1077                 if (! d->chan->rts)
1078                         ct_set_rts (d->chan, 1);
1079                 ct_send (d);
1080         }
1081
1082         splx (s);
1083 }
1084
1085 /*
1086  * Handle transmit timeouts.
1087  * Recover after lost transmit interrupts.
1088  * Always called on splimp().
1089  */
1090 static void ct_watchdog (drv_t *d)
1091 {
1092         bdrv_t *bd = d->bd;
1093         int s;
1094
1095         s = splimp ();
1096         CT_LOCK (bd);
1097         CT_DEBUG (d, ("device timeout\n"));
1098         if (d->running) {
1099                 ct_setup_chan (d->chan);
1100                 ct_start_chan (d->chan, 0, 0);
1101                 ct_set_dtr (d->chan, 1);
1102                 ct_set_rts (d->chan, 1);
1103                 ct_start (d);
1104         }
1105         CT_UNLOCK (bd);
1106         splx (s);
1107 }
1108
1109 /*
1110  * Transmit callback function.
1111  */
1112 static void ct_transmit (ct_chan_t *c, void *attachment, int len)
1113 {
1114         drv_t *d = c->sys;
1115
1116         if (!d)
1117                 return;
1118 #ifdef NETGRAPH
1119         d->timeout = 0;
1120 #else
1121         ++d->ifp->if_opackets;
1122         d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1123         d->ifp->if_timer = 0;
1124 #endif
1125         ct_start (d);
1126 }
1127
1128 /*
1129  * Process the received packet.
1130  */
1131 static void ct_receive (ct_chan_t *c, char *data, int len)
1132 {
1133         drv_t *d = c->sys;
1134         struct mbuf *m;
1135 #ifdef NETGRAPH
1136         int error;
1137 #endif
1138
1139         if (!d || !d->running)
1140                 return;
1141
1142         m = makembuf (data, len);
1143         if (! m) {
1144                 CT_DEBUG (d, ("no memory for packet\n"));
1145 #ifndef NETGRAPH
1146                 ++d->ifp->if_iqdrops;
1147 #endif
1148                 return;
1149         }
1150         if (c->debug > 1)
1151                 printmbuf (m);
1152 #ifdef NETGRAPH
1153         m->m_pkthdr.rcvif = 0;
1154         NG_SEND_DATA_ONLY (error, d->hook, m);
1155 #else
1156         ++d->ifp->if_ipackets;
1157         m->m_pkthdr.rcvif = d->ifp;
1158         /* Check if there's a BPF listener on this interface.
1159          * If so, hand off the raw packet to bpf. */
1160         BPF_TAP (d->ifp, data, len);
1161         IF_ENQUEUE (&d->queue, m);
1162 #endif
1163 }
1164
1165 /*
1166  * Error callback function.
1167  */
1168 static void ct_error (ct_chan_t *c, int data)
1169 {
1170         drv_t *d = c->sys;
1171
1172         if (!d)
1173                 return;
1174
1175         switch (data) {
1176         case CT_FRAME:
1177                 CT_DEBUG (d, ("frame error\n"));
1178 #ifndef NETGRAPH
1179                 ++d->ifp->if_ierrors;
1180 #endif
1181                 break;
1182         case CT_CRC:
1183                 CT_DEBUG (d, ("crc error\n"));
1184 #ifndef NETGRAPH
1185                 ++d->ifp->if_ierrors;
1186 #endif
1187                 break;
1188         case CT_OVERRUN:
1189                 CT_DEBUG (d, ("overrun error\n"));
1190 #ifndef NETGRAPH
1191                 ++d->ifp->if_collisions;
1192                 ++d->ifp->if_ierrors;
1193 #endif
1194                 break;
1195         case CT_OVERFLOW:
1196                 CT_DEBUG (d, ("overflow error\n"));
1197 #ifndef NETGRAPH
1198                 ++d->ifp->if_ierrors;
1199 #endif
1200                 break;
1201         case CT_UNDERRUN:
1202                 CT_DEBUG (d, ("underrun error\n"));
1203 #ifdef NETGRAPH
1204                 d->timeout = 0;
1205 #else
1206                 ++d->ifp->if_oerrors;
1207                 d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1208                 d->ifp->if_timer = 0;
1209 #endif
1210                 ct_start (d);
1211                 break;
1212         default:
1213                 CT_DEBUG (d, ("error #%d\n", data));
1214         }
1215 }
1216
1217 static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1218 {
1219         drv_t *d;
1220
1221         if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)]))
1222                 return ENXIO;
1223                 
1224         CT_DEBUG2 (d, ("ct_open\n"));
1225         return 0;
1226 }
1227
1228 static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1229 {
1230         drv_t *d = channel [minor(dev)];
1231
1232         if (!d)
1233                 return 0;
1234
1235         CT_DEBUG2 (d, ("ct_close\n"));
1236         return 0;
1237 }
1238
1239 static int ct_modem_status (ct_chan_t *c)
1240 {
1241         drv_t *d = c->sys;
1242         bdrv_t *bd;
1243         int status, s;
1244
1245         if (!d)
1246                 return 0;
1247
1248         bd = d->bd;
1249         
1250         status = d->running ? TIOCM_LE : 0;
1251         s = splimp ();
1252         CT_LOCK (bd);
1253         if (ct_get_cd  (c)) status |= TIOCM_CD;
1254         if (ct_get_cts (c)) status |= TIOCM_CTS;
1255         if (ct_get_dsr (c)) status |= TIOCM_DSR;
1256         if (c->dtr)         status |= TIOCM_DTR;
1257         if (c->rts)         status |= TIOCM_RTS;
1258         CT_UNLOCK (bd);
1259         splx (s);
1260         return status;
1261 }
1262
1263 /*
1264  * Process an ioctl request on /dev/cronyx/ctauN.
1265  */
1266 static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1267 {
1268         drv_t *d = channel [minor (dev)];
1269         bdrv_t *bd;
1270         ct_chan_t *c;
1271         struct serial_statistics *st;
1272         struct e1_statistics *opte1;
1273         int error, s;
1274         char mask[16];
1275
1276         if (!d || !d->chan)
1277                 return 0;
1278
1279         bd = d->bd;
1280         c = d->chan;
1281
1282         switch (cmd) {
1283         case SERIAL_GETREGISTERED:
1284                 bzero (mask, sizeof(mask));
1285                 for (s=0; s<NCTAU*NCHAN; ++s)
1286                         if (channel [s])
1287                                 mask [s/8] |= 1 << (s & 7);
1288                 bcopy (mask, data, sizeof (mask));
1289                 return 0;
1290
1291 #ifndef NETGRAPH
1292         case SERIAL_GETPROTO:
1293                 strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1294                         (d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1295                 return 0;
1296
1297         case SERIAL_SETPROTO:
1298                 /* Only for superuser! */
1299                 error = priv_check (td, PRIV_DRIVER);
1300                 if (error)
1301                         return error;
1302                 if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
1303                         return EBUSY;
1304                 if (! strcmp ("cisco", (char*)data)) {
1305                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1306                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1307                         d->ifp->if_flags |= PP_CISCO;
1308                 } else if (! strcmp ("fr", (char*)data)) {
1309                         d->ifp->if_flags &= ~(PP_CISCO);
1310                         IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1311                 } else if (! strcmp ("ppp", (char*)data)) {
1312                         IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1313                         d->ifp->if_flags &= ~(PP_CISCO);
1314                 } else
1315                         return EINVAL;
1316                 return 0;
1317
1318         case SERIAL_GETKEEPALIVE:
1319                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1320                         (d->ifp->if_flags & PP_CISCO))
1321                         return EINVAL;
1322                 *(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1323                 return 0;
1324
1325         case SERIAL_SETKEEPALIVE:
1326                 /* Only for superuser! */
1327                 error = priv_check (td, PRIV_DRIVER);
1328                 if (error)
1329                         return error;
1330                 if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1331                         (d->ifp->if_flags & PP_CISCO))
1332                         return EINVAL;
1333                 if (*(int*)data)
1334                         IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1335                 else
1336                         IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1337                 return 0;
1338 #endif /*NETGRAPH*/
1339
1340         case SERIAL_GETMODE:
1341                 *(int*)data = SERIAL_HDLC;
1342                 return 0;
1343
1344         case SERIAL_GETCFG:
1345                 if (c->mode == M_HDLC)
1346                         return EINVAL;
1347                 switch (ct_get_config (c->board)) {
1348                 default:    *(char*)data = 'a'; break;
1349                 case CFG_B: *(char*)data = 'b'; break;
1350                 case CFG_C: *(char*)data = 'c'; break;
1351                 }
1352                 return 0;
1353
1354         case SERIAL_SETCFG:
1355                 /* Only for superuser! */
1356                 error = priv_check (td, PRIV_DRIVER);
1357                 if (error)
1358                         return error;
1359                 if (c->mode == M_HDLC)
1360                         return EINVAL;
1361                 s = splimp ();
1362                 CT_LOCK (bd);
1363                 switch (*(char*)data) {
1364                 case 'a': ct_set_config (c->board, CFG_A); break;
1365                 case 'b': ct_set_config (c->board, CFG_B); break;
1366                 case 'c': ct_set_config (c->board, CFG_C); break;
1367                 }
1368                 CT_UNLOCK (bd);
1369                 splx (s);
1370                 return 0;
1371
1372         case SERIAL_GETSTAT:
1373                 st = (struct serial_statistics*) data;
1374                 st->rintr  = c->rintr;
1375                 st->tintr  = c->tintr;
1376                 st->mintr  = c->mintr;
1377                 st->ibytes = c->ibytes;
1378                 st->ipkts  = c->ipkts;
1379                 st->ierrs  = c->ierrs;
1380                 st->obytes = c->obytes;
1381                 st->opkts  = c->opkts;
1382                 st->oerrs  = c->oerrs;
1383                 return 0;
1384
1385         case SERIAL_GETESTAT:
1386                 opte1 = (struct e1_statistics*)data;
1387                 opte1->status      = c->status;
1388                 opte1->cursec      = c->cursec;
1389                 opte1->totsec      = c->totsec + c->cursec;
1390
1391                 opte1->currnt.bpv   = c->currnt.bpv;
1392                 opte1->currnt.fse   = c->currnt.fse;
1393                 opte1->currnt.crce  = c->currnt.crce;
1394                 opte1->currnt.rcrce = c->currnt.rcrce;
1395                 opte1->currnt.uas   = c->currnt.uas;
1396                 opte1->currnt.les   = c->currnt.les;
1397                 opte1->currnt.es    = c->currnt.es;
1398                 opte1->currnt.bes   = c->currnt.bes;
1399                 opte1->currnt.ses   = c->currnt.ses;
1400                 opte1->currnt.oofs  = c->currnt.oofs;
1401                 opte1->currnt.css   = c->currnt.css;
1402                 opte1->currnt.dm    = c->currnt.dm;
1403
1404                 opte1->total.bpv   = c->total.bpv   + c->currnt.bpv;
1405                 opte1->total.fse   = c->total.fse   + c->currnt.fse;
1406                 opte1->total.crce  = c->total.crce  + c->currnt.crce;
1407                 opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1408                 opte1->total.uas   = c->total.uas   + c->currnt.uas;
1409                 opte1->total.les   = c->total.les   + c->currnt.les;
1410                 opte1->total.es    = c->total.es    + c->currnt.es;
1411                 opte1->total.bes   = c->total.bes   + c->currnt.bes;
1412                 opte1->total.ses   = c->total.ses   + c->currnt.ses;
1413                 opte1->total.oofs  = c->total.oofs  + c->currnt.oofs;
1414                 opte1->total.css   = c->total.css   + c->currnt.css;
1415                 opte1->total.dm    = c->total.dm    + c->currnt.dm;
1416                 for (s=0; s<48; ++s) {
1417                         opte1->interval[s].bpv   = c->interval[s].bpv;
1418                         opte1->interval[s].fse   = c->interval[s].fse;
1419                         opte1->interval[s].crce  = c->interval[s].crce;
1420                         opte1->interval[s].rcrce = c->interval[s].rcrce;
1421                         opte1->interval[s].uas   = c->interval[s].uas;
1422                         opte1->interval[s].les   = c->interval[s].les;
1423                         opte1->interval[s].es    = c->interval[s].es;
1424                         opte1->interval[s].bes   = c->interval[s].bes;
1425                         opte1->interval[s].ses   = c->interval[s].ses;
1426                         opte1->interval[s].oofs  = c->interval[s].oofs;
1427                         opte1->interval[s].css   = c->interval[s].css;
1428                         opte1->interval[s].dm    = c->interval[s].dm;
1429                 }
1430                 return 0;
1431
1432         case SERIAL_CLRSTAT:
1433                 /* Only for superuser! */
1434                 error = priv_check (td, PRIV_DRIVER);
1435                 if (error)
1436                         return error;
1437                 c->rintr = 0;
1438                 c->tintr = 0;
1439                 c->mintr = 0;
1440                 c->ibytes = 0;
1441                 c->ipkts = 0;
1442                 c->ierrs = 0;
1443                 c->obytes = 0;
1444                 c->opkts = 0;
1445                 c->oerrs = 0;
1446                 bzero (&c->currnt, sizeof (c->currnt));
1447                 bzero (&c->total, sizeof (c->total));
1448                 bzero (c->interval, sizeof (c->interval));
1449                 return 0;
1450
1451         case SERIAL_GETBAUD:
1452                 *(long*)data = ct_get_baud(c);
1453                 return 0;
1454
1455         case SERIAL_SETBAUD:
1456                 /* Only for superuser! */
1457                 error = priv_check (td, PRIV_DRIVER);
1458                 if (error)
1459                         return error;
1460                 s = splimp ();
1461                 CT_LOCK (bd);
1462                 ct_set_baud (c, *(long*)data);
1463                 CT_UNLOCK (bd);
1464                 splx (s);
1465                 return 0;
1466
1467         case SERIAL_GETLOOP:
1468                 *(int*)data = ct_get_loop (c);
1469                 return 0;
1470
1471         case SERIAL_SETLOOP:
1472                 /* Only for superuser! */
1473                 error = priv_check (td, PRIV_DRIVER);
1474                 if (error)
1475                         return error;
1476                 s = splimp ();
1477                 CT_LOCK (bd);
1478                 ct_set_loop (c, *(int*)data);
1479                 CT_UNLOCK (bd);
1480                 splx (s);
1481                 return 0;
1482
1483         case SERIAL_GETDPLL:
1484                 if (c->mode == M_E1 || c->mode == M_G703)
1485                         return EINVAL;
1486                 *(int*)data = ct_get_dpll (c);
1487                 return 0;
1488
1489         case SERIAL_SETDPLL:
1490                 /* Only for superuser! */
1491                 error = priv_check (td, PRIV_DRIVER);
1492                 if (error)
1493                         return error;
1494                 if (c->mode == M_E1 || c->mode == M_G703)
1495                         return EINVAL;
1496                 s = splimp ();
1497                 CT_LOCK (bd);
1498                 ct_set_dpll (c, *(int*)data);
1499                 CT_UNLOCK (bd);
1500                 splx (s);
1501                 return 0;
1502
1503         case SERIAL_GETNRZI:
1504                 if (c->mode == M_E1 || c->mode == M_G703)
1505                         return EINVAL;
1506                 *(int*)data = ct_get_nrzi (c);
1507                 return 0;
1508
1509         case SERIAL_SETNRZI:
1510                 /* Only for superuser! */
1511                 error = priv_check (td, PRIV_DRIVER);
1512                 if (error)
1513                         return error;
1514                 if (c->mode == M_E1 || c->mode == M_G703)
1515                         return EINVAL;
1516                 s = splimp ();
1517                 CT_LOCK (bd);
1518                 ct_set_nrzi (c, *(int*)data);
1519                 CT_UNLOCK (bd);
1520                 splx (s);
1521                 return 0;
1522
1523         case SERIAL_GETDEBUG:
1524                 *(int*)data = c->debug;
1525                 return 0;
1526
1527         case SERIAL_SETDEBUG:
1528                 /* Only for superuser! */
1529                 error = priv_check (td, PRIV_DRIVER);
1530                 if (error)
1531                         return error;
1532 #ifndef NETGRAPH
1533                 /*
1534                  * The debug_shadow is always greater than zero for logic 
1535                  * simplicity.  For switching debug off the IFF_DEBUG is
1536                  * responsible.
1537                  */
1538                 c->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
1539                 if (d->ifp->if_flags & IFF_DEBUG)
1540                         c->debug = c->debug_shadow;
1541 #else
1542                 c->debug = *(int*)data;
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 (ct_mpsafenet)
2215                 ct_cdevsw.d_flags &= ~D_NEEDGIANT;
2216
2217         switch (type) {
2218         case MOD_LOAD:
2219 #ifdef NETGRAPH
2220                 if (ng_newtype (&typestruct))
2221                         printf ("Failed to register ng_ct\n");
2222 #endif
2223                 ++load_count;
2224                 callout_init (&timeout_handle, ct_mpsafenet?CALLOUT_MPSAFE:0);
2225                 callout_reset (&timeout_handle, hz*5, ct_timeout, 0);
2226                 break;
2227         case MOD_UNLOAD:
2228                 if (load_count == 1) {
2229                         printf ("Removing device entry for Tau-ISA\n");
2230 #ifdef NETGRAPH
2231                         ng_rmtype (&typestruct);
2232 #endif                  
2233                 }
2234                 /* If we were wait it than it reasserted now, just stop it. */
2235                 if (!callout_drain (&timeout_handle))
2236                         callout_stop (&timeout_handle);
2237                 --load_count;
2238                 break;
2239         case MOD_SHUTDOWN:
2240                 break;
2241         }
2242         return 0;
2243 }
2244
2245 #ifdef NETGRAPH
2246 static struct ng_type typestruct = {
2247         .version        = NG_ABI_VERSION,
2248         .name           = NG_CT_NODE_TYPE,
2249         .constructor    = ng_ct_constructor,
2250         .rcvmsg         = ng_ct_rcvmsg,
2251         .shutdown       = ng_ct_rmnode,
2252         .newhook        = ng_ct_newhook,
2253         .connect        = ng_ct_connect,
2254         .rcvdata        = ng_ct_rcvdata,
2255         .disconnect     = ng_ct_disconnect,
2256 };
2257 #endif /*NETGRAPH*/
2258
2259 #ifdef NETGRAPH
2260 MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2261 #else
2262 MODULE_DEPEND (ct, sppp, 1, 1, 1);
2263 #endif
2264 DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2265 MODULE_VERSION (ct, 1);