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