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