Deleted Added
full compact
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.22 2004/02/26 19:06:51 rik Exp $
22 */
23#include <sys/cdefs.h>
24__FBSDID("$FreeBSD: head/sys/dev/ctau/if_ct.c 130585 2004-06-16 09:47:26Z phk $");
24__FBSDID("$FreeBSD: head/sys/dev/ctau/if_ct.c 130640 2004-06-17 17:16:53Z phk $");
25
26#include <sys/param.h>
27
28#if __FreeBSD_version >= 500000
29# define NCTAU 1
30#else
31# include "ctau.h"
32#endif
33
34#if NCTAU > 0
35#include <sys/proc.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/mbuf.h>
40#include <sys/sockio.h>
41#include <sys/malloc.h>
42#include <sys/socket.h>
43#include <sys/conf.h>
44#include <sys/errno.h>
45#include <sys/tty.h>
46#if __FreeBSD_version >= 400000
47# include <sys/bus.h>
48# include <machine/bus.h>
49# include <sys/rman.h>
50# include <isa/isavar.h>
51#endif
52#include <sys/interrupt.h>
53#include <vm/vm.h>
54#include <vm/pmap.h>
55#include <net/if.h>
56#include <machine/cpufunc.h>
57#include <machine/cserial.h>
58#include <machine/clock.h>
59#if __FreeBSD_version < 500000
60#include <i386/isa/isa_device.h>
61#endif
62#if __FreeBSD_version >= 400000
63#include <machine/resource.h>
64# if __FreeBSD_version <= 501000
65# include <i386/isa/intr_machdep.h>
66# endif
67#endif
68#if __FreeBSD_version >= 400000
69#include <dev/cx/machdep.h>
70#include <dev/ctau/ctddk.h>
71#include <dev/cx/cronyxfw.h>
72#else
73#include <i386/isa/cronyx/machdep.h>
74#include <i386/isa/cronyx/ctddk.h>
75#include <i386/isa/cronyx/cronyxfw.h>
76#endif
77#include "opt_ng_cronyx.h"
78#ifdef NETGRAPH_CRONYX
79# include "opt_netgraph.h"
80# include <netgraph/ng_message.h>
81# include <netgraph/netgraph.h>
82#if __FreeBSD_version >= 400000
83# include <dev/ctau/ng_ct.h>
84#else
85# include <netgraph/ng_ct.h>
86#endif
87#else
88# include <net/if_types.h>
89# if __FreeBSD_version < 500000
90# include "sppp.h"
91# if NSPPP <= 0
92# error The device ctau requires sppp or netgraph.
93# endif
94# endif
95# include <net/if_sppp.h>
96# define PP_CISCO IFF_LINK2
97#if __FreeBSD_version < 400000
98# include <bpfilter.h>
99# if NBPFILTER > 0
100# include <net/bpf.h>
101# endif
102#else
103# if __FreeBSD_version < 500000
104# include <bpf.h>
105# endif
106# include <net/bpf.h>
107# define NBPFILTER NBPF
108#endif
109#endif
110
111/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
112#ifndef PP_FR
113#define PP_FR 0
114#endif
115
116#define CT_DEBUG(d,s) ({if (d->chan->debug) {\
117 printf ("%s: ", d->name); printf s;}})
118#define CT_DEBUG2(d,s) ({if (d->chan->debug>1) {\
119 printf ("%s: ", d->name); printf s;}})
120#define CDEV_MAJOR 99
121
122#if __FreeBSD_version >= 400000
123static void ct_identify __P((driver_t *, device_t));
124static int ct_probe __P((device_t));
125static int ct_attach __P((device_t));
126static int ct_detach __P((device_t));
127
128static device_method_t ct_isa_methods [] = {
129 DEVMETHOD(device_identify, ct_identify),
130 DEVMETHOD(device_probe, ct_probe),
131 DEVMETHOD(device_attach, ct_attach),
132 DEVMETHOD(device_detach, ct_detach),
133 {0, 0}
134};
135
136typedef struct _bdrv_t {
137 ct_board_t *board;
138 struct resource *base_res;
139 struct resource *drq_res;
140 struct resource *irq_res;
141 int base_rid;
142 int drq_rid;
143 int irq_rid;
144 void *intrhand;
145} bdrv_t;
146
147static driver_t ct_isa_driver = {
148 "ct",
149 ct_isa_methods,
150 sizeof (bdrv_t),
151};
152
153static devclass_t ct_devclass;
154#endif
155
156typedef struct _drv_t {
157 char name [8];
158 ct_chan_t *chan;
159 ct_board_t *board;
160 ct_buf_t buf;
161 int running;
162#ifdef NETGRAPH
163 char nodename [NG_NODELEN+1];
164 hook_p hook;
165 hook_p debug_hook;
166 node_p node;
167 struct ifqueue queue;
168 struct ifqueue hi_queue;
169 short timeout;
170 struct callout_handle timeout_handle;
171#else
172 struct sppp pp;
173#endif
174#if __FreeBSD_version >= 400000
175 struct cdev *devt;
176#endif
177} drv_t;
178
179static void ct_receive (ct_chan_t *c, char *data, int len);
180static void ct_transmit (ct_chan_t *c, void *attachment, int len);
181static void ct_error (ct_chan_t *c, int data);
182static void ct_up (drv_t *d);
183static void ct_start (drv_t *d);
184static void ct_down (drv_t *d);
185static void ct_watchdog (drv_t *d);
186#ifdef NETGRAPH
187extern struct ng_type typestruct;
188#else
189static void ct_ifstart (struct ifnet *ifp);
190static void ct_tlf (struct sppp *sp);
191static void ct_tls (struct sppp *sp);
192static void ct_ifwatchdog (struct ifnet *ifp);
193static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
194static void ct_initialize (void *softc);
195#endif
196
197static ct_board_t *adapter [NCTAU];
198static drv_t *channel [NCTAU*NCHAN];
199static struct callout_handle led_timo [NCTAU];
200static struct callout_handle timeout_handle;
201
202/*
203 * Print the mbuf chain, for debug purposes only.
204 */
205static void printmbuf (struct mbuf *m)
206{
207 printf ("mbuf:");
208 for (; m; m=m->m_next) {
209 if (m->m_flags & M_PKTHDR)
210 printf (" HDR %d:", m->m_pkthdr.len);
211 if (m->m_flags & M_EXT)
212 printf (" EXT:");
213 printf (" %d", m->m_len);
214 }
215 printf ("\n");
216}
217
218/*
219 * Make an mbuf from data.
220 */
221static struct mbuf *makembuf (void *buf, u_int len)
222{
223 struct mbuf *m;
224
225 MGETHDR (m, M_DONTWAIT, MT_DATA);
226 if (! m)
227 return 0;
228 MCLGET (m, M_DONTWAIT);
229 if (! (m->m_flags & M_EXT)) {
230 m_freem (m);
231 return 0;
232 }
233 m->m_pkthdr.len = m->m_len = len;
234 bcopy (buf, mtod (m, caddr_t), len);
235 return m;
236}
237
238static void ct_timeout (void *arg)
239{
240 drv_t *d;
241 int s, i;
242
243 for (i=0; i<NCTAU*NCHAN; ++i) {
244 d = channel[i];
245 if (! d)
246 continue;
247 if (d->chan->mode != M_G703)
248 continue;
249 s = splimp ();
250 ct_g703_timer (d->chan);
251 splx (s);
252 }
253 timeout_handle = timeout (ct_timeout, 0, hz);
254}
255
256static void ct_led_off (void *arg)
257{
258 ct_board_t *b = arg;
259 int s = splimp ();
260
261 ct_led (b, 0);
262 led_timo[b->num].callout = 0;
263 splx (s);
264}
265
266/*
267 * Activate interupt handler from DDK.
268 */
269#if __FreeBSD_version >= 400000
270static void ct_intr (void *arg)
271{
272 bdrv_t *bd = arg;
273 ct_board_t *b = bd->board;
274#else
275static void ct_intr (int bnum)
276{
277 ct_board_t *b = adapter [bnum];
278#endif
279 int s = splimp ();
280
281 /* Turn LED on. */
282 ct_led (b, 1);
283
284 ct_int_handler (b);
285
286 /* Turn LED off 50 msec later. */
287 if (! led_timo[b->num].callout)
288 led_timo[b->num] = timeout (ct_led_off, b, hz/20);
289 splx (s);
290}
291
292static int probe_irq (ct_board_t *b, int irq)
293{
294 int mask, busy, cnt;
295
296 /* Clear pending irq, if any. */
297 ct_probe_irq (b, -irq);
298 DELAY (100);
299 for (cnt=0; cnt<5; ++cnt) {
300 /* Get the mask of pending irqs, assuming they are busy.
301 * Activate the adapter on given irq. */
302 busy = ct_probe_irq (b, irq);
303 DELAY (1000);
304
305 /* Get the mask of active irqs.
306 * Deactivate our irq. */
307 mask = ct_probe_irq (b, -irq);
308 DELAY (100);
309 if ((mask & ~busy) == 1 << irq) {
310 ct_probe_irq (b, 0);
311 /* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
312 b->num, irq, mask, busy); */
313 return 1;
314 }
315 }
316 /* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
317 b->num, irq, mask, busy); */
318 ct_probe_irq (b, 0);
319 return 0;
320}
321
322static short porttab [] = {
323 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
324 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
325 };
326static char dmatab [] = { 7, 6, 5, 0 };
327static char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
328
329#if __FreeBSD_version >= 400000
330static int ct_is_free_res (device_t dev, int rid, int type, u_long start,
331 u_long end, u_long count)
332{
333 struct resource *res;
334
335 if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
336 RF_ALLOCATED)))
337 return 0;
338
339 bus_release_resource (dev, type, rid, res);
340
341 return 1;
342}
343
344static void ct_identify (driver_t *driver, device_t dev)
345{
346 u_long iobase, rescount;
347 int devcount;
348 device_t *devices;
349 device_t child;
350 devclass_t my_devclass;
351 int i, k;
352
353 if ((my_devclass = devclass_find ("ct")) == NULL)
354 return;
355
356 devclass_get_devices (my_devclass, &devices, &devcount);
357
358 if (devcount == 0) {
359 /* We should find all devices by our self. We could alter other
360 * devices, but we don't have a choise
361 */
362 for (i = 0; (iobase = porttab [i]) != 0; i++) {
363 if (!ct_is_free_res (dev, 1, SYS_RES_IOPORT,
364 iobase, iobase + NPORT, NPORT))
365 continue;
366 if (ct_probe_board (iobase, -1, -1) == 0)
367 continue;
368
369 devcount++;
370 child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct",
371 -1);
372
373 if (child == NULL)
374 return;
375
376 device_set_desc_copy (child, "Cronyx Tau-ISA");
377 device_set_driver (child, driver);
378 bus_set_resource (child, SYS_RES_IOPORT, 0,
379 iobase, NPORT);
380
381 if (devcount >= NCTAU)
382 break;
383 }
384 } else {
385 static short porttab [] = {
386 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
387 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
388 };
389 /* Lets check user choise.
390 */
391 for (k = 0; k < devcount; k++) {
392 if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
393 &iobase, &rescount) != 0)
394 continue;
395
396 for (i = 0; porttab [i] != 0; i++) {
397 if (porttab [i] != iobase)
398 continue;
399
400 if (!ct_is_free_res (devices[k], 1, SYS_RES_IOPORT,
401 iobase, iobase + NPORT, NPORT))
402 continue;
403
404 if (ct_probe_board (iobase, -1, -1) == 0)
405 continue;
406 porttab [i] = -1;
407 device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
408 break;
409 }
410 if (porttab [i] == 0) {
411 device_delete_child (
412 device_get_parent (devices[k]),
413 devices [k]);
414 devices[k] = 0;
415 continue;
416 }
417 }
418 for (k = 0; k < devcount; k++) {
419 if (devices[k] == 0)
420 continue;
421 if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
422 &iobase, &rescount) == 0)
423 continue;
424 for (i = 0; (iobase = porttab [i]) != 0; i++) {
425 if (porttab [i] == -1)
426 continue;
427 if (!ct_is_free_res (devices[k], 1, SYS_RES_IOPORT,
428 iobase, iobase + NPORT, NPORT))
429 continue;
430 if (ct_probe_board (iobase, -1, -1) == 0)
431 continue;
432
433 bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
434 iobase, NPORT);
435 porttab [i] = -1;
436 device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
437 break;
438 }
439 if (porttab [i] == 0) {
440 device_delete_child (
441 device_get_parent (devices[k]),
442 devices [k]);
443 }
444 }
445 free (devices, M_TEMP);
446 }
447
448 return;
449}
450
451static int ct_probe (device_t dev)
452{
453 int unit = device_get_unit (dev);
454 u_long iobase, rescount;
455
456 if (!device_get_desc (dev) ||
457 strcmp (device_get_desc (dev), "Cronyx Tau-ISA"))
458 return ENXIO;
459
460/* KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/
461 if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
462 printf ("ct%d: Couldn't get IOPORT\n", unit);
463 return ENXIO;
464 }
465
466 if (!ct_is_free_res (dev, 1, SYS_RES_IOPORT,
467 iobase, iobase + NPORT, NPORT)) {
468 printf ("ct%d: Resource IOPORT isn't free\n", unit);
469 return ENXIO;
470 }
471
472 if (!ct_probe_board (iobase, -1, -1)) {
473 printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
474 return ENXIO;
475 }
476
477 return 0;
478}
479#else /* __FreeBSD_version < 400000 */
480static int ct_probe (struct isa_device *id)
481{
482 int unit = id->id_unit;
483 int iobase;
484 ct_board_t *b;
485 int i;
486
487 iobase = id->id_iobase;
488 if (iobase < 0) {
489 /* Autodetect the adapter. */
490
491 for (i=0; ; i++) {
492 if (! porttab[i]) {
493 iobase = -1;
494 return 0;
495 }
496 iobase = porttab[i];
497 if (unit > 0 && adapter[0] && adapter[0]->port == iobase)
498 continue;
499 if (unit > 1 && adapter[1] && adapter[1]->port == iobase)
500 continue;
501 if (! haveseen_isadev (id, CC_IOADDR | CC_QUIET) &&
502 ct_probe_board (iobase, -1, -1))
503 break;
504 }
505 } else if (! ct_probe_board (iobase, -1, -1))
506 return 0;
507
508 if (id->id_drq < 0) {
509 /* Find available 16-bit DRQ. */
510
511 for (i=0; ; ++i) {
512 if (! dmatab[i]) {
513 printf ("ct%d: no available drq found\n",
514 unit);
515 id->id_drq = -1;
516 return 0;
517 }
518 id->id_drq = dmatab[i];
519 if (! haveseen_isadev (id, CC_DRQ | CC_QUIET)
520 && !isa_dma_acquire (id->id_drq))
521 break;
522 }
523 }
524
525 b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
526 if (!b) {
527 printf ("ct:%d: Couldn't allocate memory\n", unit);
528 return (ENXIO);
529 }
530 adapter[unit] = b;
531 bzero (b, sizeof(ct_board_t));
532
533 if (! ct_open_board (b, unit, iobase,
534 id->id_irq ? ffs (id->id_irq) - 1 : -1, id->id_drq)) {
535 printf ("ct%d: error loading firmware\n", unit);
536 adapter [unit] = 0;
537 free (b, M_DEVBUF);
538 isa_dma_release (id->id_drq);
539 return 0;
540 }
541
542 if (id->id_irq) {
543 if (! probe_irq (b, ffs (id->id_irq) - 1))
544 printf ("ct%d: irq %d not functional\n",
545 unit, ffs (id->id_irq) - 1);
546 } else {
547 /* Find available IRQ. */
548
549 for (i=0; ; ++i) {
550 if (! irqtab[i]) {
551 printf ("ct%d: no available irq found\n",
552 unit);
553 id->id_irq = -1;
554 isa_dma_release (id->id_drq);
555 adapter [unit] = 0;
556 free (b, M_DEVBUF);
557 return 0;
558 }
559 id->id_irq = 1 << irqtab[i];
560 if (haveseen_isadev (id, CC_IRQ | CC_QUIET))
561 continue;
562#ifdef KLD_MODULE
563 if (register_intr (irqtab[i], 0, 0, (inthand2_t*)
564 ct_intr, &net_imask, unit) != 0)
565 continue;
566 unregister_intr (irqtab[i], (inthand2_t*) ct_intr);
567#endif
568 if (probe_irq (b, irqtab[i]))
569 break;
570 }
571 }
572 ct_init_board (b, b->num, b->port, ffs (id->id_irq) - 1, b->dma,
573 b->type, b->osc);
574 ct_setup_board (b, 0, 0, 0);
575
576 return 1;
577}
578#endif /* __FreeBSD_version < 400000 */
579
580extern struct cdevsw ct_cdevsw;
581/*
582 * The adapter is present, initialize the driver structures.
583 */
584#if __FreeBSD_version < 400000
585static int ct_attach (struct isa_device *id)
586{
587#else
588static int ct_attach (device_t dev)
589{
590 bdrv_t *bd = device_get_softc (dev);
591 u_long iobase, drq, irq, rescount;
592 int unit = device_get_unit (dev);
593 int i;
594 int s;
595#endif
596 ct_board_t *b;
597 ct_chan_t *c;
598 drv_t *d;
599
600#if __FreeBSD_version >= 400000
601 KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));
602
603 bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
604 bd->base_rid = 0;
605 bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
606 iobase, iobase + NPORT, NPORT, RF_ACTIVE);
607 if (! bd->base_res) {
608 printf ("ct%d: cannot alloc base address\n", unit);
609 return ENXIO;
610 }
611
612 if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
613 for (i = 0; (drq = dmatab [i]) != 0; i++) {
614 if (!ct_is_free_res (dev, 1, SYS_RES_DRQ,
615 drq, drq + 1, 1))
616 continue;
617 bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
618 break;
619 }
620
621 if (dmatab[i] == 0) {
622 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
623 bd->base_res);
624 printf ("ct%d: Couldn't get DRQ\n", unit);
625 return ENXIO;
626 }
627 }
628
629 bd->drq_rid = 0;
630 bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
631 drq, drq + 1, 1, RF_ACTIVE);
632 if (! bd->drq_res) {
633 printf ("ct%d: cannot allocate drq\n", unit);
634 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
635 bd->base_res);
636 return ENXIO;
637 }
638
639 if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
640 for (i = 0; (irq = irqtab [i]) != 0; i++) {
641 if (!ct_is_free_res (dev, 1, SYS_RES_IRQ,
642 irq, irq + 1, 1))
643 continue;
644 bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
645 break;
646 }
647
648 if (irqtab[i] == 0) {
649 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
650 bd->drq_res);
651 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
652 bd->base_res);
653 printf ("ct%d: Couldn't get IRQ\n", unit);
654 return ENXIO;
655 }
656 }
657
658 bd->irq_rid = 0;
659 bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
660 irq, irq + 1, 1, RF_ACTIVE);
661 if (! bd->irq_res) {
662 printf ("ct%d: Couldn't allocate irq\n", unit);
663 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
664 bd->drq_res);
665 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
666 bd->base_res);
667 return ENXIO;
668 }
669
670 b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
671 if (!b) {
672 printf ("ct:%d: Couldn't allocate memory\n", unit);
673 return (ENXIO);
674 }
675 adapter[unit] = b;
676 bzero (b, sizeof(ct_board_t));
677
678 if (! ct_open_board (b, unit, iobase, irq, drq)) {
679 printf ("ct%d: error loading firmware\n", unit);
680 free (b, M_DEVBUF);
681 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
682 bd->irq_res);
683 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
684 bd->drq_res);
685 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
686 bd->base_res);
687 return ENXIO;
688 }
689
690 bd->board = b;
691
692 if (! probe_irq (b, irq)) {
693 printf ("ct%d: irq %ld not functional\n", unit, irq);
694 bd->board = 0;
695 adapter [unit] = 0;
696 free (b, M_DEVBUF);
697 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
698 bd->irq_res);
699 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
700 bd->drq_res);
701 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
702 bd->base_res);
703 return ENXIO;
704 }
705
706 s = splimp ();
707 if (bus_setup_intr (dev, bd->irq_res, INTR_TYPE_NET, ct_intr, bd,
708 &bd->intrhand)) {
709 printf ("ct%d: Can't setup irq %ld\n", unit, irq);
710 bd->board = 0;
711 adapter [unit] = 0;
712 free (b, M_DEVBUF);
713 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
714 bd->irq_res);
715 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
716 bd->drq_res);
717 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
718 bd->base_res);
719 splx (s);
720 return ENXIO;
721 }
722
723 ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc);
724 ct_setup_board (b, 0, 0, 0);
725#else
726 b = adapter [id->id_unit];
727#endif
728
729 printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name,
730 b->osc == 20000000 ? "20" : "16.384");
731#if __FreeBSD_version < 400000
732 id->id_ointr = ct_intr;
733#endif
734
735 for (c=b->chan; c<b->chan+NCHAN; ++c) {
736 d = contigmalloc (sizeof(drv_t), M_DEVBUF, M_WAITOK,
737 0x100000, 0x1000000, 16, 0);
738 channel [b->num*NCHAN + c->num] = d;
739 bzero (d, sizeof(drv_t));
740 sprintf (d->name, "ct%d.%d", b->num, c->num);
741 d->board = b;
742 d->chan = c;
743 c->sys = d;
744
745#ifdef NETGRAPH
746 if (ng_make_node_common (&typestruct, &d->node) != 0) {
747 printf ("%s: cannot make common node\n", d->name);
748 channel [b->num*NCHAN + c->num] = 0;
749 c->sys = 0;
750#if __FreeBSD_version < 400000
751 free (d, M_DEVBUF);
752#else
753 contigfree (d, sizeof (*d), M_DEVBUF);
754#endif
755 continue;
756 }
757#if __FreeBSD_version >= 500000
758 NG_NODE_SET_PRIVATE (d->node, d);
759#else
760 d->node->private = d;
761#endif
762 sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE,
763 c->board->num*NCHAN + c->num);
764 if (ng_name_node (d->node, d->nodename)) {
765 printf ("%s: cannot name node\n", d->nodename);
766#if __FreeBSD_version >= 500000
767 NG_NODE_UNREF (d->node);
768#else
769 ng_rmnode (d->node);
770 ng_unref (d->node);
771#endif
772 channel [b->num*NCHAN + c->num] = 0;
773 c->sys = 0;
774#if __FreeBSD_version < 400000
775 free (d, M_DEVBUF);
776#else
777 contigfree (d, sizeof (*d), M_DEVBUF);
778#endif
779 continue;
780 }
781 d->queue.ifq_maxlen = IFQ_MAXLEN;
782 d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
783#if __FreeBSD_version >= 500000
784 mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
785 mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF);
786#endif
787#else /*NETGRAPH*/
788 d->pp.pp_if.if_softc = d;
789#if __FreeBSD_version > 501000
790 if_initname (&d->pp.pp_if, "ct", b->num * NCHAN + c->num);
791#else
792 d->pp.pp_if.if_unit = b->num * NCHAN + c->num;
793 d->pp.pp_if.if_name = "ct";
794#endif
795 d->pp.pp_if.if_mtu = PP_MTU;
796 d->pp.pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
797 d->pp.pp_if.if_ioctl = ct_sioctl;
798 d->pp.pp_if.if_start = ct_ifstart;
799 d->pp.pp_if.if_watchdog = ct_ifwatchdog;
800 d->pp.pp_if.if_init = ct_initialize;
801 sppp_attach (&d->pp.pp_if);
802 if_attach (&d->pp.pp_if);
803 d->pp.pp_tlf = ct_tlf;
804 d->pp.pp_tls = ct_tls;
805#if __FreeBSD_version >= 400000 || NBPFILTER > 0
806 /* If BPF is in the kernel, call the attach for it.
807 * Header size is 4 bytes. */
808 bpfattach (&d->pp.pp_if, DLT_PPP, 4);
809#endif
810#endif /*NETGRAPH*/
811 ct_start_chan (c, &d->buf, vtophys (&d->buf));
812 ct_register_receive (c, &ct_receive);
813 ct_register_transmit (c, &ct_transmit);
814 ct_register_error (c, &ct_error);
815#if __FreeBSD_version >= 400000
816 d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
817 GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num);
818 }
819 splx (s);
820
821 return 0;
822#else /* __FreeBSD_version < 400000 */
823 }
824 return 1;
825#endif /*__FreeBSD_version */
826}
827
828#if __FreeBSD_version >= 400000
829static int ct_detach (device_t dev)
830{
831 bdrv_t *bd = device_get_softc (dev);
832 ct_board_t *b = bd->board;
833 ct_chan_t *c;
834 int s = splimp ();
835
836 /* Check if the device is busy (open). */
837 for (c = b->chan; c < b->chan + NCHAN; ++c) {
838 drv_t *d = (drv_t*) c->sys;
839
840 if (!d || !d->chan->type)
841 continue;
842
843 if (d->running) {
844 splx (s);
845 return EBUSY;
846 }
847 }
848
849 /* Deactivate the timeout routine. */
850 if (led_timo[b->num].callout)
851 untimeout (ct_led_off, b, led_timo[b->num]);
852
853 bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
854 bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
855 bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
856
857 bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
858 bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
859
860 bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res);
861 bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
862
863 ct_close_board (b);
864
865 /* Detach the interfaces, free buffer memory. */
866 for (c = b->chan; c < b->chan + NCHAN; ++c) {
867 drv_t *d = (drv_t*) c->sys;
868
869 if (!d || !d->chan->type)
870 continue;
871
872#ifdef NETGRAPH
873#if __FreeBSD_version >= 500000
874 if (d->node) {
875 ng_rmnode_self (d->node);
876 NG_NODE_UNREF (d->node);
877 d->node = NULL;
878 }
879 mtx_destroy (&d->queue.ifq_mtx);
880 mtx_destroy (&d->hi_queue.ifq_mtx);
881#else
882 ng_rmnode (d->node);
883 d->node = 0;
884#endif
885#else
886#if __FreeBSD_version >= 410000 && NBPFILTER > 0
887 /* Detach from the packet filter list of interfaces. */
888 bpfdetach (&d->pp.pp_if);
889#endif
890 /* Detach from the sync PPP list. */
891 sppp_detach (&d->pp.pp_if);
892
893 if_detach (&d->pp.pp_if);
894#endif
895 destroy_dev (d->devt);
896 }
897
898 ct_led_off (b);
899 if (led_timo[b->num].callout)
900 untimeout (ct_led_off, b, led_timo[b->num]);
901 splx (s);
902
903 s = splimp ();
904 for (c = b->chan; c < b->chan + NCHAN; ++c) {
905 drv_t *d = (drv_t*) c->sys;
906
907 if (!d || !d->chan->type)
908 continue;
909
910 /* Deallocate buffers. */
911#if __FreeBSD_version < 400000
912 free (d, M_DEVBUF);
913#else
914 contigfree (d, sizeof (*d), M_DEVBUF);
915#endif
916 }
917 bd->board = 0;
918 adapter [b->num] = 0;
919 free (b, M_DEVBUF);
920 splx (s);
921
922 return 0;
923}
924#endif
925
926#ifndef NETGRAPH
927static void ct_ifstart (struct ifnet *ifp)
928{
929 drv_t *d = ifp->if_softc;
930
931 ct_start (d);
932}
933
934static void ct_ifwatchdog (struct ifnet *ifp)
935{
936 drv_t *d = ifp->if_softc;
937
938 ct_watchdog (d);
939}
940
941static void ct_tlf (struct sppp *sp)
942{
943 drv_t *d = sp->pp_if.if_softc;
944
945 CT_DEBUG (d, ("ct_tlf\n"));
946/* ct_set_dtr (d->chan, 0);*/
947/* ct_set_rts (d->chan, 0);*/
948 sp->pp_down (sp);
949}
950
951static void ct_tls (struct sppp *sp)
952{
953 drv_t *d = sp->pp_if.if_softc;
954
955 CT_DEBUG (d, ("ct_tls\n"));
956 sp->pp_up (sp);
957}
958
959/*
960 * Initialization of interface.
961 * Ii seems to be never called by upper level.
962 */
963static void ct_initialize (void *softc)
964{
965 drv_t *d = softc;
966
967 CT_DEBUG (d, ("ct_initialize\n"));
968}
969
970/*
971 * Process an ioctl request.
972 */
973static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
974{
975 drv_t *d = ifp->if_softc;
976 int error, s, was_up, should_be_up;
977
978 was_up = (ifp->if_flags & IFF_RUNNING) != 0;
979 error = sppp_ioctl (ifp, cmd, data);
980 if (error)
981 return error;
982
983 if (! (ifp->if_flags & IFF_DEBUG))
984 d->chan->debug = 0;
985 else if (! d->chan->debug)
986 d->chan->debug = 1;
987
988 switch (cmd) {
989 default: CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
990 case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n")); return 0;
991 case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n")); return 0;
992 case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n")); break;
993 case SIOCSIFADDR: CT_DEBUG2 (d, ("SIOCSIFADDR\n")); break;
994 }
995
996 /* We get here only in case of SIFFLAGS or SIFADDR. */
997 s = splimp ();
998 should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
999 if (! was_up && should_be_up) {
1000 /* Interface goes up -- start it. */
1001 ct_up (d);
1002 ct_start (d);
1003 } else if (was_up && ! should_be_up) {
1004 /* Interface is going down -- stop it. */
1005 /* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
1006 ct_down (d);
1007 }
1008 splx (s);
1009 return 0;
1010}
1011#endif /*NETGRAPH*/
1012
1013/*
1014 * Stop the interface. Called on splimp().
1015 */
1016static void ct_down (drv_t *d)
1017{
1018 int s = splimp ();
1019 CT_DEBUG (d, ("ct_down\n"));
1020 ct_set_dtr (d->chan, 0);
1021 ct_set_rts (d->chan, 0);
1022 d->running = 0;
1023 splx (s);
1024}
1025
1026/*
1027 * Start the interface. Called on splimp().
1028 */
1029static void ct_up (drv_t *d)
1030{
1031 int s = splimp ();
1032 CT_DEBUG (d, ("ct_up\n"));
1033 ct_set_dtr (d->chan, 1);
1034 ct_set_rts (d->chan, 1);
1035 d->running = 1;
1036 splx (s);
1037}
1038
1039/*
1040 * Start output on the (slave) interface. Get another datagram to send
1041 * off of the interface queue, and copy it to the interface
1042 * before starting the output.
1043 */
1044static void ct_send (drv_t *d)
1045{
1046 struct mbuf *m;
1047 u_short len;
1048
1049 CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
1050
1051 /* No output if the interface is down. */
1052 if (! d->running)
1053 return;
1054
1055 /* No output if the modem is off. */
1056 if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
1057 return;
1058
1059 while (ct_buf_free (d->chan)) {
1060 /* Get the packet to send. */
1061#ifdef NETGRAPH
1062 IF_DEQUEUE (&d->hi_queue, m);
1063 if (! m)
1064 IF_DEQUEUE (&d->queue, m);
1065#else
1066 m = sppp_dequeue (&d->pp.pp_if);
1067#endif
1068 if (! m)
1069 return;
1070#if (__FreeBSD_version >= 400000 || NBPFILTER > 0) && !defined (NETGRAPH)
1071 if (d->pp.pp_if.if_bpf)
1072#if __FreeBSD_version >= 500000
1073 BPF_MTAP (&d->pp.pp_if, m);
1074#else
1075 bpf_mtap (&d->pp.pp_if, m);
1076#endif
1077#endif
1078 len = m->m_pkthdr.len;
1079 if (! m->m_next)
1080 ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
1081 len, 0);
1082 else {
1083 m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
1084 ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
1085 len, 0);
1086 }
1087 m_freem (m);
1088
1089 /* Set up transmit timeout, if the transmit ring is not empty.
1090 * Transmit timeout is 10 seconds. */
1091#ifdef NETGRAPH
1092 d->timeout = 10;
1093#else
1094 d->pp.pp_if.if_timer = 10;
1095#endif
1096 }
1097#ifndef NETGRAPH
1098 d->pp.pp_if.if_flags |= IFF_OACTIVE;
1099#endif
1100}
1101
1102/*
1103 * Start output on the interface.
1104 * Always called on splimp().
1105 */
1106static void ct_start (drv_t *d)
1107{
1108 int s = splimp ();
1109
1110 if (d->running) {
1111 if (! d->chan->dtr)
1112 ct_set_dtr (d->chan, 1);
1113 if (! d->chan->rts)
1114 ct_set_rts (d->chan, 1);
1115 ct_send (d);
1116 }
1117
1118 splx (s);
1119}
1120
1121/*
1122 * Handle transmit timeouts.
1123 * Recover after lost transmit interrupts.
1124 * Always called on splimp().
1125 */
1126static void ct_watchdog (drv_t *d)
1127{
1128 int s = splimp ();
1129
1130 CT_DEBUG (d, ("device timeout\n"));
1131 if (d->running) {
1132 ct_setup_chan (d->chan);
1133 ct_start_chan (d->chan, 0, 0);
1134 ct_set_dtr (d->chan, 1);
1135 ct_set_rts (d->chan, 1);
1136 ct_start (d);
1137 }
1138
1139 splx (s);
1140}
1141
1142/*
1143 * Transmit callback function.
1144 */
1145static void ct_transmit (ct_chan_t *c, void *attachment, int len)
1146{
1147 drv_t *d = c->sys;
1148
1149 if (!d)
1150 return;
1151#ifdef NETGRAPH
1152 d->timeout = 0;
1153#else
1154 ++d->pp.pp_if.if_opackets;
1155 d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1156 d->pp.pp_if.if_timer = 0;
1157#endif
1158 ct_start (d);
1159}
1160
1161/*
1162 * Process the received packet.
1163 */
1164static void ct_receive (ct_chan_t *c, char *data, int len)
1165{
1166 drv_t *d = c->sys;
1167 struct mbuf *m;
1168#if __FreeBSD_version >= 500000 && defined NETGRAPH
1169 int error;
1170#endif
1171
1172 if (!d || !d->running)
1173 return;
1174
1175 m = makembuf (data, len);
1176 if (! m) {
1177 CT_DEBUG (d, ("no memory for packet\n"));
1178#ifndef NETGRAPH
1179 ++d->pp.pp_if.if_iqdrops;
1180#endif
1181 return;
1182 }
1183 if (c->debug > 1)
1184 printmbuf (m);
1185#ifdef NETGRAPH
1186 m->m_pkthdr.rcvif = 0;
1187#if __FreeBSD_version >= 500000
1188 NG_SEND_DATA_ONLY (error, d->hook, m);
1189#else
1190 ng_queue_data (d->hook, m, 0);
1191#endif
1192#else
1193 ++d->pp.pp_if.if_ipackets;
1194 m->m_pkthdr.rcvif = &d->pp.pp_if;
1195#if __FreeBSD_version >= 400000 || NBPFILTER > 0
1196 /* Check if there's a BPF listener on this interface.
1197 * If so, hand off the raw packet to bpf. */
1198 if (d->pp.pp_if.if_bpf)
1199#if __FreeBSD_version >= 500000
1200 BPF_TAP (&d->pp.pp_if, data, len);
1201#else
1202 bpf_tap (&d->pp.pp_if, data, len);
1203#endif
1204#endif
1205 sppp_input (&d->pp.pp_if, m);
1206#endif
1207}
1208
1209/*
1210 * Error callback function.
1211 */
1212static void ct_error (ct_chan_t *c, int data)
1213{
1214 drv_t *d = c->sys;
1215
1216 if (!d)
1217 return;
1218
1219 switch (data) {
1220 case CT_FRAME:
1221 CT_DEBUG (d, ("frame error\n"));
1222#ifndef NETGRAPH
1223 ++d->pp.pp_if.if_ierrors;
1224#endif
1225 break;
1226 case CT_CRC:
1227 CT_DEBUG (d, ("crc error\n"));
1228#ifndef NETGRAPH
1229 ++d->pp.pp_if.if_ierrors;
1230#endif
1231 break;
1232 case CT_OVERRUN:
1233 CT_DEBUG (d, ("overrun error\n"));
1234#ifndef NETGRAPH
1235 ++d->pp.pp_if.if_collisions;
1236 ++d->pp.pp_if.if_ierrors;
1237#endif
1238 break;
1239 case CT_OVERFLOW:
1240 CT_DEBUG (d, ("overflow error\n"));
1241#ifndef NETGRAPH
1242 ++d->pp.pp_if.if_ierrors;
1243#endif
1244 break;
1245 case CT_UNDERRUN:
1246 CT_DEBUG (d, ("underrun error\n"));
1247#ifdef NETGRAPH
1248 d->timeout = 0;
1249#else
1250 ++d->pp.pp_if.if_oerrors;
1251 d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1252 d->pp.pp_if.if_timer = 0;
1253#endif
1254 ct_start (d);
1255 break;
1256 default:
1257 CT_DEBUG (d, ("error #%d\n", data));
1258 }
1259}
1260
1261#if __FreeBSD_version < 500000
1262static int ct_open (dev_t dev, int oflags, int devtype, struct proc *p)
1263#else
1264static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1265#endif
1266{
1267 drv_t *d;
1268
1269 if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)]))
1270 return ENXIO;
1271
1272 CT_DEBUG2 (d, ("ct_open\n"));
1273 return 0;
1274}
1275
1276#if __FreeBSD_version < 500000
1277static int ct_close (dev_t dev, int fflag, int devtype, struct proc *p)
1278#else
1279static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1280#endif
1281{
1282 drv_t *d = channel [minor(dev)];
1283
1284 if (!d)
1285 return 0;
1286
1287 CT_DEBUG2 (d, ("ct_close\n"));
1288 return 0;
1289}
1290
1291static int ct_modem_status (ct_chan_t *c)
1292{
1293 drv_t *d = c->sys;
1294 int status, s;
1295
1296 if (!d)
1297 return 0;
1298
1299 status = d->running ? TIOCM_LE : 0;
1300 s = splimp ();
1301 if (ct_get_cd (c)) status |= TIOCM_CD;
1302 if (ct_get_cts (c)) status |= TIOCM_CTS;
1303 if (ct_get_dsr (c)) status |= TIOCM_DSR;
1304 if (c->dtr) status |= TIOCM_DTR;
1305 if (c->rts) status |= TIOCM_RTS;
1306 splx (s);
1307 return status;
1308}
1309
1310/*
1311 * Process an ioctl request on /dev/cronyx/ctauN.
1312 */
1313#if __FreeBSD_version < 500000
1314static int ct_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1315#else
1316static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1317#endif
1318{
1319 drv_t *d = channel [minor (dev)];
1320 ct_chan_t *c;
1321 struct serial_statistics *st;
1322 struct e1_statistics *opte1;
1323 int error, s;
1324 char mask[16];
1325
1326 if (!d || !d->chan)
1327 return 0;
1328
1329 c = d->chan;
1330
1331 switch (cmd) {
1332 case SERIAL_GETREGISTERED:
1333 bzero (mask, sizeof(mask));
1334 for (s=0; s<NCTAU*NCHAN; ++s)
1335 if (channel [s])
1336 mask [s/8] |= 1 << (s & 7);
1337 bcopy (mask, data, sizeof (mask));
1338 return 0;
1339
1340#ifndef NETGRAPH
1341 case SERIAL_GETPROTO:
1342 strcpy ((char*)data, (d->pp.pp_flags & PP_FR) ? "fr" :
1343 (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp");
1344 return 0;
1345
1346 case SERIAL_SETPROTO:
1347 /* Only for superuser! */
1348#if __FreeBSD_version < 400000
1349 error = suser (p->p_ucred, &p->p_acflag);
1350#elif __FreeBSD_version < 500000
1351 error = suser (p);
1352#else /* __FreeBSD_version >= 500000 */
1353 error = suser (td);
1354#endif /* __FreeBSD_version >= 500000 */
1355 if (error)
1356 return error;
1357 if (d->pp.pp_if.if_flags & IFF_RUNNING)
1358 return EBUSY;
1359 if (! strcmp ("cisco", (char*)data)) {
1360 d->pp.pp_flags &= ~(PP_FR);
1361 d->pp.pp_flags |= PP_KEEPALIVE;
1362 d->pp.pp_if.if_flags |= PP_CISCO;
1363 } else if (! strcmp ("fr", (char*)data)) {
1364 d->pp.pp_if.if_flags &= ~(PP_CISCO);
1365 d->pp.pp_flags |= PP_FR | PP_KEEPALIVE;
1366 } else if (! strcmp ("ppp", (char*)data)) {
1367 d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1368 d->pp.pp_if.if_flags &= ~(PP_CISCO);
1369 } else
1370 return EINVAL;
1371 return 0;
1372
1373 case SERIAL_GETKEEPALIVE:
1374 if ((d->pp.pp_flags & PP_FR) ||
1375 (d->pp.pp_if.if_flags & PP_CISCO))
1376 return EINVAL;
1377 *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0;
1378 return 0;
1379
1380 case SERIAL_SETKEEPALIVE:
1381 /* Only for superuser! */
1382#if __FreeBSD_version < 400000
1383 error = suser (p->p_ucred, &p->p_acflag);
1384#elif __FreeBSD_version < 500000
1385 error = suser (p);
1386#else /* __FreeBSD_version >= 500000 */
1387 error = suser (td);
1388#endif /* __FreeBSD_version >= 500000 */
1389 if (error)
1390 return error;
1391 if ((d->pp.pp_flags & PP_FR) ||
1392 (d->pp.pp_if.if_flags & PP_CISCO))
1393 return EINVAL;
1394 if (*(int*)data)
1395 d->pp.pp_flags |= PP_KEEPALIVE;
1396 else
1397 d->pp.pp_flags &= ~PP_KEEPALIVE;
1398 return 0;
1399#endif /*NETGRAPH*/
1400
1401 case SERIAL_GETMODE:
1402 *(int*)data = SERIAL_HDLC;
1403 return 0;
1404
1405 case SERIAL_GETCFG:
1406 if (c->mode == M_HDLC)
1407 return EINVAL;
1408 switch (ct_get_config (c->board)) {
1409 default: *(char*)data = 'a'; break;
1410 case CFG_B: *(char*)data = 'b'; break;
1411 case CFG_C: *(char*)data = 'c'; break;
1412 }
1413 return 0;
1414
1415 case SERIAL_SETCFG:
1416 /* Only for superuser! */
1417#if __FreeBSD_version < 400000
1418 error = suser (p->p_ucred, &p->p_acflag);
1419#elif __FreeBSD_version < 500000
1420 error = suser (p);
1421#else /* __FreeBSD_version >= 500000 */
1422 error = suser (td);
1423#endif /* __FreeBSD_version >= 500000 */
1424 if (error)
1425 return error;
1426 if (c->mode == M_HDLC)
1427 return EINVAL;
1428 s = splimp ();
1429 switch (*(char*)data) {
1430 case 'a': ct_set_config (c->board, CFG_A); break;
1431 case 'b': ct_set_config (c->board, CFG_B); break;
1432 case 'c': ct_set_config (c->board, CFG_C); break;
1433 }
1434 splx (s);
1435 return 0;
1436
1437 case SERIAL_GETSTAT:
1438 st = (struct serial_statistics*) data;
1439 st->rintr = c->rintr;
1440 st->tintr = c->tintr;
1441 st->mintr = c->mintr;
1442 st->ibytes = c->ibytes;
1443 st->ipkts = c->ipkts;
1444 st->ierrs = c->ierrs;
1445 st->obytes = c->obytes;
1446 st->opkts = c->opkts;
1447 st->oerrs = c->oerrs;
1448 return 0;
1449
1450 case SERIAL_GETESTAT:
1451 opte1 = (struct e1_statistics*)data;
1452 opte1->status = c->status;
1453 opte1->cursec = c->cursec;
1454 opte1->totsec = c->totsec + c->cursec;
1455
1456 opte1->currnt.bpv = c->currnt.bpv;
1457 opte1->currnt.fse = c->currnt.fse;
1458 opte1->currnt.crce = c->currnt.crce;
1459 opte1->currnt.rcrce = c->currnt.rcrce;
1460 opte1->currnt.uas = c->currnt.uas;
1461 opte1->currnt.les = c->currnt.les;
1462 opte1->currnt.es = c->currnt.es;
1463 opte1->currnt.bes = c->currnt.bes;
1464 opte1->currnt.ses = c->currnt.ses;
1465 opte1->currnt.oofs = c->currnt.oofs;
1466 opte1->currnt.css = c->currnt.css;
1467 opte1->currnt.dm = c->currnt.dm;
1468
1469 opte1->total.bpv = c->total.bpv + c->currnt.bpv;
1470 opte1->total.fse = c->total.fse + c->currnt.fse;
1471 opte1->total.crce = c->total.crce + c->currnt.crce;
1472 opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1473 opte1->total.uas = c->total.uas + c->currnt.uas;
1474 opte1->total.les = c->total.les + c->currnt.les;
1475 opte1->total.es = c->total.es + c->currnt.es;
1476 opte1->total.bes = c->total.bes + c->currnt.bes;
1477 opte1->total.ses = c->total.ses + c->currnt.ses;
1478 opte1->total.oofs = c->total.oofs + c->currnt.oofs;
1479 opte1->total.css = c->total.css + c->currnt.css;
1480 opte1->total.dm = c->total.dm + c->currnt.dm;
1481 for (s=0; s<48; ++s) {
1482 opte1->interval[s].bpv = c->interval[s].bpv;
1483 opte1->interval[s].fse = c->interval[s].fse;
1484 opte1->interval[s].crce = c->interval[s].crce;
1485 opte1->interval[s].rcrce = c->interval[s].rcrce;
1486 opte1->interval[s].uas = c->interval[s].uas;
1487 opte1->interval[s].les = c->interval[s].les;
1488 opte1->interval[s].es = c->interval[s].es;
1489 opte1->interval[s].bes = c->interval[s].bes;
1490 opte1->interval[s].ses = c->interval[s].ses;
1491 opte1->interval[s].oofs = c->interval[s].oofs;
1492 opte1->interval[s].css = c->interval[s].css;
1493 opte1->interval[s].dm = c->interval[s].dm;
1494 }
1495 return 0;
1496
1497 case SERIAL_CLRSTAT:
1498 /* Only for superuser! */
1499#if __FreeBSD_version < 400000
1500 error = suser (p->p_ucred, &p->p_acflag);
1501#elif __FreeBSD_version < 500000
1502 error = suser (p);
1503#else /* __FreeBSD_version >= 500000 */
1504 error = suser (td);
1505#endif /* __FreeBSD_version >= 500000 */
1506 if (error)
1507 return error;
1508 c->rintr = 0;
1509 c->tintr = 0;
1510 c->mintr = 0;
1511 c->ibytes = 0;
1512 c->ipkts = 0;
1513 c->ierrs = 0;
1514 c->obytes = 0;
1515 c->opkts = 0;
1516 c->oerrs = 0;
1517 bzero (&c->currnt, sizeof (c->currnt));
1518 bzero (&c->total, sizeof (c->total));
1519 bzero (c->interval, sizeof (c->interval));
1520 return 0;
1521
1522 case SERIAL_GETBAUD:
1523 *(long*)data = ct_get_baud(c);
1524 return 0;
1525
1526 case SERIAL_SETBAUD:
1527 /* Only for superuser! */
1528#if __FreeBSD_version < 400000
1529 error = suser (p->p_ucred, &p->p_acflag);
1530#elif __FreeBSD_version < 500000
1531 error = suser (p);
1532#else /* __FreeBSD_version >= 500000 */
1533 error = suser (td);
1534#endif /* __FreeBSD_version >= 500000 */
1535 if (error)
1536 return error;
1537 s = splimp ();
1538 ct_set_baud (c, *(long*)data);
1539 splx (s);
1540 return 0;
1541
1542 case SERIAL_GETLOOP:
1543 *(int*)data = ct_get_loop (c);
1544 return 0;
1545
1546 case SERIAL_SETLOOP:
1547 /* Only for superuser! */
1548#if __FreeBSD_version < 400000
1549 error = suser (p->p_ucred, &p->p_acflag);
1550#elif __FreeBSD_version < 500000
1551 error = suser (p);
1552#else /* __FreeBSD_version >= 500000 */
1553 error = suser (td);
1554#endif /* __FreeBSD_version >= 500000 */
1555 if (error)
1556 return error;
1557 s = splimp ();
1558 ct_set_loop (c, *(int*)data);
1559 splx (s);
1560 return 0;
1561
1562 case SERIAL_GETDPLL:
1563 if (c->mode == M_E1 || c->mode == M_G703)
1564 return EINVAL;
1565 *(int*)data = ct_get_dpll (c);
1566 return 0;
1567
1568 case SERIAL_SETDPLL:
1569 /* Only for superuser! */
1570#if __FreeBSD_version < 400000
1571 error = suser (p->p_ucred, &p->p_acflag);
1572#elif __FreeBSD_version < 500000
1573 error = suser (p);
1574#else /* __FreeBSD_version >= 500000 */
1575 error = suser (td);
1576#endif /* __FreeBSD_version >= 500000 */
1577 if (error)
1578 return error;
1579 if (c->mode == M_E1 || c->mode == M_G703)
1580 return EINVAL;
1581 s = splimp ();
1582 ct_set_dpll (c, *(int*)data);
1583 splx (s);
1584 return 0;
1585
1586 case SERIAL_GETNRZI:
1587 if (c->mode == M_E1 || c->mode == M_G703)
1588 return EINVAL;
1589 *(int*)data = ct_get_nrzi (c);
1590 return 0;
1591
1592 case SERIAL_SETNRZI:
1593 /* Only for superuser! */
1594#if __FreeBSD_version < 400000
1595 error = suser (p->p_ucred, &p->p_acflag);
1596#elif __FreeBSD_version < 500000
1597 error = suser (p);
1598#else /* __FreeBSD_version >= 500000 */
1599 error = suser (td);
1600#endif /* __FreeBSD_version >= 500000 */
1601 if (error)
1602 return error;
1603 if (c->mode == M_E1 || c->mode == M_G703)
1604 return EINVAL;
1605 s = splimp ();
1606 ct_set_nrzi (c, *(int*)data);
1607 splx (s);
1608 return 0;
1609
1610 case SERIAL_GETDEBUG:
1611 *(int*)data = c->debug;
1612 return 0;
1613
1614 case SERIAL_SETDEBUG:
1615 /* Only for superuser! */
1616#if __FreeBSD_version < 400000
1617 error = suser (p->p_ucred, &p->p_acflag);
1618#elif __FreeBSD_version < 500000
1619 error = suser (p);
1620#else /* __FreeBSD_version >= 500000 */
1621 error = suser (td);
1622#endif /* __FreeBSD_version >= 500000 */
1623 if (error)
1624 return error;
1625 c->debug = *(int*)data;
1626#ifndef NETGRAPH
1627 if (d->chan->debug)
1628 d->pp.pp_if.if_flags |= IFF_DEBUG;
1629 else
1630 d->pp.pp_if.if_flags &= (~IFF_DEBUG);
1631#endif
1632 return 0;
1633
1634 case SERIAL_GETHIGAIN:
1635 if (c->mode != M_E1)
1636 return EINVAL;
1637 *(int*)data = ct_get_higain (c);
1638 return 0;
1639
1640 case SERIAL_SETHIGAIN:
1641 /* Only for superuser! */
1642#if __FreeBSD_version < 400000
1643 error = suser (p->p_ucred, &p->p_acflag);
1644#elif __FreeBSD_version < 500000
1645 error = suser (p);
1646#else /* __FreeBSD_version >= 500000 */
1647 error = suser (td);
1648#endif /* __FreeBSD_version >= 500000 */
1649 if (error)
1650 return error;
1651 s = splimp ();
1652 ct_set_higain (c, *(int*)data);
1653 splx (s);
1654 return 0;
1655
1656 case SERIAL_GETPHONY:
1657 CT_DEBUG2 (d, ("ioctl: getphony\n"));
1658 if (c->mode != M_E1)
1659 return EINVAL;
1660 *(int*)data = c->gopt.phony;
1661 return 0;
1662
1663 case SERIAL_SETPHONY:
1664 CT_DEBUG2 (d, ("ioctl: setphony\n"));
1665 if (c->mode != M_E1)
1666 return EINVAL;
1667 /* Only for superuser! */
1668#if __FreeBSD_version < 400000
1669 error = suser (p->p_ucred, &p->p_acflag);
1670#elif __FreeBSD_version < 500000
1671 error = suser (p);
1672#else /* __FreeBSD_version >= 500000 */
1673 error = suser (td);
1674#endif /* __FreeBSD_version >= 500000 */
1675 if (error)
1676 return error;
1677 s = splimp ();
1678 ct_set_phony (c, *(int*)data);
1679 splx (s);
1680 return 0;
1681
1682 case SERIAL_GETCLK:
1683 if (c->mode != M_E1 && c->mode != M_G703)
1684 return EINVAL;
1685 switch (ct_get_clk(c)) {
1686 default: *(int*)data = E1CLK_INTERNAL; break;
1687 case GCLK_RCV: *(int*)data = E1CLK_RECEIVE; break;
1688 case GCLK_RCLKO: *(int*)data = c->num ?
1689 E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1; break;
1690 }
1691 return 0;
1692
1693 case SERIAL_SETCLK:
1694 /* Only for superuser! */
1695#if __FreeBSD_version < 400000
1696 error = suser (p->p_ucred, &p->p_acflag);
1697#elif __FreeBSD_version < 500000
1698 error = suser (p);
1699#else /* __FreeBSD_version >= 500000 */
1700 error = suser (td);
1701#endif /* __FreeBSD_version >= 500000 */
1702 if (error)
1703 return error;
1704 s = splimp ();
1705 switch (*(int*)data) {
1706 default: ct_set_clk (c, GCLK_INT); break;
1707 case E1CLK_RECEIVE: ct_set_clk (c, GCLK_RCV); break;
1708 case E1CLK_RECEIVE_CHAN0:
1709 case E1CLK_RECEIVE_CHAN1:
1710 ct_set_clk (c, GCLK_RCLKO); break;
1711 }
1712 splx (s);
1713 return 0;
1714
1715 case SERIAL_GETTIMESLOTS:
1716 if (c->mode != M_E1)
1717 return EINVAL;
1718 *(long*)data = ct_get_ts (c);
1719 return 0;
1720
1721 case SERIAL_SETTIMESLOTS:
1722 /* Only for superuser! */
1723#if __FreeBSD_version < 400000
1724 error = suser (p->p_ucred, &p->p_acflag);
1725#elif __FreeBSD_version < 500000
1726 error = suser (p);
1727#else /* __FreeBSD_version >= 500000 */
1728 error = suser (td);
1729#endif /* __FreeBSD_version >= 500000 */
1730 if (error)
1731 return error;
1732 s = splimp ();
1733 ct_set_ts (c, *(long*)data);
1734 splx (s);
1735 return 0;
1736
1737 case SERIAL_GETSUBCHAN:
1738 if (c->mode != M_E1)
1739 return EINVAL;
1740 *(long*)data = ct_get_subchan (c->board);
1741 return 0;
1742
1743 case SERIAL_SETSUBCHAN:
1744 /* Only for superuser! */
1745#if __FreeBSD_version < 400000
1746 error = suser (p->p_ucred, &p->p_acflag);
1747#elif __FreeBSD_version < 500000
1748 error = suser (p);
1749#else /* __FreeBSD_version >= 500000 */
1750 error = suser (td);
1751#endif /* __FreeBSD_version >= 500000 */
1752 if (error)
1753 return error;
1754 s = splimp ();
1755 ct_set_subchan (c->board, *(long*)data);
1756 splx (s);
1757 return 0;
1758
1759 case SERIAL_GETINVCLK:
1760 case SERIAL_GETINVTCLK:
1761 if (c->mode == M_E1 || c->mode == M_G703)
1762 return EINVAL;
1763 *(int*)data = ct_get_invtxc (c);
1764 return 0;
1765
1766 case SERIAL_GETINVRCLK:
1767 if (c->mode == M_E1 || c->mode == M_G703)
1768 return EINVAL;
1769 *(int*)data = ct_get_invrxc (c);
1770 return 0;
1771
1772 case SERIAL_SETINVCLK:
1773 case SERIAL_SETINVTCLK:
1774 /* Only for superuser! */
1775#if __FreeBSD_version < 400000
1776 error = suser (p->p_ucred, &p->p_acflag);
1777#elif __FreeBSD_version < 500000
1778 error = suser (p);
1779#else /* __FreeBSD_version >= 500000 */
1780 error = suser (td);
1781#endif /* __FreeBSD_version >= 500000 */
1782 if (error)
1783 return error;
1784 if (c->mode == M_E1 || c->mode == M_G703)
1785 return EINVAL;
1786 s = splimp ();
1787 ct_set_invtxc (c, *(int*)data);
1788 splx (s);
1789 return 0;
1790
1791 case SERIAL_SETINVRCLK:
1792 /* Only for superuser! */
1793#if __FreeBSD_version < 400000
1794 error = suser (p->p_ucred, &p->p_acflag);
1795#elif __FreeBSD_version < 500000
1796 error = suser (p);
1797#else /* __FreeBSD_version >= 500000 */
1798 error = suser (td);
1799#endif /* __FreeBSD_version >= 500000 */
1800 if (error)
1801 return error;
1802 if (c->mode == M_E1 || c->mode == M_G703)
1803 return EINVAL;
1804 s = splimp ();
1805 ct_set_invrxc (c, *(int*)data);
1806 splx (s);
1807 return 0;
1808
1809 case SERIAL_GETLEVEL:
1810 if (c->mode != M_G703)
1811 return EINVAL;
1812 s = splimp ();
1813 *(int*)data = ct_get_lq (c);
1814 splx (s);
1815 return 0;
1816
1817 case TIOCSDTR: /* Set DTR */
1818 s = splimp ();
1819 ct_set_dtr (c, 1);
1820 splx (s);
1821 return 0;
1822
1823 case TIOCCDTR: /* Clear DTR */
1824 s = splimp ();
1825 ct_set_dtr (c, 0);
1826 splx (s);
1827 return 0;
1828
1829 case TIOCMSET: /* Set DTR/RTS */
1830 s = splimp ();
1831 ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1832 ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1833 splx (s);
1834 return 0;
1835
1836 case TIOCMBIS: /* Add DTR/RTS */
1837 s = splimp ();
1838 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1);
1839 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1);
1840 splx (s);
1841 return 0;
1842
1843 case TIOCMBIC: /* Clear DTR/RTS */
1844 s = splimp ();
1845 if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0);
1846 if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0);
1847 splx (s);
1848 return 0;
1849
1850 case TIOCMGET: /* Get modem status */
1851 *(int*)data = ct_modem_status (c);
1852 return 0;
1853 }
1854 return ENOTTY;
1855}
1856
1857#if __FreeBSD_version < 400000
1858struct isa_driver ctdriver = { ct_probe, ct_attach, "ct" };
1859static struct cdevsw ct_cdevsw = {
1860 ct_open, ct_close, noread, nowrite,
1861 ct_ioctl, nostop, noreset, nodevtotty,
1862 seltrue, nommap, NULL, "ct",
1863 NULL, -1,
1864};
1865#elif __FreeBSD_version < 500000
1866static struct cdevsw ct_cdevsw = {
1867 ct_open, ct_close, noread, nowrite,
1868 ct_ioctl, nopoll, nommap, nostrategy,
1869 "ct", CDEV_MAJOR, nodump, nopsize,
1870 D_NAGGED, -1
1871};
1872#elif __FreeBSD_version == 500000
1873static struct cdevsw ct_cdevsw = {
1874 ct_open, ct_close, noread, nowrite,
1875 ct_ioctl, nopoll, nommap, nostrategy,
1876 "ct", CDEV_MAJOR, nodump, nopsize,
1877 D_NAGGED,
1878 };
1879#elif __FreeBSD_version <= 501000
1880static struct cdevsw ct_cdevsw = {
1881 .d_open = ct_open,
1882 .d_close = ct_close,
1883 .d_read = noread,
1884 .d_write = nowrite,
1885 .d_ioctl = ct_ioctl,
1886 .d_poll = nopoll,
1887 .d_mmap = nommap,
1888 .d_strategy = nostrategy,
1889 .d_name = "ct",
1890 .d_maj = CDEV_MAJOR,
1891 .d_dump = nodump,
1892 .d_flags = D_NAGGED,
1893};
1894#elif __FreeBSD_version < 502103
1895static struct cdevsw ct_cdevsw = {
1896 .d_open = ct_open,
1897 .d_close = ct_close,
1898 .d_ioctl = ct_ioctl,
1899 .d_name = "ct",
1900 .d_maj = CDEV_MAJOR,
1901 .d_flags = D_NAGGED,
1902};
1903#else /* __FreeBSD_version >= 502103 */
1904static struct cdevsw ct_cdevsw = {
1905 .d_version = D_VERSION,
1906 .d_open = ct_open,
1907 .d_close = ct_close,
1908 .d_ioctl = ct_ioctl,
1909 .d_name = "ct",
1910 .d_maj = CDEV_MAJOR,
1911 .d_flags = D_NEEDGIANT,
1912};
1913#endif /* __FreeBSD_version > 501000 */
1914
1915#ifdef NETGRAPH
1916#if __FreeBSD_version >= 500000
1917static int ng_ct_constructor (node_p node)
1918{
1919 drv_t *d = NG_NODE_PRIVATE (node);
1920#else
1921static int ng_ct_constructor (node_p *node)
1922{
1923 drv_t *d = (*node)->private;
1924#endif
1925 CT_DEBUG (d, ("Constructor\n"));
1926 return EINVAL;
1927}
1928
1929static int ng_ct_newhook (node_p node, hook_p hook, const char *name)
1930{
1931 int s;
1932#if __FreeBSD_version >= 500000
1933 drv_t *d = NG_NODE_PRIVATE (node);
1934#else
1935 drv_t *d = node->private;
1936#endif
1937
1938 if (!d)
1939 return EINVAL;
1940
1941 /* Attach debug hook */
1942 if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) {
1943#if __FreeBSD_version >= 500000
1944 NG_HOOK_SET_PRIVATE (hook, NULL);
1945#else
1946 hook->private = 0;
1947#endif
1948 d->debug_hook = hook;
1949 return 0;
1950 }
1951
1952 /* Check for raw hook */
1953 if (strcmp (name, NG_CT_HOOK_RAW) != 0)
1954 return EINVAL;
1955
1956#if __FreeBSD_version >= 500000
1957 NG_HOOK_SET_PRIVATE (hook, d);
1958#else
1959 hook->private = d;
1960#endif
1961 d->hook = hook;
1962 s = splimp ();
1963 ct_up (d);
1964 splx (s);
1965 return 0;
1966}
1967
1968static char *format_timeslots (u_long s)
1969{
1970 static char buf [100];
1971 char *p = buf;
1972 int i;
1973
1974 for (i=1; i<32; ++i)
1975 if ((s >> i) & 1) {
1976 int prev = (i > 1) & (s >> (i-1));
1977 int next = (i < 31) & (s >> (i+1));
1978
1979 if (prev) {
1980 if (next)
1981 continue;
1982 *p++ = '-';
1983 } else if (p > buf)
1984 *p++ = ',';
1985
1986 if (i >= 10)
1987 *p++ = '0' + i / 10;
1988 *p++ = '0' + i % 10;
1989 }
1990 *p = 0;
1991 return buf;
1992}
1993
1994static int print_modems (char *s, ct_chan_t *c, int need_header)
1995{
1996 int status = ct_modem_status (c);
1997 int length = 0;
1998
1999 if (need_header)
2000 length += sprintf (s + length, " LE DTR DSR RTS CTS CD\n");
2001 length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
2002 status & TIOCM_LE ? "On" : "-",
2003 status & TIOCM_DTR ? "On" : "-",
2004 status & TIOCM_DSR ? "On" : "-",
2005 status & TIOCM_RTS ? "On" : "-",
2006 status & TIOCM_CTS ? "On" : "-",
2007 status & TIOCM_CD ? "On" : "-");
2008 return length;
2009}
2010
2011static int print_stats (char *s, ct_chan_t *c, int need_header)
2012{
2013 struct serial_statistics st;
2014 int length = 0;
2015
2016 st.rintr = c->rintr;
2017 st.tintr = c->tintr;
2018 st.mintr = c->mintr;
2019 st.ibytes = c->ibytes;
2020 st.ipkts = c->ipkts;
2021 st.ierrs = c->ierrs;
2022 st.obytes = c->obytes;
2023 st.opkts = c->opkts;
2024 st.oerrs = c->oerrs;
2025 if (need_header)
2026 length += sprintf (s + length, " Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n");
2027 length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
2028 st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts,
2029 st.ierrs, st.obytes, st.opkts, st.oerrs);
2030 return length;
2031}
2032
2033static char *format_e1_status (u_char status)
2034{
2035 static char buf [80];
2036
2037 if (status & E1_NOALARM)
2038 return "Ok";
2039 buf[0] = 0;
2040 if (status & E1_LOS) strcat (buf, ",LOS");
2041 if (status & E1_AIS) strcat (buf, ",AIS");
2042 if (status & E1_LOF) strcat (buf, ",LOF");
2043 if (status & E1_LOMF) strcat (buf, ",LOMF");
2044 if (status & E1_FARLOF) strcat (buf, ",FARLOF");
2045 if (status & E1_AIS16) strcat (buf, ",AIS16");
2046 if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
2047 if (status & E1_TSTREQ) strcat (buf, ",TSTREQ");
2048 if (status & E1_TSTERR) strcat (buf, ",TSTERR");
2049 if (buf[0] == ',')
2050 return buf+1;
2051 return "Unknown";
2052}
2053
2054static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
2055{
2056 int n, length = 0;
2057
2058 if (numerator < 1 || divider < 1) {
2059 length += sprintf (s+length, leftalign ? "/- " : " -");
2060 return length;
2061 }
2062 n = (int) (0.5 + 1000.0 * numerator / divider);
2063 if (n < 1000) {
2064 length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
2065 return length;
2066 }
2067 *(s + length) = leftalign ? '/' : ' ';
2068 length ++;
2069
2070 if (n >= 1000000) n = (n+500) / 1000 * 1000;
2071 else if (n >= 100000) n = (n+50) / 100 * 100;
2072 else if (n >= 10000) n = (n+5) / 10 * 10;
2073
2074 switch (n) {
2075 case 1000: length += printf (s+length, ".999"); return length;
2076 case 10000: n = 9990; break;
2077 case 100000: n = 99900; break;
2078 case 1000000: n = 999000; break;
2079 }
2080 if (n < 10000) length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
2081 else if (n < 100000) length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
2082 else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
2083 else length += sprintf (s+length, "%d", n/1000);
2084
2085 return length;
2086}
2087
2088static int print_e1_stats (char *s, ct_chan_t *c)
2089{
2090 struct e1_counters total;
2091 u_long totsec;
2092 int length = 0;
2093
2094 totsec = c->totsec + c->cursec;
2095 total.bpv = c->total.bpv + c->currnt.bpv;
2096 total.fse = c->total.fse + c->currnt.fse;
2097 total.crce = c->total.crce + c->currnt.crce;
2098 total.rcrce = c->total.rcrce + c->currnt.rcrce;
2099 total.uas = c->total.uas + c->currnt.uas;
2100 total.les = c->total.les + c->currnt.les;
2101 total.es = c->total.es + c->currnt.es;
2102 total.bes = c->total.bes + c->currnt.bes;
2103 total.ses = c->total.ses + c->currnt.ses;
2104 total.oofs = c->total.oofs + c->currnt.oofs;
2105 total.css = c->total.css + c->currnt.css;
2106 total.dm = c->total.dm + c->currnt.dm;
2107
2108 length += sprintf (s + length, " Unav/Degr Bpv/Fsyn CRC/RCRC Err/Lerr Sev/Bur Oof/Slp Status\n");
2109
2110 /* Unavailable seconds, degraded minutes */
2111 length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
2112 length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
2113
2114 /* Bipolar violations, frame sync errors */
2115 length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
2116 length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
2117
2118 /* CRC errors, remote CRC errors (E-bit) */
2119 length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
2120 length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
2121
2122 /* Errored seconds, line errored seconds */
2123 length += print_frac (s + length, 0, c->currnt.es, c->cursec);
2124 length += print_frac (s + length, 1, c->currnt.les, c->cursec);
2125
2126 /* Severely errored seconds, burst errored seconds */
2127 length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
2128 length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
2129
2130 /* Out of frame seconds, controlled slip seconds */
2131 length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
2132 length += print_frac (s + length, 1, c->currnt.css, c->cursec);
2133
2134 length += sprintf (s + length, " %s\n", format_e1_status (c->status));
2135
2136 /* Print total statistics. */
2137 length += print_frac (s + length, 0, total.uas, totsec);
2138 length += print_frac (s + length, 1, 60 * total.dm, totsec);
2139
2140 length += print_frac (s + length, 0, total.bpv, totsec);
2141 length += print_frac (s + length, 1, total.fse, totsec);
2142
2143 length += print_frac (s + length, 0, total.crce, totsec);
2144 length += print_frac (s + length, 1, total.rcrce, totsec);
2145
2146 length += print_frac (s + length, 0, total.es, totsec);
2147 length += print_frac (s + length, 1, total.les, totsec);
2148
2149 length += print_frac (s + length, 0, total.ses, totsec);
2150 length += print_frac (s + length, 1, total.bes, totsec);
2151
2152 length += print_frac (s + length, 0, total.oofs, totsec);
2153 length += print_frac (s + length, 1, total.css, totsec);
2154
2155 length += sprintf (s + length, " -- Total\n");
2156 return length;
2157}
2158
2159static int print_chan (char *s, ct_chan_t *c)
2160{
2161 drv_t *d = c->sys;
2162 int length = 0;
2163
2164 length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num);
2165 if (d->chan->debug)
2166 length += sprintf (s + length, " debug=%d", d->chan->debug);
2167
2168 switch (ct_get_config (c->board)) {
2169 case CFG_A: length += sprintf (s + length, " cfg=A"); break;
2170 case CFG_B: length += sprintf (s + length, " cfg=B"); break;
2171 case CFG_C: length += sprintf (s + length, " cfg=C"); break;
2172 default: length += sprintf (s + length, " cfg=unknown"); break;
2173 }
2174
2175 if (ct_get_baud (c))
2176 length += sprintf (s + length, " %ld", ct_get_baud (c));
2177 else
2178 length += sprintf (s + length, " extclock");
2179
2180 if (c->mode == M_E1 || c->mode == M_G703)
2181 switch (ct_get_clk(c)) {
2182 case GCLK_INT : length += sprintf (s + length, " syn=int"); break;
2183 case GCLK_RCV : length += sprintf (s + length, " syn=rcv"); break;
2184 case GCLK_RCLKO : length += sprintf (s + length, " syn=xrcv"); break;
2185 }
2186 if (c->mode == M_HDLC) {
2187 length += sprintf (s + length, " dpll=%s", ct_get_dpll (c) ? "on" : "off");
2188 length += sprintf (s + length, " nrzi=%s", ct_get_nrzi (c) ? "on" : "off");
2189 length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off");
2190 length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off");
2191 }
2192 if (c->mode == M_E1)
2193 length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off");
2194
2195 length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off");
2196
2197 if (c->mode == M_E1)
2198 length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c)));
2199 if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A)
2200 length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board)));
2201 if (c->mode == M_G703) {
2202 int lq, x;
2203
2204 x = splimp ();
2205 lq = ct_get_lq (c);
2206 splx (x);
2207 length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2208 }
2209 length += sprintf (s + length, "\n");
2210 return length;
2211}
2212
2213#if __FreeBSD_version >= 500000
2214static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook)
2215{
2216 drv_t *d = NG_NODE_PRIVATE (node);
2217 struct ng_mesg *msg;
2218#else
2219static int ng_ct_rcvmsg (node_p node, struct ng_mesg *msg,
2220 const char *retaddr, struct ng_mesg **rptr)
2221{
2222 drv_t *d = node->private;
2223#endif
2224 struct ng_mesg *resp = NULL;
2225 int error = 0;
2226
2227 if (!d)
2228 return EINVAL;
2229
2230 CT_DEBUG (d, ("Rcvmsg\n"));
2231#if __FreeBSD_version >= 500000
2232 NGI_GET_MSG (item, msg);
2233#endif
2234 switch (msg->header.typecookie) {
2235 default:
2236 error = EINVAL;
2237 break;
2238
2239 case NGM_CT_COOKIE:
2240 printf ("Don't forget to implement\n");
2241 error = EINVAL;
2242 break;
2243
2244 case NGM_GENERIC_COOKIE:
2245 switch (msg->header.cmd) {
2246 default:
2247 error = EINVAL;
2248 break;
2249
2250 case NGM_TEXT_STATUS: {
2251 char *s;
2252 int l = 0;
2253 int dl = sizeof (struct ng_mesg) + 730;
2254
2255#if __FreeBSD_version >= 500000
2256 NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2257 if (! resp) {
2258 error = ENOMEM;
2259 break;
2260 }
2261#else
2262 MALLOC (resp, struct ng_mesg *, dl,
2263 M_NETGRAPH, M_NOWAIT);
2264 if (! resp) {
2265 error = ENOMEM;
2266 break;
2267 }
2268 bzero (resp, dl);
2269#endif
2270 s = (resp)->data;
2271 l += print_chan (s + l, d->chan);
2272 l += print_stats (s + l, d->chan, 1);
2273 l += print_modems (s + l, d->chan, 1);
2274 l += print_e1_stats (s + l, d->chan);
2275#if __FreeBSD_version < 500000
2276 (resp)->header.version = NG_VERSION;
2277 (resp)->header.arglen = strlen (s) + 1;
2278 (resp)->header.token = msg->header.token;
2279 (resp)->header.typecookie = NGM_CT_COOKIE;
2280 (resp)->header.cmd = msg->header.cmd;
2281#endif
2282 strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2283 }
2284 break;
2285 }
2286 break;
2287 }
2288#if __FreeBSD_version >= 500000
2289 NG_RESPOND_MSG (error, node, item, resp);
2290 NG_FREE_MSG (msg);
2291#else
2292 *rptr = resp;
2293 FREE (msg, M_NETGRAPH);
2294#endif
2295 return error;
2296}
2297
2298#if __FreeBSD_version >= 500000
2299static int ng_ct_rcvdata (hook_p hook, item_p item)
2300{
2301 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2302 struct mbuf *m;
2303 meta_p meta;
2304#else
2305static int ng_ct_rcvdata (hook_p hook, struct mbuf *m, meta_p meta)
2306{
2307 drv_t *d = hook->node->private;
2308#endif
2309 struct ifqueue *q;
2310 int s;
2311
2312 if (!d)
2313 return ENETDOWN;
2314
2315#if __FreeBSD_version >= 500000
2316 NGI_GET_M (item, m);
2317 NGI_GET_META (item, meta);
2318 NG_FREE_ITEM (item);
2319 if (! NG_HOOK_PRIVATE (hook) || ! d) {
2320 NG_FREE_M (m);
2321 NG_FREE_META (meta);
2322#else
2323 if (! hook->private || ! d) {
2324 NG_FREE_DATA (m,meta);
2325#endif
2326 return ENETDOWN;
2327 }
2328 q = (meta && meta->priority > 0) ? &d->hi_queue : &d->queue;
2329 s = splimp ();
2330#if __FreeBSD_version >= 500000
2331 IF_LOCK (q);
2332 if (_IF_QFULL (q)) {
2333 _IF_DROP (q);
2334 IF_UNLOCK (q);
2335 splx (s);
2336 NG_FREE_M (m);
2337 NG_FREE_META (meta);
2338 return ENOBUFS;
2339 }
2340 _IF_ENQUEUE (q, m);
2341 IF_UNLOCK (q);
2342#else
2343 if (IF_QFULL (q)) {
2344 IF_DROP (q);
2345 splx (s);
2346 NG_FREE_DATA (m, meta);
2347 return ENOBUFS;
2348 }
2349 IF_ENQUEUE (q, m);
2350#endif
2351 ct_start (d);
2352 splx (s);
2353 return 0;
2354}
2355
2356static int ng_ct_rmnode (node_p node)
2357{
2358#if __FreeBSD_version >= 500000
2359 drv_t *d = NG_NODE_PRIVATE (node);
2360
2361 CT_DEBUG (d, ("Rmnode\n"));
2362 if (d && d->running) {
2363 int s = splimp ();
2364 ct_down (d);
2365 splx (s);
2366 }
2367#ifdef KLD_MODULE
2368 if (node->nd_flags & NG_REALLY_DIE) {
2369 NG_NODE_SET_PRIVATE (node, NULL);
2370 NG_NODE_UNREF (node);
2371 }
2372 node->nd_flags &= ~NG_INVALID;
2373#endif
2374#else /* __FreeBSD_version < 500000 */
2375 drv_t *d = node->private;
2376 int s;
2377
2378 if (!d)
2379 return 0;
2380
2381 s = splimp ();
2382 ct_down (d);
2383 splx (s);
2384 node->flags |= NG_INVALID;
2385 ng_cutlinks (node);
2386#ifdef KLD_MODULE
2387 ng_unname (node);
2388 ng_unref (node);
2389#else
2390 node->flags &= ~NG_INVALID;
2391#endif
2392#endif
2393 return 0;
2394}
2395
2396static void ng_ct_watchdog (void *arg)
2397{
2398 drv_t *d = arg;
2399
2400 if (!d)
2401 return;
2402
2403 if (d->timeout == 1)
2404 ct_watchdog (d);
2405 if (d->timeout)
2406 d->timeout--;
2407 d->timeout_handle = timeout (ng_ct_watchdog, d, hz);
2408}
2409
2410static int ng_ct_connect (hook_p hook)
2411{
2412#if __FreeBSD_version >= 500000
2413 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2414#else
2415 drv_t *d = hook->node->private;
2416#endif
2417
2418 if (!d)
2419 return 0;
2420
2421 d->timeout_handle = timeout (ng_ct_watchdog, d, hz);
2422 return 0;
2423}
2424
2425static int ng_ct_disconnect (hook_p hook)
2426{
2427#if __FreeBSD_version >= 500000
2428 drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2429#else
2430 drv_t *d = hook->node->private;
2431#endif
2432
2433 if (!d)
2434 return 0;
2435
2436#if __FreeBSD_version >= 500000
2437 if (NG_HOOK_PRIVATE (hook))
2438#else
2439 if (hook->private)
2440#endif
2441 ct_down (d);
2442 untimeout (ng_ct_watchdog, d, d->timeout_handle);
2443 return 0;
2444}
2445#endif
2446
2447#ifdef KLD_MODULE
2448#if __FreeBSD_version < 400000
2449/*
2450 * Function called when loading the driver.
2451 */
2452static int ct_load (void)
2453{
2454 int i;
2455
2456 for (i=0;i<NCTAU; ++i) {
2457 struct isa_device id = {-1, &ctdriver, -1, 0, -1, 0, 0, (inthand2_t *)ct_intr, i, 0, 0, 0, 0 ,0 ,1 ,0 ,0};
2458 disable_intr();
2459 if (!ct_probe (&id)) {
2460 enable_intr();
2461 break;
2462 }
2463 ct_attach (&id);
2464 register_intr ((adapter [i])->irq, 0, 0, (inthand2_t*) ct_intr,
2465 &net_imask, id.id_unit);
2466 enable_intr();
2467 }
2468 if (!i) {
2469 /* Deactivate the timeout routine. */
2470 untimeout (ct_timeout, 0, timeout_handle);
2471
2472 return ENXIO;
2473 }
2474 return 0;
2475}
2476
2477/*
2478 * Function called when unloading the driver.
2479 */
2480static int ct_unload (void)
2481{
2482 int i, s;
2483
2484 /* Check if the device is busy (open). */
2485 for (i=0; i<NCTAU*NCHAN; ++i) {
2486 drv_t *d = channel[i];
2487
2488 if (!d)
2489 continue;
2490 if (d->running)
2491 return EBUSY;
2492 }
2493
2494 /* OK to unload the driver, unregister the interrupt first. */
2495 s = splimp ();
2496
2497 /* Deactivate the timeout routine. */
2498 for (i=0; i<NCTAU; ++i) {
2499 if (!adapter [i])
2500 continue;
2501 untimeout (ct_timeout, 0, timeout_handle);
2502 break;
2503 }
2504
2505 for (i=0; i<NCTAU; ++i) {
2506 ct_board_t *b = adapter [i];
2507
2508 if (!b || ! b->port)
2509 continue;
2510
2511 ct_close_board (b);
2512 }
2513
2514 for (i=0; i<NCTAU; ++i) {
2515 ct_board_t *b = adapter [i];
2516
2517 if (!b || ! b->port)
2518 continue;
2519
2520 if (led_timo[i].callout)
2521 untimeout (ct_led_off, b, led_timo[i]);
2522 }
2523
2524 for (i=0; i<NCTAU; ++i) {
2525 ct_board_t *b = adapter [i];
2526
2527 if (!b || ! b->port)
2528 continue;
2529
2530 /* Disable the interrupt request. */
2531 disable_intr();
2532 unregister_intr (b->irq, (inthand2_t *)ct_intr);
2533 isa_dma_release (b->dma);
2534 enable_intr();
2535 }
2536
2537 /* Detach the interfaces, free buffer memory. */
2538 for (i=0; i<NCTAU*NCHAN; ++i) {
2539 drv_t *d = channel[i];
2540
2541 if (!d)
2542 continue;
2543
2544#ifndef NETGRAPH
2545#if NBPFILTER > 0
2546 /* Detach from the packet filter list of interfaces. */
2547 {
2548 struct bpf_if *q, **b = &bpf_iflist;
2549
2550 while ((q = *b)) {
2551 if (q->bif_ifp == d->pp.pp_if) {
2552 *b = q->bif_next;
2553 free (q, M_DEVBUF);
2554 }
2555 b = &(q->bif_next);
2556 }
2557 }
2558#endif /* NBPFILTER > 0 */
2559 /* Detach from the sync PPP list. */
2560 sppp_detach (&d->pp.pp_if);
2561
2562 /* Detach from the system list of interfaces. */
2563 {
2564 struct ifaddr *ifa;
2565 TAILQ_FOREACH (ifa, &d->pp.pp_if.if_addrhead, ifa_link) {
2566 TAILQ_REMOVE (&d->pp.pp_if.if_addrhead, ifa, ifa_link);
2567 free (ifa, M_IFADDR);
2568 }
2569 TAILQ_REMOVE (&ifnet, &d->pp.pp_if, if_link);
2570 }
2571#endif /* !NETGRAPH */
2572 /* Deallocate buffers. */
2573/* free (d, M_DEVBUF);*/
2574 }
2575 for (i=0; i<NCTAU; ++i) {
2576 ct_board_t *b = adapter [i];
2577 if (!b)
2578 continue;
2579 adapter [i] = 0;
2580 free (b, M_DEVBUF);
2581 }
2582 splx(s);
2583
2584 return 0;
2585}
2586
2587#define devsw(a) cdevsw[major((a))]
2588#endif /* __FreeBSD_version < 400000 */
2589#endif /* KLD_MODULE */
2590
2591#if __FreeBSD_version < 400000
2592#ifdef KLD_MODULE
2593static int ct_modevent (module_t mod, int type, void *unused)
2594{
2595 dev_t dev;
2596 int result;
2597 static int load_count = 0;
2598
2599 dev = makedev (CDEV_MAJOR, 0);
2600 switch (type) {
2601 case MOD_LOAD:
2602 if (devsw(dev))
2603 return (ENXIO);
2604 load_count ++;
2605 cdevsw_add (&dev, &ct_cdevsw, NULL);
2606 timeout_handle = timeout (ct_timeout, 0, hz*5);
2607 result = ct_load ();
2608 return result;
2609 case MOD_UNLOAD:
2610 result = ct_unload ();
2611 if (result)
2612 return result;
2613 if (devsw(dev)&&!(load_count-1)) {
2614 cdevsw_add (&dev, NULL, NULL);
2615 }
2616 load_count --;
2617 return result;
2618 case MOD_SHUTDOWN:
2619 break;
2620 }
2621 return 0;
2622}
2623#endif /* KLD_MODULE */
2624#else /* __FreeBSD_version >= 400000 */
2625static int ct_modevent (module_t mod, int type, void *unused)
2626{
2627 struct cdev *dev;
2628 static int load_count = 0;
2629 struct cdevsw *cdsw;
2630
2631#if __FreeBSD_version >= 502103
2632 dev = udev2dev (makeudev(CDEV_MAJOR, 0));
2632 dev = findcdev (makedev(CDEV_MAJOR, 0));
2633#else
2634 dev = makedev (CDEV_MAJOR, 0);
2635#endif
2636 switch (type) {
2637 case MOD_LOAD:
2638 if (dev != NODEV &&
2638 if (dev != NULL &&
2639 (cdsw = devsw (dev)) &&
2640 cdsw->d_maj == CDEV_MAJOR) {
2641 printf ("Tau-ISA driver is already in system\n");
2642 return (ENXIO);
2643 }
2644#if __FreeBSD_version >= 500000 && defined NETGRAPH
2645 if (ng_newtype (&typestruct))
2646 printf ("Failed to register ng_ct\n");
2647#endif
2648 ++load_count;
2649#if __FreeBSD_version <= 500000
2650 cdevsw_add (&ct_cdevsw);
2651#endif
2652 timeout_handle = timeout (ct_timeout, 0, hz*5);
2653 break;
2654 case MOD_UNLOAD:
2655 if (load_count == 1) {
2656 printf ("Removing device entry for Tau-ISA\n");
2657#if __FreeBSD_version <= 500000
2658 cdevsw_remove (&ct_cdevsw);
2659#endif
2660#if __FreeBSD_version >= 500000 && defined NETGRAPH
2661 ng_rmtype (&typestruct);
2662#endif
2663 }
2664 if (timeout_handle.callout)
2665 untimeout (ct_timeout, 0, timeout_handle);
2666 --load_count;
2667 break;
2668 case MOD_SHUTDOWN:
2669 break;
2670 }
2671 return 0;
2672}
2673#endif /* __FreeBSD_version >= 400000 */
2674
2675#ifdef NETGRAPH
2676static struct ng_type typestruct = {
2677 .version = NG_ABI_VERSION,
2678 .name = NG_CT_NODE_TYPE,
2679 .constructor = ng_ct_constructor,
2680 .rcvmsg = ng_ct_rcvmsg,
2681 .shutdown = ng_ct_rmnode,
2682 .newhook = ng_ct_newhook,
2683 .connect = ng_ct_connect,
2684 .rcvdata = ng_ct_rcvdata,
2685 .disconnect = ng_ct_disconnect
2686};
2687
2688#if __FreeBSD_version < 400000
2689NETGRAPH_INIT_ORDERED (ct, &typestruct, SI_SUB_DRIVERS,\
2690 SI_ORDER_MIDDLE + CDEV_MAJOR);
2691#endif
2692#endif /*NETGRAPH*/
2693
2694#if __FreeBSD_version >= 500000
2695#ifdef NETGRAPH
2696MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2697#else
2698MODULE_DEPEND (ct, sppp, 1, 1, 1);
2699#endif
2700#ifdef KLD_MODULE
2701DRIVER_MODULE (ctmod, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2702#else
2703DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2704#endif
2705#elif __FreeBSD_version >= 400000
2706#ifdef NETGRAPH
2707DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, ng_mod_event, &typestruct);
2708#else
2709DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, ct_modevent, 0);
2710#endif
2711#else /* __FreeBSD_version < 400000 */
2712#ifdef KLD_MODULE
2713#ifndef NETGRAPH
2714static moduledata_t ctmod = { "ct", ct_modevent, };
2715DECLARE_MODULE (ct, ctmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR);
2716#endif /* !NETGRAPH */
2717#else /* KLD_MODULE */
2718
2719/*
2720 * Now for some driver initialisation.
2721 * Occurs ONCE during boot (very early).
2722 * This is if we are NOT a loadable module.
2723 */
2724static void ct_drvinit (void *unused)
2725{
2726 dev_t dev;
2727
2728 dev = makedev (CDEV_MAJOR, 0);
2729 cdevsw_add (&dev, &ct_cdevsw, NULL);
2730
2731 /* Activate the timeout routine. */
2732 timeout_handle = timeout (ct_timeout, 0, hz);
2733#ifdef NETGRAPH
2734#if 0
2735 /* Register our node type in netgraph */
2736 if (ng_newtype (&typestruct))
2737 printf ("Failed to register ng_ct\n");
2738#endif
2739#endif
2740}
2741
2742SYSINIT (ctdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, ct_drvinit, 0)
2743#endif /* KLD_MODULE */
2744#endif /* __FreeBSD_version < 400000 */
2745#endif /* NCTAU */