if_cp.c revision 131108
1/*
2 * Cronyx-Tau-PCI adapter driver for FreeBSD.
3 * Supports PPP/HDLC, Cisco/HDLC and FrameRelay 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) 1999-2004 Cronyx Engineering.
8 * Author: Kurakin Roman, <rik@cronyx.ru>
9 *
10 * Copyright (C) 1999-2002 Cronyx Engineering.
11 * Author: Serge Vakulenko, <vak@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_cp.c,v 1.1.2.41 2004/06/23 17:09:13 rik Exp $
22 */
23
24#include <sys/cdefs.h>
25__FBSDID("$FreeBSD: head/sys/dev/cp/if_cp.c 131108 2004-06-25 19:22:05Z julian $");
26
27#include <sys/param.h>
28
29#if __FreeBSD_version >= 500000
30#   define NPCI 1
31#else
32#   include "pci.h"
33#endif
34
35#if NPCI > 0
36
37#include <sys/ucred.h>
38#include <sys/proc.h>
39#include <sys/systm.h>
40#include <sys/mbuf.h>
41#include <sys/kernel.h>
42#include <sys/module.h>
43#include <sys/conf.h>
44#include <sys/malloc.h>
45#include <sys/socket.h>
46#include <sys/sockio.h>
47#include <sys/tty.h>
48#include <sys/bus.h>
49#include <vm/vm.h>
50#include <vm/pmap.h>
51#include <net/if.h>
52#if __FreeBSD_version > 501000
53#   include <dev/pci/pcivar.h>
54#   include <dev/pci/pcireg.h>
55#else
56#   include <pci/pcivar.h>
57#   include <pci/pcireg.h>
58#endif
59#include <machine/bus.h>
60#include <sys/rman.h>
61#include "opt_ng_cronyx.h"
62#ifdef NETGRAPH_CRONYX
63#   include "opt_netgraph.h"
64#   ifndef NETGRAPH
65#       error #option	NETGRAPH missed from configuration
66#   endif
67#   include <netgraph/ng_message.h>
68#   include <netgraph/netgraph.h>
69#   include <dev/cp/ng_cp.h>
70#else
71#   include <net/if_sppp.h>
72#   define PP_CISCO IFF_LINK2
73#   if __FreeBSD_version < 500000
74#       include <bpf.h>
75#   endif
76#   include <net/bpf.h>
77#   define NBPFILTER NBPF
78#endif
79#include <dev/cx/machdep.h>
80#include <dev/cp/cpddk.h>
81#include <machine/cserial.h>
82#include <machine/resource.h>
83#include <machine/pmap.h>
84
85/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
86#ifndef PP_FR
87#define PP_FR 0
88#endif
89
90#define CP_DEBUG(d,s)	({if (d->chan->debug) {\
91				printf ("%s: ", d->name); printf s;}})
92#define CP_DEBUG2(d,s)	({if (d->chan->debug>1) {\
93				printf ("%s: ", d->name); printf s;}})
94
95#define CDEV_MAJOR	134
96
97static	int cp_probe		__P((device_t));
98static	int cp_attach		__P((device_t));
99static	int cp_detach		__P((device_t));
100
101static	device_method_t cp_methods[] = {
102	/* Device interface */
103	DEVMETHOD(device_probe,		cp_probe),
104	DEVMETHOD(device_attach,	cp_attach),
105	DEVMETHOD(device_detach,	cp_detach),
106
107	{0, 0}
108};
109
110typedef struct _cp_dma_mem_t {
111	unsigned long	phys;
112	void		*virt;
113	size_t		size;
114#if __FreeBSD_version >= 500000
115	bus_dma_tag_t	dmat;
116	bus_dmamap_t	mapp;
117#endif
118} cp_dma_mem_t;
119
120typedef struct _drv_t {
121	char name [8];
122	cp_chan_t *chan;
123	cp_board_t *board;
124	cp_dma_mem_t dmamem;
125	int running;
126#ifdef NETGRAPH
127	char	nodename [NG_NODELEN+1];
128	hook_p	hook;
129	hook_p	debug_hook;
130	node_p	node;
131	struct	ifqueue queue;
132	struct	ifqueue hi_queue;
133	short	timeout;
134	struct	callout_handle timeout_handle;
135#else
136	struct sppp pp;
137#endif
138	struct cdev *devt;
139} drv_t;
140
141typedef	struct _bdrv_t {
142	cp_board_t	*board;
143	struct resource *cp_res;
144	struct resource *cp_irq;
145	void		*cp_intrhand;
146	cp_dma_mem_t	dmamem;
147	drv_t		channel [NCHAN];
148} bdrv_t;
149
150static	driver_t cp_driver = {
151	"cp",
152	cp_methods,
153	sizeof(bdrv_t),
154};
155
156static	devclass_t cp_devclass;
157
158static void cp_receive (cp_chan_t *c, unsigned char *data, int len);
159static void cp_transmit (cp_chan_t *c, void *attachment, int len);
160static void cp_error (cp_chan_t *c, int data);
161static void cp_up (drv_t *d);
162static void cp_start (drv_t *d);
163static void cp_down (drv_t *d);
164static void cp_watchdog (drv_t *d);
165#ifdef NETGRAPH
166extern struct ng_type typestruct;
167#else
168static void cp_ifstart (struct ifnet *ifp);
169static void cp_tlf (struct sppp *sp);
170static void cp_tls (struct sppp *sp);
171static void cp_ifwatchdog (struct ifnet *ifp);
172static int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
173static void cp_initialize (void *softc);
174#endif
175
176static cp_board_t *adapter [NBRD];
177static drv_t *channel [NBRD*NCHAN];
178static struct callout_handle led_timo [NBRD];
179static struct callout_handle timeout_handle;
180
181static int cp_destroy = 0;
182
183/*
184 * Print the mbuf chain, for debug purposes only.
185 */
186static void printmbuf (struct mbuf *m)
187{
188	printf ("mbuf:");
189	for (; m; m=m->m_next) {
190		if (m->m_flags & M_PKTHDR)
191			printf (" HDR %d:", m->m_pkthdr.len);
192		if (m->m_flags & M_EXT)
193			printf (" EXT:");
194		printf (" %d", m->m_len);
195	}
196	printf ("\n");
197}
198
199/*
200 * Make an mbuf from data.
201 */
202static struct mbuf *makembuf (void *buf, unsigned len)
203{
204	struct mbuf *m;
205
206	MGETHDR (m, M_DONTWAIT, MT_DATA);
207	if (! m)
208		return 0;
209	MCLGET (m, M_DONTWAIT);
210	if (! (m->m_flags & M_EXT)) {
211		m_freem (m);
212		return 0;
213	}
214	m->m_pkthdr.len = m->m_len = len;
215	bcopy (buf, mtod (m, caddr_t), len);
216	return m;
217}
218
219static int cp_probe (device_t dev)
220{
221	if ((pci_get_vendor (dev) == cp_vendor_id) &&
222	    (pci_get_device (dev) == cp_device_id)) {
223		device_set_desc (dev, "Cronyx-Tau-PCI serial adapter");
224		return 0;
225	}
226	return ENXIO;
227}
228
229static void cp_timeout (void *arg)
230{
231	drv_t *d;
232	int s, i;
233
234	for (i=0; i<NBRD*NCHAN; ++i) {
235		s = splimp ();
236		if (cp_destroy) {
237			splx (s);
238			return;
239		}
240		d = channel[i];
241		if (!d) {
242			splx (s);
243			continue;
244		}
245		switch (d->chan->type) {
246		case T_G703:
247			cp_g703_timer (d->chan);
248			break;
249		case T_E1:
250			cp_e1_timer (d->chan);
251			break;
252		case T_E3:
253		case T_T3:
254		case T_STS1:
255			cp_e3_timer (d->chan);
256			break;
257		default:
258			break;
259		}
260		splx (s);
261	}
262	s = splimp ();
263	if (!cp_destroy)
264		timeout_handle = timeout (cp_timeout, 0, hz);
265	splx (s);
266}
267
268static void cp_led_off (void *arg)
269{
270	cp_board_t *b = arg;
271	int s = splimp ();
272	if (cp_destroy) {
273		splx (s);
274		return;
275	}
276	cp_led (b, 0);
277	led_timo[b->num].callout = 0;
278	splx (s);
279}
280
281static void cp_intr (void *arg)
282{
283	bdrv_t *bd = arg;
284	cp_board_t *b = bd->board;
285	int s = splimp ();
286	if (cp_destroy) {
287		splx (s);
288		return;
289	}
290	/* Turn LED on. */
291	cp_led (b, 1);
292
293	cp_interrupt (b);
294
295	/* Turn LED off 50 msec later. */
296	if (!led_timo[b->num].callout)
297		led_timo[b->num] = timeout (cp_led_off, b, hz/20);
298	splx (s);
299}
300
301extern struct cdevsw cp_cdevsw;
302
303#if __FreeBSD_version >= 500000
304static void
305cp_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
306{
307	unsigned long *addr;
308
309	if (error)
310		return;
311
312	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
313	addr = arg;
314	*addr = segs->ds_addr;
315}
316
317static int
318cp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem)
319{
320	int error;
321
322	error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
323		BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
324		dmem->size, 0, NULL, NULL, &dmem->dmat);
325	if (error) {
326		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
327		else		printf ("cp%d: ", bnum);
328		printf ("couldn't allocate tag for dma memory\n");
329 		return 0;
330	}
331	error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
332		BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
333	if (error) {
334		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
335		else		printf ("cp%d: ", bnum);
336		printf ("couldn't allocate mem for dma memory\n");
337		bus_dma_tag_destroy (dmem->dmat);
338 		return 0;
339	}
340	error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
341		dmem->size, cp_bus_dmamap_addr, &dmem->phys, 0);
342	if (error) {
343		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
344		else		printf ("cp%d: ", bnum);
345		printf ("couldn't load mem map for dma memory\n");
346		bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
347		bus_dma_tag_destroy (dmem->dmat);
348 		return 0;
349	}
350	return 1;
351}
352
353static void
354cp_bus_dma_mem_free (cp_dma_mem_t *dmem)
355{
356	bus_dmamap_unload (dmem->dmat, dmem->mapp);
357	bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
358	bus_dma_tag_destroy (dmem->dmat);
359}
360#else
361static int
362cp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem)
363{
364	dmem->virt = contigmalloc (dmem->size, M_DEVBUF, M_WAITOK,
365				   0x100000, 0xffffffff, 16, 0);
366	if (dmem->virt == NULL) {
367		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
368		else		printf ("cp%d: ", bnum);
369		printf ("couldn't allocate memory for dma memory\n", unit);
370 		return 0;
371	}
372	dmem->phys = vtophys (dmem->virt);
373	return 1;
374}
375
376static void
377cp_bus_dma_mem_free (cp_dma_mem_t *dmem)
378{
379	contigfree (dmem->virt, dmem->size, M_DEVBUF);
380}
381#endif
382
383/*
384 * Called if the probe succeeded.
385 */
386static int cp_attach (device_t dev)
387{
388	bdrv_t *bd = device_get_softc (dev);
389	int unit = device_get_unit (dev);
390	unsigned short res;
391	vm_offset_t vbase;
392	int rid, error;
393	cp_board_t *b;
394	cp_chan_t *c;
395	drv_t *d;
396	int s = splimp ();
397
398	b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK);
399	if (!b) {
400		printf ("cp%d: couldn't allocate memory\n", unit);
401		splx (s);
402		return (ENXIO);
403	}
404	adapter[unit] = b;
405	bzero (b, sizeof(cp_board_t));
406
407	bd->board = b;
408	b->sys = bd;
409	rid = PCIR_BAR(0);
410	bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid,
411			0, ~0, 1, RF_ACTIVE);
412	if (! bd->cp_res) {
413		printf ("cp%d: cannot map memory\n", unit);
414		free (b, M_DEVBUF);
415		splx (s);
416		return (ENXIO);
417	}
418	vbase = (vm_offset_t) rman_get_virtual (bd->cp_res);
419
420	res = cp_init (b, unit, (u_char*) vbase);
421	if (res) {
422		printf ("cp%d: can't init, error code:%x\n", unit, res);
423		bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
424		free (b, M_DEVBUF);
425		splx (s);
426 		return (ENXIO);
427	}
428
429	bd->dmamem.size = sizeof(cp_qbuf_t);
430	if (! cp_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) {
431		free (b, M_DEVBUF);
432		splx (s);
433 		return (ENXIO);
434	}
435	cp_reset (b, bd->dmamem.virt, bd->dmamem.phys);
436
437	rid = 0;
438	bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
439			RF_SHAREABLE | RF_ACTIVE);
440       	if (! bd->cp_irq) {
441		printf ("cp%d: cannot map interrupt\n", unit);
442		bus_release_resource (dev, SYS_RES_MEMORY,
443				PCIR_BAR(0), bd->cp_res);
444		free (b, M_DEVBUF);
445		splx (s);
446		return (ENXIO);
447	}
448	error  = bus_setup_intr (dev, bd->cp_irq, INTR_TYPE_NET, cp_intr, bd,
449				&bd->cp_intrhand);
450	if (error) {
451		printf ("cp%d: cannot set up irq\n", unit);
452		bus_release_resource (dev, SYS_RES_MEMORY,
453				PCIR_BAR(0), bd->cp_res);
454		bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
455		free (b, M_DEVBUF);
456		splx (s);
457		return (ENXIO);
458	}
459	printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000);
460
461	for (c=b->chan; c<b->chan+NCHAN; ++c) {
462		if (! c->type)
463			continue;
464		d = &bd->channel[c->num];
465		d->dmamem.size = sizeof(cp_buf_t);
466		if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
467			continue;
468		channel [b->num*NCHAN + c->num] = d;
469		sprintf (d->name, "cp%d.%d", b->num, c->num);
470		d->board = b;
471		d->chan = c;
472		c->sys = d;
473#ifdef NETGRAPH
474		if (ng_make_node_common (&typestruct, &d->node) != 0) {
475			printf ("%s: cannot make common node\n", d->name);
476			d->node = NULL;
477			continue;
478		}
479#if __FreeBSD_version >= 500000
480		NG_NODE_SET_PRIVATE (d->node, d);
481#else
482		d->node->private = d;
483#endif
484		sprintf (d->nodename, "%s%d", NG_CP_NODE_TYPE,
485			 c->board->num*NCHAN + c->num);
486		if (ng_name_node (d->node, d->nodename)) {
487			printf ("%s: cannot name node\n", d->nodename);
488#if __FreeBSD_version >= 500000
489			NG_NODE_UNREF (d->node);
490#else
491			ng_rmnode (d->node);
492			ng_unref (d->node);
493#endif
494			continue;
495		}
496		d->queue.ifq_maxlen = IFQ_MAXLEN;
497		d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
498#if __FreeBSD_version >= 500000
499		mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF);
500		mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF);
501#endif
502#else /*NETGRAPH*/
503		d->pp.pp_if.if_softc    = d;
504#if __FreeBSD_version > 501000
505		if_initname (&d->pp.pp_if, "cp", b->num * NCHAN + c->num);
506#else
507		d->pp.pp_if.if_unit     = b->num * NCHAN + c->num;
508		d->pp.pp_if.if_name     = "cp";
509#endif
510		d->pp.pp_if.if_mtu      = PP_MTU;
511		d->pp.pp_if.if_flags    = IFF_POINTOPOINT | IFF_MULTICAST;
512		d->pp.pp_if.if_ioctl    = cp_sioctl;
513		d->pp.pp_if.if_start    = cp_ifstart;
514		d->pp.pp_if.if_watchdog = cp_ifwatchdog;
515		d->pp.pp_if.if_init     = cp_initialize;
516		sppp_attach (&d->pp.pp_if);
517		if_attach (&d->pp.pp_if);
518		d->pp.pp_tlf		= cp_tlf;
519		d->pp.pp_tls		= cp_tls;
520		/* If BPF is in the kernel, call the attach for it.
521		 * The header size of PPP or Cisco/HDLC is 4 bytes. */
522		bpfattach (&d->pp.pp_if, DLT_PPP, 4);
523#endif /*NETGRAPH*/
524		cp_start_e1 (c);
525		cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys);
526
527		/* Register callback functions. */
528		cp_register_transmit (c, &cp_transmit);
529		cp_register_receive (c, &cp_receive);
530		cp_register_error (c, &cp_error);
531		d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
532				GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num);
533	}
534	splx (s);
535	return 0;
536}
537
538static int cp_detach (device_t dev)
539{
540	bdrv_t *bd = device_get_softc (dev);
541        cp_board_t *b = bd->board;
542	cp_chan_t *c;
543	int s = splimp ();
544
545	/* Check if the device is busy (open). */
546	for (c=b->chan; c<b->chan+NCHAN; ++c) {
547		drv_t *d = (drv_t*) c->sys;
548
549		if (! d || ! d->chan->type)
550			continue;
551		if (d->running) {
552			splx (s);
553			return EBUSY;
554		}
555	}
556
557	/* Ok, we can unload driver */
558	/* At first we should stop all channels */
559	for (c=b->chan; c<b->chan+NCHAN; ++c) {
560		drv_t *d = (drv_t*) c->sys;
561
562		if (! d || ! d->chan->type)
563			continue;
564
565		cp_stop_chan (c);
566		cp_stop_e1 (c);
567		cp_set_dtr (d->chan, 0);
568		cp_set_rts (d->chan, 0);
569	}
570
571	/* Reset the adapter. */
572	cp_destroy = 1;
573	cp_interrupt_poll (b, 1);
574	cp_led_off (b);
575	cp_reset (b, 0 ,0);
576	if (led_timo[b->num].callout)
577		untimeout (cp_led_off, b, led_timo[b->num]);
578
579	for (c=b->chan; c<b->chan+NCHAN; ++c) {
580		drv_t *d = (drv_t*) c->sys;
581
582		if (! d || ! d->chan->type)
583			continue;
584#ifndef NETGRAPH
585#if __FreeBSD_version >= 410000 && NBPFILTER > 0
586		/* Detach from the packet filter list of interfaces. */
587		bpfdetach (&d->pp.pp_if);
588#endif
589		/* Detach from the sync PPP list. */
590		sppp_detach (&d->pp.pp_if);
591
592		/* Detach from the system list of interfaces. */
593		if_detach (&d->pp.pp_if);
594#else
595#if __FreeBSD_version >= 500000
596		if (d->node) {
597			ng_rmnode_self (d->node);
598			NG_NODE_UNREF (d->node);
599			d->node = NULL;
600		}
601		mtx_destroy (&d->queue.ifq_mtx);
602		mtx_destroy (&d->hi_queue.ifq_mtx);
603#else
604		ng_rmnode (d->node);
605		d->node = 0;
606#endif
607#endif
608		destroy_dev (d->devt);
609	}
610
611	/* Disable the interrupt request. */
612	bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand);
613	bus_deactivate_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
614	bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
615	bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
616	cp_led_off (b);
617	if (led_timo[b->num].callout)
618		untimeout (cp_led_off, b, led_timo[b->num]);
619	splx (s);
620
621	s = splimp ();
622	for (c=b->chan; c<b->chan+NCHAN; ++c) {
623		drv_t *d = (drv_t*) c->sys;
624
625		if (! d || ! d->chan->type)
626			continue;
627		channel [b->num*NCHAN + c->num] = 0;
628		/* Deallocate buffers. */
629		cp_bus_dma_mem_free (&d->dmamem);
630	}
631	adapter [b->num] = 0;
632	cp_bus_dma_mem_free (&bd->dmamem);
633	free (b, M_DEVBUF);
634	splx (s);
635	return 0;
636}
637
638#ifndef NETGRAPH
639static void cp_ifstart (struct ifnet *ifp)
640{
641        drv_t *d = ifp->if_softc;
642
643	cp_start (d);
644}
645
646static void cp_ifwatchdog (struct ifnet *ifp)
647{
648        drv_t *d = ifp->if_softc;
649
650	cp_watchdog (d);
651}
652
653static void cp_tlf (struct sppp *sp)
654{
655	drv_t *d = sp->pp_if.if_softc;
656
657	CP_DEBUG2 (d, ("cp_tlf\n"));
658/*	cp_set_dtr (d->chan, 0);*/
659/*	cp_set_rts (d->chan, 0);*/
660	sp->pp_down (sp);
661}
662
663static void cp_tls (struct sppp *sp)
664{
665	drv_t *d = sp->pp_if.if_softc;
666
667	CP_DEBUG2 (d, ("cp_tls\n"));
668	sp->pp_up (sp);
669}
670
671/*
672 * Process an ioctl request.
673 */
674static int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
675{
676	drv_t *d = ifp->if_softc;
677	int error, s, was_up, should_be_up;
678
679	was_up = (ifp->if_flags & IFF_RUNNING) != 0;
680	error = sppp_ioctl (ifp, cmd, data);
681
682	if (error)
683		return error;
684
685	if (! (ifp->if_flags & IFF_DEBUG))
686		d->chan->debug = 0;
687	else if (! d->chan->debug)
688		d->chan->debug = 1;
689
690	switch (cmd) {
691	default:           CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd));   return 0;
692	case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0;
693	case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0;
694	case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break;
695	case SIOCSIFADDR:  CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n"));  break;
696	}
697
698	/* We get here only in case of SIFFLAGS or SIFADDR. */
699	s = splimp ();
700	should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
701	if (! was_up && should_be_up) {
702		/* Interface goes up -- start it. */
703		cp_up (d);
704		cp_start (d);
705	} else if (was_up && ! should_be_up) {
706		/* Interface is going down -- stop it. */
707/*		if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
708		cp_down (d);
709	}
710	CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd));
711	splx (s);
712	return 0;
713}
714
715/*
716 * Initialization of interface.
717 * It seems to be never called by upper level?
718 */
719static void cp_initialize (void *softc)
720{
721	drv_t *d = softc;
722
723	CP_DEBUG (d, ("cp_initialize\n"));
724}
725#endif /*NETGRAPH*/
726
727/*
728 * Stop the interface.  Called on splimp().
729 */
730static void cp_down (drv_t *d)
731{
732	CP_DEBUG (d, ("cp_down\n"));
733	/* Interface is going down -- stop it. */
734	cp_set_dtr (d->chan, 0);
735	cp_set_rts (d->chan, 0);
736
737	d->running = 0;
738}
739
740/*
741 * Start the interface.  Called on splimp().
742 */
743static void cp_up (drv_t *d)
744{
745	CP_DEBUG (d, ("cp_up\n"));
746	cp_set_dtr (d->chan, 1);
747	cp_set_rts (d->chan, 1);
748	d->running = 1;
749}
750
751/*
752 * Start output on the interface.  Get another datagram to send
753 * off of the interface queue, and copy it to the interface
754 * before starting the output.
755 */
756static void cp_send (drv_t *d)
757{
758	struct mbuf *m;
759	u_short len;
760
761	CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te));
762
763	/* No output if the interface is down. */
764	if (! d->running)
765		return;
766
767	/* No output if the modem is off. */
768	if (! (d->chan->lloop || d->chan->type != T_SERIAL ||
769		cp_get_dsr (d->chan)))
770		return;
771
772	while (cp_transmit_space (d->chan)) {
773		/* Get the packet to send. */
774#ifdef NETGRAPH
775		IF_DEQUEUE (&d->hi_queue, m);
776		if (! m)
777			IF_DEQUEUE (&d->queue, m);
778#else
779		m = sppp_dequeue (&d->pp.pp_if);
780#endif
781		if (! m)
782			return;
783#ifndef NETGRAPH
784		if (d->pp.pp_if.if_bpf)
785#if __FreeBSD_version >= 500000
786			BPF_MTAP (&d->pp.pp_if, m);
787#else
788			bpf_mtap (&d->pp.pp_if, m);
789#endif
790#endif
791		len = m->m_pkthdr.len;
792		if (len >= BUFSZ)
793			printf ("%s: too long packet: %d bytes: ",
794				d->name, len);
795		else if (! m->m_next)
796			cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0);
797		else {
798			u_char *buf = d->chan->tbuf[d->chan->te];
799			m_copydata (m, 0, len, buf);
800			cp_send_packet (d->chan, buf, len, 0);
801		}
802		m_freem (m);
803		/* Set up transmit timeout, if the transmit ring is not empty.*/
804#ifdef NETGRAPH
805		d->timeout = 10;
806#else
807		d->pp.pp_if.if_timer = 10;
808#endif
809	}
810#ifndef NETGRAPH
811	d->pp.pp_if.if_flags |= IFF_OACTIVE;
812#endif
813}
814
815/*
816 * Start output on the interface.
817 * Always called on splimp().
818 */
819static void cp_start (drv_t *d)
820{
821        if (d->running) {
822		if (! d->chan->dtr)
823			cp_set_dtr (d->chan, 1);
824		if (! d->chan->rts)
825			cp_set_rts (d->chan, 1);
826		cp_send (d);
827	}
828}
829
830/*
831 * Handle transmit timeouts.
832 * Recover after lost transmit interrupts.
833 * Always called on splimp().
834 */
835static void cp_watchdog (drv_t *d)
836{
837	CP_DEBUG (d, ("device timeout\n"));
838	if (d->running) {
839		int s = splimp ();
840
841		cp_stop_chan (d->chan);
842		cp_stop_e1 (d->chan);
843		cp_start_e1 (d->chan);
844		cp_start_chan (d->chan, 1, 1, 0, 0);
845		cp_set_dtr (d->chan, 1);
846		cp_set_rts (d->chan, 1);
847		cp_start (d);
848		splx (s);
849	}
850}
851
852static void cp_transmit (cp_chan_t *c, void *attachment, int len)
853{
854	drv_t *d = c->sys;
855
856#ifdef NETGRAPH
857	d->timeout = 0;
858#else
859	++d->pp.pp_if.if_opackets;
860	d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
861	d->pp.pp_if.if_timer = 0;
862#endif
863	cp_start (d);
864}
865
866static void cp_receive (cp_chan_t *c, unsigned char *data, int len)
867{
868	drv_t *d = c->sys;
869	struct mbuf *m;
870#if __FreeBSD_version >= 500000 && defined NETGRAPH
871	int error;
872#endif
873
874	if (! d->running)
875		return;
876
877	m = makembuf (data, len);
878	if (! m) {
879		CP_DEBUG (d, ("no memory for packet\n"));
880#ifndef NETGRAPH
881		++d->pp.pp_if.if_iqdrops;
882#endif
883		return;
884	}
885	if (c->debug > 1)
886		printmbuf (m);
887#ifdef NETGRAPH
888	m->m_pkthdr.rcvif = 0;
889#if __FreeBSD_version >= 500000
890	NG_SEND_DATA_ONLY (error, d->hook, m);
891#else
892	ng_queue_data (d->hook, m, 0);
893#endif
894#else
895	++d->pp.pp_if.if_ipackets;
896	m->m_pkthdr.rcvif = &d->pp.pp_if;
897	/* Check if there's a BPF listener on this interface.
898	 * If so, hand off the raw packet to bpf. */
899	if (d->pp.pp_if.if_bpf)
900#if __FreeBSD_version >= 500000
901		BPF_TAP (&d->pp.pp_if, data, len);
902#else
903		bpf_tap (&d->pp.pp_if, data, len);
904#endif
905	sppp_input (&d->pp.pp_if, m);
906#endif
907}
908
909static void cp_error (cp_chan_t *c, int data)
910{
911	drv_t *d = c->sys;
912
913	switch (data) {
914	case CP_FRAME:
915		CP_DEBUG (d, ("frame error\n"));
916#ifndef NETGRAPH
917		++d->pp.pp_if.if_ierrors;
918#endif
919		break;
920	case CP_CRC:
921		CP_DEBUG (d, ("crc error\n"));
922#ifndef NETGRAPH
923		++d->pp.pp_if.if_ierrors;
924#endif
925		break;
926	case CP_OVERRUN:
927		CP_DEBUG (d, ("overrun error\n"));
928#ifndef NETGRAPH
929		++d->pp.pp_if.if_collisions;
930		++d->pp.pp_if.if_ierrors;
931#endif
932		break;
933	case CP_OVERFLOW:
934		CP_DEBUG (d, ("overflow error\n"));
935#ifndef NETGRAPH
936		++d->pp.pp_if.if_ierrors;
937#endif
938		break;
939	case CP_UNDERRUN:
940		CP_DEBUG (d, ("underrun error\n"));
941#ifdef NETGRAPH
942		d->timeout = 0;
943#else
944		++d->pp.pp_if.if_oerrors;
945		d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
946		d->pp.pp_if.if_timer = 0;
947#endif
948		cp_start (d);
949		break;
950	default:
951		CP_DEBUG (d, ("error #%d\n", data));
952		break;
953	}
954}
955
956/*
957 * You also need read, write, open, close routines.
958 * This should get you started
959 */
960#if __FreeBSD_version < 500000
961static int cp_open (dev_t dev, int oflags, int devtype, struct proc *p)
962#else
963static int cp_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
964#endif
965{
966	int unit = minor (dev);
967	drv_t *d;
968
969	if (unit >= NBRD*NCHAN || ! (d = channel[unit]))
970		return ENXIO;
971	CP_DEBUG2 (d, ("cp_open\n"));
972	return 0;
973}
974
975/*
976 * Only called on the LAST close.
977 */
978#if __FreeBSD_version < 500000
979static int cp_close (dev_t dev, int fflag, int devtype, struct proc *p)
980#else
981static int cp_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
982#endif
983{
984	drv_t *d = channel [minor (dev)];
985
986	CP_DEBUG2 (d, ("cp_close\n"));
987	return 0;
988}
989
990static int cp_modem_status (cp_chan_t *c)
991{
992	drv_t *d = c->sys;
993	int status, s;
994
995	status = d->running ? TIOCM_LE : 0;
996	s = splimp ();
997	if (cp_get_cd  (c)) status |= TIOCM_CD;
998	if (cp_get_cts (c)) status |= TIOCM_CTS;
999	if (cp_get_dsr (c)) status |= TIOCM_DSR;
1000	if (c->dtr)	    status |= TIOCM_DTR;
1001	if (c->rts)	    status |= TIOCM_RTS;
1002	splx (s);
1003	return status;
1004}
1005
1006#if __FreeBSD_version < 500000
1007static int cp_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1008#else
1009static int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1010#endif
1011{
1012        drv_t *d = channel [minor (dev)];
1013	cp_chan_t *c = d->chan;
1014	struct serial_statistics *st;
1015	struct e1_statistics *opte1;
1016	struct e3_statistics *opte3;
1017	int error, s;
1018	char mask[16];
1019
1020	switch (cmd) {
1021	case SERIAL_GETREGISTERED:
1022	        CP_DEBUG2 (d, ("ioctl: getregistered\n"));
1023		bzero (mask, sizeof(mask));
1024		for (s=0; s<NBRD*NCHAN; ++s)
1025			if (channel [s])
1026				mask [s/8] |= 1 << (s & 7);
1027	        bcopy (mask, data, sizeof (mask));
1028		return 0;
1029
1030#ifndef NETGRAPH
1031	case SERIAL_GETPROTO:
1032	        CP_DEBUG2 (d, ("ioctl: getproto\n"));
1033	        strcpy ((char*)data, (d->pp.pp_flags & PP_FR) ? "fr" :
1034			(d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp");
1035	        return 0;
1036
1037	case SERIAL_SETPROTO:
1038	        CP_DEBUG2 (d, ("ioctl: setproto\n"));
1039	        /* Only for superuser! */
1040#if __FreeBSD_version < 500000
1041	        error = suser (p);
1042#else /* __FreeBSD_version >= 500000 */
1043	        error = suser (td);
1044#endif /* __FreeBSD_version >= 500000 */
1045	        if (error)
1046	                return error;
1047		if (d->pp.pp_if.if_flags & IFF_RUNNING)
1048			return EBUSY;
1049	        if (! strcmp ("cisco", (char*)data)) {
1050	                d->pp.pp_flags &= ~(PP_FR);
1051	                d->pp.pp_flags |= PP_KEEPALIVE;
1052	                d->pp.pp_if.if_flags |= PP_CISCO;
1053	        } else if (! strcmp ("fr", (char*)data) && !PP_FR) {
1054	                d->pp.pp_if.if_flags &= ~(PP_CISCO);
1055	                d->pp.pp_flags |= PP_FR | PP_KEEPALIVE;
1056	        } else if (! strcmp ("ppp", (char*)data)) {
1057	                d->pp.pp_flags &= ~PP_FR;
1058	                d->pp.pp_flags &= ~PP_KEEPALIVE;
1059	                d->pp.pp_if.if_flags &= ~(PP_CISCO);
1060	        } else
1061			return EINVAL;
1062	        return 0;
1063
1064	case SERIAL_GETKEEPALIVE:
1065	        CP_DEBUG2 (d, ("ioctl: getkeepalive\n"));
1066	        if ((d->pp.pp_flags & PP_FR) ||
1067			(d->pp.pp_if.if_flags & PP_CISCO))
1068			return EINVAL;
1069	        *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0;
1070	        return 0;
1071
1072	case SERIAL_SETKEEPALIVE:
1073	        CP_DEBUG2 (d, ("ioctl: setkeepalive\n"));
1074	        /* Only for superuser! */
1075#if __FreeBSD_version < 500000
1076	        error = suser (p);
1077#else
1078	        error = suser (td);
1079#endif
1080	        if (error)
1081	                return error;
1082	        if ((d->pp.pp_flags & PP_FR) ||
1083			(d->pp.pp_if.if_flags & PP_CISCO))
1084			return EINVAL;
1085		s = splimp ();
1086	        if (*(int*)data)
1087	                d->pp.pp_flags |= PP_KEEPALIVE;
1088		else
1089	                d->pp.pp_flags &= ~PP_KEEPALIVE;
1090		splx (s);
1091	        return 0;
1092#endif /*NETGRAPH*/
1093
1094	case SERIAL_GETMODE:
1095	        CP_DEBUG2 (d, ("ioctl: getmode\n"));
1096		*(int*)data = SERIAL_HDLC;
1097	        return 0;
1098
1099	case SERIAL_SETMODE:
1100	        /* Only for superuser! */
1101#if __FreeBSD_version < 500000
1102	        error = suser (p);
1103#else
1104	        error = suser (td);
1105#endif
1106	        if (error)
1107	                return error;
1108		if (*(int*)data != SERIAL_HDLC)
1109			return EINVAL;
1110                return 0;
1111
1112	case SERIAL_GETCFG:
1113	        CP_DEBUG2 (d, ("ioctl: getcfg\n"));
1114		if (c->type != T_E1 || c->unfram)
1115			return EINVAL;
1116		*(char*)data = c->board->mux ? 'c' : 'a';
1117	        return 0;
1118
1119	case SERIAL_SETCFG:
1120	        CP_DEBUG2 (d, ("ioctl: setcfg\n"));
1121#if __FreeBSD_version < 500000
1122	        error = suser (p);
1123#else
1124	        error = suser (td);
1125#endif
1126	        if (error)
1127	                return error;
1128		if (c->type != T_E1)
1129			return EINVAL;
1130	        s = splimp ();
1131		cp_set_mux (c->board, *((char*)data) == 'c');
1132	        splx (s);
1133                return 0;
1134
1135	case SERIAL_GETSTAT:
1136	        CP_DEBUG2 (d, ("ioctl: getstat\n"));
1137	        st = (struct serial_statistics*) data;
1138	        st->rintr  = c->rintr;
1139	        st->tintr  = c->tintr;
1140	        st->mintr  = 0;
1141	        st->ibytes = c->ibytes;
1142	        st->ipkts  = c->ipkts;
1143	        st->obytes = c->obytes;
1144	        st->opkts  = c->opkts;
1145		st->ierrs  = c->overrun + c->frame + c->crc;
1146		st->oerrs  = c->underrun;
1147	        return 0;
1148
1149	case SERIAL_GETESTAT:
1150	        CP_DEBUG2 (d, ("ioctl: getestat\n"));
1151		if (c->type != T_E1 && c->type != T_G703)
1152			return EINVAL;
1153		opte1 = (struct e1_statistics*) data;
1154		opte1->status	    = c->status;
1155		opte1->cursec	    = c->cursec;
1156		opte1->totsec	    = c->totsec + c->cursec;
1157
1158		opte1->currnt.bpv   = c->currnt.bpv;
1159		opte1->currnt.fse   = c->currnt.fse;
1160		opte1->currnt.crce  = c->currnt.crce;
1161		opte1->currnt.rcrce = c->currnt.rcrce;
1162		opte1->currnt.uas   = c->currnt.uas;
1163		opte1->currnt.les   = c->currnt.les;
1164		opte1->currnt.es    = c->currnt.es;
1165		opte1->currnt.bes   = c->currnt.bes;
1166		opte1->currnt.ses   = c->currnt.ses;
1167		opte1->currnt.oofs  = c->currnt.oofs;
1168		opte1->currnt.css   = c->currnt.css;
1169		opte1->currnt.dm    = c->currnt.dm;
1170
1171		opte1->total.bpv    = c->total.bpv   + c->currnt.bpv;
1172		opte1->total.fse    = c->total.fse   + c->currnt.fse;
1173		opte1->total.crce   = c->total.crce  + c->currnt.crce;
1174		opte1->total.rcrce  = c->total.rcrce + c->currnt.rcrce;
1175		opte1->total.uas    = c->total.uas   + c->currnt.uas;
1176		opte1->total.les    = c->total.les   + c->currnt.les;
1177		opte1->total.es	    = c->total.es    + c->currnt.es;
1178		opte1->total.bes    = c->total.bes   + c->currnt.bes;
1179		opte1->total.ses    = c->total.ses   + c->currnt.ses;
1180		opte1->total.oofs   = c->total.oofs  + c->currnt.oofs;
1181		opte1->total.css    = c->total.css   + c->currnt.css;
1182		opte1->total.dm	    = c->total.dm    + c->currnt.dm;
1183		for (s=0; s<48; ++s) {
1184			opte1->interval[s].bpv   = c->interval[s].bpv;
1185			opte1->interval[s].fse   = c->interval[s].fse;
1186			opte1->interval[s].crce  = c->interval[s].crce;
1187			opte1->interval[s].rcrce = c->interval[s].rcrce;
1188			opte1->interval[s].uas   = c->interval[s].uas;
1189			opte1->interval[s].les   = c->interval[s].les;
1190			opte1->interval[s].es	 = c->interval[s].es;
1191			opte1->interval[s].bes   = c->interval[s].bes;
1192			opte1->interval[s].ses   = c->interval[s].ses;
1193			opte1->interval[s].oofs  = c->interval[s].oofs;
1194			opte1->interval[s].css   = c->interval[s].css;
1195			opte1->interval[s].dm	 = c->interval[s].dm;
1196		}
1197		return 0;
1198
1199	case SERIAL_GETE3STAT:
1200	        CP_DEBUG2 (d, ("ioctl: gete3stat\n"));
1201		if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1202			return EINVAL;
1203	        opte3 = (struct e3_statistics*) data;
1204
1205		opte3->status = c->e3status;
1206		opte3->cursec = (c->e3csec_5 * 2 + 1) / 10;
1207		opte3->totsec = c->e3tsec + opte3->cursec;
1208
1209		opte3->ccv = c->e3ccv;
1210		opte3->tcv = c->e3tcv + opte3->ccv;
1211
1212		for (s = 0; s < 48; ++s) {
1213			opte3->icv[s] = c->e3icv[s];
1214		}
1215	        return 0;
1216
1217	case SERIAL_CLRSTAT:
1218	        CP_DEBUG2 (d, ("ioctl: clrstat\n"));
1219	        /* Only for superuser! */
1220#if __FreeBSD_version < 500000
1221	        error = suser (p);
1222#else
1223	        error = suser (td);
1224#endif
1225	        if (error)
1226	                return error;
1227		c->rintr    = 0;
1228		c->tintr    = 0;
1229		c->ibytes   = 0;
1230		c->obytes   = 0;
1231		c->ipkts    = 0;
1232		c->opkts    = 0;
1233		c->overrun  = 0;
1234		c->frame    = 0;
1235		c->crc      = 0;
1236		c->underrun = 0;
1237		bzero (&c->currnt, sizeof (c->currnt));
1238		bzero (&c->total, sizeof (c->total));
1239		bzero (c->interval, sizeof (c->interval));
1240		c->e3ccv    = 0;
1241		c->e3tcv    = 0;
1242		bzero (c->e3icv, sizeof (c->e3icv));
1243	        return 0;
1244
1245	case SERIAL_GETBAUD:
1246	        CP_DEBUG2 (d, ("ioctl: getbaud\n"));
1247	        *(long*)data = c->baud;
1248	        return 0;
1249
1250	case SERIAL_SETBAUD:
1251	        CP_DEBUG2 (d, ("ioctl: setbaud\n"));
1252	        /* Only for superuser! */
1253#if __FreeBSD_version < 500000
1254	        error = suser (p);
1255#else
1256	        error = suser (td);
1257#endif
1258	        if (error)
1259	                return error;
1260	        s = splimp ();
1261	        cp_set_baud (c, *(long*)data);
1262	        splx (s);
1263	        return 0;
1264
1265	case SERIAL_GETLOOP:
1266	        CP_DEBUG2 (d, ("ioctl: getloop\n"));
1267	        *(int*)data = c->lloop;
1268	        return 0;
1269
1270	case SERIAL_SETLOOP:
1271	        CP_DEBUG2 (d, ("ioctl: setloop\n"));
1272	        /* Only for superuser! */
1273#if __FreeBSD_version < 500000
1274	        error = suser (p);
1275#else
1276	        error = suser (td);
1277#endif
1278	        if (error)
1279	                return error;
1280	        s = splimp ();
1281		cp_set_lloop (c, *(int*)data);
1282	        splx (s);
1283	        return 0;
1284
1285	case SERIAL_GETDPLL:
1286	        CP_DEBUG2 (d, ("ioctl: getdpll\n"));
1287	        if (c->type != T_SERIAL)
1288	                return EINVAL;
1289	        *(int*)data = c->dpll;
1290	        return 0;
1291
1292	case SERIAL_SETDPLL:
1293	        CP_DEBUG2 (d, ("ioctl: setdpll\n"));
1294	        /* Only for superuser! */
1295#if __FreeBSD_version < 500000
1296	        error = suser (p);
1297#else
1298	        error = suser (td);
1299#endif
1300	        if (error)
1301	                return error;
1302	        if (c->type != T_SERIAL)
1303	                return EINVAL;
1304	        s = splimp ();
1305	        cp_set_dpll (c, *(int*)data);
1306	        splx (s);
1307	        return 0;
1308
1309	case SERIAL_GETNRZI:
1310	        CP_DEBUG2 (d, ("ioctl: getnrzi\n"));
1311	        if (c->type != T_SERIAL)
1312	                return EINVAL;
1313	        *(int*)data = c->nrzi;
1314	        return 0;
1315
1316	case SERIAL_SETNRZI:
1317	        CP_DEBUG2 (d, ("ioctl: setnrzi\n"));
1318	        /* Only for superuser! */
1319#if __FreeBSD_version < 500000
1320	        error = suser (p);
1321#else
1322	        error = suser (td);
1323#endif
1324	        if (error)
1325	                return error;
1326	        if (c->type != T_SERIAL)
1327	                return EINVAL;
1328	        s = splimp ();
1329	        cp_set_nrzi (c, *(int*)data);
1330	        splx (s);
1331	        return 0;
1332
1333	case SERIAL_GETDEBUG:
1334	        CP_DEBUG2 (d, ("ioctl: getdebug\n"));
1335	        *(int*)data = d->chan->debug;
1336	        return 0;
1337
1338	case SERIAL_SETDEBUG:
1339	        CP_DEBUG2 (d, ("ioctl: setdebug\n"));
1340	        /* Only for superuser! */
1341#if __FreeBSD_version < 500000
1342	        error = suser (p);
1343#else
1344	        error = suser (td);
1345#endif
1346	        if (error)
1347	                return error;
1348	        d->chan->debug = *(int*)data;
1349#ifndef	NETGRAPH
1350		if (d->chan->debug)
1351			d->pp.pp_if.if_flags |= IFF_DEBUG;
1352		else
1353			d->pp.pp_if.if_flags &= ~IFF_DEBUG;
1354#endif
1355	        return 0;
1356
1357	case SERIAL_GETHIGAIN:
1358	        CP_DEBUG2 (d, ("ioctl: gethigain\n"));
1359	        if (c->type != T_E1)
1360	                return EINVAL;
1361	        *(int*)data = c->higain;
1362		return 0;
1363
1364	case SERIAL_SETHIGAIN:
1365	        CP_DEBUG2 (d, ("ioctl: sethigain\n"));
1366	        /* Only for superuser! */
1367#if __FreeBSD_version < 500000
1368	        error = suser (p);
1369#else
1370	        error = suser (td);
1371#endif
1372	        if (error)
1373	                return error;
1374	        if (c->type != T_E1)
1375	                return EINVAL;
1376		s = splimp ();
1377		cp_set_higain (c, *(int*)data);
1378		splx (s);
1379		return 0;
1380
1381	case SERIAL_GETPHONY:
1382		CP_DEBUG2 (d, ("ioctl: getphony\n"));
1383	        if (c->type != T_E1)
1384	                return EINVAL;
1385	        *(int*)data = c->phony;
1386		return 0;
1387
1388	case SERIAL_SETPHONY:
1389		CP_DEBUG2 (d, ("ioctl: setphony\n"));
1390	        /* Only for superuser! */
1391#if __FreeBSD_version < 500000
1392	        error = suser (p);
1393#else
1394	        error = suser (td);
1395#endif
1396	        if (error)
1397	                return error;
1398	        if (c->type != T_E1)
1399	                return EINVAL;
1400		s = splimp ();
1401		cp_set_phony (c, *(int*)data);
1402		splx (s);
1403		return 0;
1404
1405	case SERIAL_GETUNFRAM:
1406		CP_DEBUG2 (d, ("ioctl: getunfram\n"));
1407	        if (c->type != T_E1)
1408	                return EINVAL;
1409	        *(int*)data = c->unfram;
1410		return 0;
1411
1412	case SERIAL_SETUNFRAM:
1413		CP_DEBUG2 (d, ("ioctl: setunfram\n"));
1414	        /* Only for superuser! */
1415#if __FreeBSD_version < 500000
1416	        error = suser (p);
1417#else
1418	        error = suser (td);
1419#endif
1420	        if (error)
1421	                return error;
1422	        if (c->type != T_E1)
1423	                return EINVAL;
1424		s = splimp ();
1425		cp_set_unfram (c, *(int*)data);
1426		splx (s);
1427		return 0;
1428
1429	case SERIAL_GETSCRAMBLER:
1430		CP_DEBUG2 (d, ("ioctl: getscrambler\n"));
1431	        if (c->type != T_G703 && !c->unfram)
1432	                return EINVAL;
1433	        *(int*)data = c->scrambler;
1434		return 0;
1435
1436	case SERIAL_SETSCRAMBLER:
1437		CP_DEBUG2 (d, ("ioctl: setscrambler\n"));
1438	        /* Only for superuser! */
1439#if __FreeBSD_version < 500000
1440	        error = suser (p);
1441#else
1442	        error = suser (td);
1443#endif
1444	        if (error)
1445	                return error;
1446	        if (c->type != T_G703 && !c->unfram)
1447	                return EINVAL;
1448		s = splimp ();
1449		cp_set_scrambler (c, *(int*)data);
1450		splx (s);
1451		return 0;
1452
1453	case SERIAL_GETMONITOR:
1454		CP_DEBUG2 (d, ("ioctl: getmonitor\n"));
1455	        if (c->type != T_E1 &&
1456		    c->type != T_E3 &&
1457		    c->type != T_T3 &&
1458		    c->type != T_STS1)
1459	                return EINVAL;
1460	        *(int*)data = c->monitor;
1461		return 0;
1462
1463	case SERIAL_SETMONITOR:
1464		CP_DEBUG2 (d, ("ioctl: setmonitor\n"));
1465	        /* Only for superuser! */
1466#if __FreeBSD_version < 500000
1467	        error = suser (p);
1468#else
1469	        error = suser (td);
1470#endif
1471	        if (error)
1472	                return error;
1473	        if (c->type != T_E1)
1474	                return EINVAL;
1475		s = splimp ();
1476		cp_set_monitor (c, *(int*)data);
1477		splx (s);
1478		return 0;
1479
1480	case SERIAL_GETUSE16:
1481	        CP_DEBUG2 (d, ("ioctl: getuse16\n"));
1482	        if (c->type != T_E1 || c->unfram)
1483	                return EINVAL;
1484	        *(int*)data = c->use16;
1485		return 0;
1486
1487	case SERIAL_SETUSE16:
1488	        CP_DEBUG2 (d, ("ioctl: setuse16\n"));
1489	        /* Only for superuser! */
1490#if __FreeBSD_version < 500000
1491	        error = suser (p);
1492#else
1493	        error = suser (td);
1494#endif
1495	        if (error)
1496	                return error;
1497	        if (c->type != T_E1)
1498	                return EINVAL;
1499		s = splimp ();
1500		cp_set_use16 (c, *(int*)data);
1501		splx (s);
1502		return 0;
1503
1504	case SERIAL_GETCRC4:
1505	        CP_DEBUG2 (d, ("ioctl: getcrc4\n"));
1506	        if (c->type != T_E1 || c->unfram)
1507	                return EINVAL;
1508	        *(int*)data = c->crc4;
1509		return 0;
1510
1511	case SERIAL_SETCRC4:
1512	        CP_DEBUG2 (d, ("ioctl: setcrc4\n"));
1513	        /* Only for superuser! */
1514#if __FreeBSD_version < 500000
1515	        error = suser (p);
1516#else
1517	        error = suser (td);
1518#endif
1519	        if (error)
1520	                return error;
1521	        if (c->type != T_E1)
1522	                return EINVAL;
1523		s = splimp ();
1524		cp_set_crc4 (c, *(int*)data);
1525		splx (s);
1526		return 0;
1527
1528	case SERIAL_GETCLK:
1529	        CP_DEBUG2 (d, ("ioctl: getclk\n"));
1530	        if (c->type != T_E1 &&
1531		    c->type != T_G703 &&
1532		    c->type != T_E3 &&
1533		    c->type != T_T3 &&
1534		    c->type != T_STS1)
1535	                return EINVAL;
1536		switch (c->gsyn) {
1537		default:	*(int*)data = E1CLK_INTERNAL;		break;
1538		case GSYN_RCV:	*(int*)data = E1CLK_RECEIVE;		break;
1539		case GSYN_RCV0:	*(int*)data = E1CLK_RECEIVE_CHAN0;	break;
1540		case GSYN_RCV1:	*(int*)data = E1CLK_RECEIVE_CHAN1;	break;
1541		case GSYN_RCV2:	*(int*)data = E1CLK_RECEIVE_CHAN2;	break;
1542		case GSYN_RCV3:	*(int*)data = E1CLK_RECEIVE_CHAN3;	break;
1543		}
1544		return 0;
1545
1546	case SERIAL_SETCLK:
1547	        CP_DEBUG2 (d, ("ioctl: setclk\n"));
1548	        /* Only for superuser! */
1549#if __FreeBSD_version < 500000
1550	        error = suser (p);
1551#else
1552	        error = suser (td);
1553#endif
1554	        if (error)
1555	                return error;
1556		if (c->type != T_E1 &&
1557		    c->type != T_G703 &&
1558		    c->type != T_E3 &&
1559		    c->type != T_T3 &&
1560		    c->type != T_STS1)
1561	                return EINVAL;
1562		s = splimp ();
1563		switch (*(int*)data) {
1564		default:		  cp_set_gsyn (c, GSYN_INT);  break;
1565		case E1CLK_RECEIVE:	  cp_set_gsyn (c, GSYN_RCV);  break;
1566		case E1CLK_RECEIVE_CHAN0: cp_set_gsyn (c, GSYN_RCV0); break;
1567		case E1CLK_RECEIVE_CHAN1: cp_set_gsyn (c, GSYN_RCV1); break;
1568		case E1CLK_RECEIVE_CHAN2: cp_set_gsyn (c, GSYN_RCV2); break;
1569		case E1CLK_RECEIVE_CHAN3: cp_set_gsyn (c, GSYN_RCV3); break;
1570		}
1571		splx (s);
1572		return 0;
1573
1574	case SERIAL_GETTIMESLOTS:
1575	        CP_DEBUG2 (d, ("ioctl: gettimeslots\n"));
1576	        if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1577	                return EINVAL;
1578	        *(u_long*)data = c->ts;
1579		return 0;
1580
1581	case SERIAL_SETTIMESLOTS:
1582	        CP_DEBUG2 (d, ("ioctl: settimeslots\n"));
1583	        /* Only for superuser! */
1584#if __FreeBSD_version < 500000
1585	        error = suser (p);
1586#else
1587	        error = suser (td);
1588#endif
1589	        if (error)
1590	                return error;
1591		if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1592	                return EINVAL;
1593		s = splimp ();
1594		cp_set_ts (c, *(u_long*)data);
1595		splx (s);
1596		return 0;
1597
1598	case SERIAL_GETINVCLK:
1599	        CP_DEBUG2 (d, ("ioctl: getinvclk\n"));
1600#if 1
1601		return EINVAL;
1602#else
1603	        if (c->type != T_SERIAL)
1604	                return EINVAL;
1605	        *(int*)data = c->invtxc;
1606		return 0;
1607#endif
1608
1609	case SERIAL_SETINVCLK:
1610	        CP_DEBUG2 (d, ("ioctl: setinvclk\n"));
1611	        /* Only for superuser! */
1612#if __FreeBSD_version < 500000
1613	        error = suser (p);
1614#else
1615	        error = suser (td);
1616#endif
1617	        if (error)
1618	                return error;
1619	        if (c->type != T_SERIAL)
1620	                return EINVAL;
1621		s = splimp ();
1622		cp_set_invtxc (c, *(int*)data);
1623		cp_set_invrxc (c, *(int*)data);
1624		splx (s);
1625		return 0;
1626
1627	case SERIAL_GETINVTCLK:
1628	        CP_DEBUG2 (d, ("ioctl: getinvtclk\n"));
1629	        if (c->type != T_SERIAL)
1630	                return EINVAL;
1631	        *(int*)data = c->invtxc;
1632		return 0;
1633
1634	case SERIAL_SETINVTCLK:
1635	        CP_DEBUG2 (d, ("ioctl: setinvtclk\n"));
1636	        /* Only for superuser! */
1637#if __FreeBSD_version < 500000
1638	        error = suser (p);
1639#else
1640	        error = suser (td);
1641#endif
1642	        if (error)
1643	                return error;
1644	        if (c->type != T_SERIAL)
1645	                return EINVAL;
1646		s = splimp ();
1647		cp_set_invtxc (c, *(int*)data);
1648		splx (s);
1649		return 0;
1650
1651	case SERIAL_GETINVRCLK:
1652	        CP_DEBUG2 (d, ("ioctl: getinvrclk\n"));
1653	        if (c->type != T_SERIAL)
1654	                return EINVAL;
1655	        *(int*)data = c->invrxc;
1656		return 0;
1657
1658	case SERIAL_SETINVRCLK:
1659	        CP_DEBUG2 (d, ("ioctl: setinvrclk\n"));
1660	        /* Only for superuser! */
1661#if __FreeBSD_version < 500000
1662	        error = suser (p);
1663#else
1664	        error = suser (td);
1665#endif
1666	        if (error)
1667	                return error;
1668	        if (c->type != T_SERIAL)
1669	                return EINVAL;
1670		s = splimp ();
1671		cp_set_invrxc (c, *(int*)data);
1672		splx (s);
1673		return 0;
1674
1675	case SERIAL_GETLEVEL:
1676	        CP_DEBUG2 (d, ("ioctl: getlevel\n"));
1677	        if (c->type != T_G703)
1678	                return EINVAL;
1679		s = splimp ();
1680	        *(int*)data = cp_get_lq (c);
1681		splx (s);
1682		return 0;
1683
1684#if 0
1685	case SERIAL_RESET:
1686	        CP_DEBUG2 (d, ("ioctl: reset\n"));
1687	        /* Only for superuser! */
1688#if __FreeBSD_version < 500000
1689	        error = suser (p);
1690#else
1691	        error = suser (td);
1692#endif
1693	        if (error)
1694	                return error;
1695		s = splimp ();
1696		cp_reset (c->board, 0, 0);
1697		splx (s);
1698		return 0;
1699
1700	case SERIAL_HARDRESET:
1701	        CP_DEBUG2 (d, ("ioctl: hardreset\n"));
1702	        /* Only for superuser! */
1703#if __FreeBSD_version < 500000
1704	        error = suser (p);
1705#else
1706	        error = suser (td);
1707#endif
1708	        if (error)
1709	                return error;
1710		s = splimp ();
1711		/* hard_reset (c->board); */
1712		splx (s);
1713		return 0;
1714#endif
1715
1716	case SERIAL_GETCABLE:
1717	        CP_DEBUG2 (d, ("ioctl: getcable\n"));
1718	        if (c->type != T_SERIAL)
1719	                return EINVAL;
1720		s = splimp ();
1721		*(int*)data = cp_get_cable (c);
1722		splx (s);
1723		return 0;
1724
1725	case SERIAL_GETDIR:
1726	        CP_DEBUG2 (d, ("ioctl: getdir\n"));
1727	        if (c->type != T_E1 && c->type != T_DATA)
1728	                return EINVAL;
1729		*(int*)data = c->dir;
1730		return 0;
1731
1732	case SERIAL_SETDIR:
1733	        CP_DEBUG2 (d, ("ioctl: setdir\n"));
1734	        /* Only for superuser! */
1735#if __FreeBSD_version < 500000
1736	        error = suser (p);
1737#else
1738	        error = suser (td);
1739#endif
1740	        if (error)
1741	                return error;
1742		s = splimp ();
1743		cp_set_dir (c, *(int*)data);
1744		splx (s);
1745		return 0;
1746
1747	case SERIAL_GETRLOOP:
1748	        CP_DEBUG2 (d, ("ioctl: getrloop\n"));
1749	        if (c->type != T_G703 &&
1750		    c->type != T_E3 &&
1751		    c->type != T_T3 &&
1752		    c->type != T_STS1)
1753	                return EINVAL;
1754	        *(int*)data = cp_get_rloop (c);
1755	        return 0;
1756
1757	case SERIAL_SETRLOOP:
1758	        CP_DEBUG2 (d, ("ioctl: setloop\n"));
1759	        if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1760	                return EINVAL;
1761	        /* Only for superuser! */
1762#if __FreeBSD_version < 500000
1763	        error = suser (p);
1764#else
1765	        error = suser (td);
1766#endif
1767	        if (error)
1768	                return error;
1769	        s = splimp ();
1770		cp_set_rloop (c, *(int*)data);
1771	        splx (s);
1772	        return 0;
1773
1774	case SERIAL_GETCABLEN:
1775	        CP_DEBUG2 (d, ("ioctl: getcablen\n"));
1776	        if (c->type != T_T3 && c->type != T_STS1)
1777	                return EINVAL;
1778	        *(int*)data = c->cablen;
1779	        return 0;
1780
1781	case SERIAL_SETCABLEN:
1782	        CP_DEBUG2 (d, ("ioctl: setloop\n"));
1783	        if (c->type != T_T3 && c->type != T_STS1)
1784	                return EINVAL;
1785	        /* Only for superuser! */
1786#if __FreeBSD_version < 500000
1787	        error = suser (p);
1788#else
1789	        error = suser (td);
1790#endif
1791	        if (error)
1792	                return error;
1793	        s = splimp ();
1794		cp_set_cablen (c, *(int*)data);
1795	        splx (s);
1796	        return 0;
1797
1798	case TIOCSDTR:          /* Set DTR */
1799		s = splimp ();
1800		cp_set_dtr (c, 1);
1801		splx (s);
1802		return 0;
1803
1804	case TIOCCDTR:          /* Clear DTR */
1805		s = splimp ();
1806		cp_set_dtr (c, 0);
1807		splx (s);
1808		return 0;
1809
1810	case TIOCMSET:          /* Set DTR/RTS */
1811		s = splimp ();
1812		cp_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1813		cp_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1814		splx (s);
1815		return 0;
1816
1817	case TIOCMBIS:          /* Add DTR/RTS */
1818		s = splimp ();
1819		if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 1);
1820		if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 1);
1821		splx (s);
1822		return 0;
1823
1824	case TIOCMBIC:          /* Clear DTR/RTS */
1825		s = splimp ();
1826		if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 0);
1827		if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 0);
1828		splx (s);
1829		return 0;
1830
1831	case TIOCMGET:          /* Get modem status */
1832		*(int*)data = cp_modem_status (c);
1833		return 0;
1834	}
1835	return ENOTTY;
1836}
1837
1838#if __FreeBSD_version < 500000
1839static struct cdevsw cp_cdevsw = {
1840	cp_open,	cp_close,	noread,		nowrite,
1841	cp_ioctl,	nopoll,		nommap,		nostrategy,
1842	"cp",		CDEV_MAJOR,	nodump,		nopsize,
1843	D_NAGGED,	-1
1844	};
1845#elif __FreeBSD_version == 500000
1846static struct cdevsw cp_cdevsw = {
1847	cp_open,	cp_close,	noread,		nowrite,
1848	cp_ioctl,	nopoll,		nommap,		nostrategy,
1849	"cp",		CDEV_MAJOR,	nodump,		nopsize,
1850	D_NAGGED,
1851	};
1852#elif __FreeBSD_version <= 501000
1853static struct cdevsw cp_cdevsw = {
1854	.d_open     = cp_open,
1855	.d_close    = cp_close,
1856	.d_read     = noread,
1857	.d_write    = nowrite,
1858	.d_ioctl    = cp_ioctl,
1859	.d_poll     = nopoll,
1860	.d_mmap	    = nommap,
1861	.d_strategy = nostrategy,
1862	.d_name     = "cp",
1863	.d_maj      = CDEV_MAJOR,
1864	.d_dump     = nodump,
1865	.d_flags    = D_NAGGED,
1866};
1867#elif __FreeBSD_version < 502103
1868static struct cdevsw cp_cdevsw = {
1869	.d_open     = cp_open,
1870	.d_close    = cp_close,
1871	.d_ioctl    = cp_ioctl,
1872	.d_name     = "cp",
1873	.d_maj      = CDEV_MAJOR,
1874	.d_flags    = D_NAGGED,
1875};
1876#else /* __FreeBSD_version >= 502103 */
1877static struct cdevsw cp_cdevsw = {
1878	.d_version  = D_VERSION,
1879	.d_open     = cp_open,
1880	.d_close    = cp_close,
1881	.d_ioctl    = cp_ioctl,
1882	.d_name     = "cp",
1883	.d_maj      = CDEV_MAJOR,
1884	.d_flags    = D_NEEDGIANT,
1885};
1886#endif
1887
1888#ifdef NETGRAPH
1889#if __FreeBSD_version >= 500000
1890static int ng_cp_constructor (node_p node)
1891{
1892	drv_t *d = NG_NODE_PRIVATE (node);
1893#else
1894static int ng_cp_constructor (node_p *node)
1895{
1896	drv_t *d = (*node)->private;
1897#endif
1898	CP_DEBUG (d, ("Constructor\n"));
1899	return EINVAL;
1900}
1901
1902static int ng_cp_newhook (node_p node, hook_p hook, const char *name)
1903{
1904	int s;
1905#if __FreeBSD_version >= 500000
1906	drv_t *d = NG_NODE_PRIVATE (node);
1907#else
1908	drv_t *d = node->private;
1909#endif
1910
1911	CP_DEBUG (d, ("Newhook\n"));
1912	/* Attach debug hook */
1913	if (strcmp (name, NG_CP_HOOK_DEBUG) == 0) {
1914#if __FreeBSD_version >= 500000
1915		NG_HOOK_SET_PRIVATE (hook, NULL);
1916#else
1917		hook->private = 0;
1918#endif
1919		d->debug_hook = hook;
1920		return 0;
1921	}
1922
1923	/* Check for raw hook */
1924	if (strcmp (name, NG_CP_HOOK_RAW) != 0)
1925		return EINVAL;
1926
1927#if __FreeBSD_version >= 500000
1928	NG_HOOK_SET_PRIVATE (hook, d);
1929#else
1930	hook->private = d;
1931#endif
1932	d->hook = hook;
1933	s = splimp ();
1934	cp_up (d);
1935	splx (s);
1936	return 0;
1937}
1938
1939static char *format_timeslots (u_long s)
1940{
1941	static char buf [100];
1942	char *p = buf;
1943	int i;
1944
1945	for (i=1; i<32; ++i)
1946		if ((s >> i) & 1) {
1947			int prev = (i > 1)  & (s >> (i-1));
1948			int next = (i < 31) & (s >> (i+1));
1949
1950			if (prev) {
1951				if (next)
1952					continue;
1953				*p++ = '-';
1954			} else if (p > buf)
1955				*p++ = ',';
1956
1957			if (i >= 10)
1958				*p++ = '0' + i / 10;
1959			*p++ = '0' + i % 10;
1960		}
1961	*p = 0;
1962	return buf;
1963}
1964
1965static int print_modems (char *s, cp_chan_t *c, int need_header)
1966{
1967	int status = cp_modem_status (c);
1968	int length = 0;
1969
1970	if (need_header)
1971		length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1972	length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1973		status & TIOCM_LE  ? "On" : "-",
1974		status & TIOCM_DTR ? "On" : "-",
1975		status & TIOCM_DSR ? "On" : "-",
1976		status & TIOCM_RTS ? "On" : "-",
1977		status & TIOCM_CTS ? "On" : "-",
1978		status & TIOCM_CD  ? "On" : "-");
1979	return length;
1980}
1981
1982static int print_stats (char *s, cp_chan_t *c, int need_header)
1983{
1984	int length = 0;
1985
1986	if (need_header)
1987		length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1988	length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n",
1989		c->rintr, c->tintr, 0l, (unsigned long) c->ibytes,
1990		c->ipkts, c->overrun + c->frame + c->crc,
1991		(unsigned long) c->obytes, c->opkts, c->underrun);
1992	return length;
1993}
1994
1995static char *format_e1_status (u_char status)
1996{
1997	static char buf [80];
1998
1999	if (status & E1_NOALARM)
2000		return "Ok";
2001	buf[0] = 0;
2002	if (status & E1_LOS)     strcat (buf, ",LOS");
2003	if (status & E1_AIS)     strcat (buf, ",AIS");
2004	if (status & E1_LOF)     strcat (buf, ",LOF");
2005	if (status & E1_LOMF)    strcat (buf, ",LOMF");
2006	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
2007	if (status & E1_AIS16)   strcat (buf, ",AIS16");
2008	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
2009	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
2010	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
2011	if (buf[0] == ',')
2012		return buf+1;
2013	return "Unknown";
2014}
2015
2016static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
2017{
2018	int n, length = 0;
2019
2020	if (numerator < 1 || divider < 1) {
2021		length += sprintf (s+length, leftalign ? "/-   " : "    -");
2022		return length;
2023	}
2024	n = (int) (0.5 + 1000.0 * numerator / divider);
2025	if (n < 1000) {
2026		length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
2027		return length;
2028	}
2029	*(s + length) = leftalign ? '/' : ' ';
2030	length ++;
2031
2032	if      (n >= 1000000) n = (n+500) / 1000 * 1000;
2033	else if (n >= 100000)  n = (n+50)  / 100 * 100;
2034	else if (n >= 10000)   n = (n+5)   / 10 * 10;
2035
2036	switch (n) {
2037	case 1000:    length += printf (s+length, ".999"); return length;
2038	case 10000:   n = 9990;   break;
2039	case 100000:  n = 99900;  break;
2040	case 1000000: n = 999000; break;
2041	}
2042	if (n < 10000)        length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
2043	else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
2044	else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
2045	else                  length += sprintf (s+length, "%d", n/1000);
2046
2047	return length;
2048}
2049
2050static int print_e1_stats (char *s, cp_chan_t *c)
2051{
2052	struct e1_counters total;
2053	u_long totsec;
2054	int length = 0;
2055
2056	totsec		= c->totsec + c->cursec;
2057	total.bpv	= c->total.bpv   + c->currnt.bpv;
2058	total.fse	= c->total.fse   + c->currnt.fse;
2059	total.crce	= c->total.crce  + c->currnt.crce;
2060	total.rcrce	= c->total.rcrce + c->currnt.rcrce;
2061	total.uas	= c->total.uas   + c->currnt.uas;
2062	total.les	= c->total.les   + c->currnt.les;
2063	total.es	= c->total.es    + c->currnt.es;
2064	total.bes	= c->total.bes   + c->currnt.bes;
2065	total.ses	= c->total.ses   + c->currnt.ses;
2066	total.oofs	= c->total.oofs  + c->currnt.oofs;
2067	total.css	= c->total.css   + c->currnt.css;
2068	total.dm	= c->total.dm    + c->currnt.dm;
2069
2070	length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
2071
2072	/* Unavailable seconds, degraded minutes */
2073	length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
2074	length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
2075
2076	/* Bipolar violations, frame sync errors */
2077	length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
2078	length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
2079
2080	/* CRC errors, remote CRC errors (E-bit) */
2081	length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
2082	length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
2083
2084	/* Errored seconds, line errored seconds */
2085	length += print_frac (s + length, 0, c->currnt.es, c->cursec);
2086	length += print_frac (s + length, 1, c->currnt.les, c->cursec);
2087
2088	/* Severely errored seconds, burst errored seconds */
2089	length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
2090	length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
2091
2092	/* Out of frame seconds, controlled slip seconds */
2093	length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
2094	length += print_frac (s + length, 1, c->currnt.css, c->cursec);
2095
2096	length += sprintf (s + length, " %s\n", format_e1_status (c->status));
2097
2098	/* Print total statistics. */
2099	length += print_frac (s + length, 0, total.uas, totsec);
2100	length += print_frac (s + length, 1, 60 * total.dm, totsec);
2101
2102	length += print_frac (s + length, 0, total.bpv, totsec);
2103	length += print_frac (s + length, 1, total.fse, totsec);
2104
2105	length += print_frac (s + length, 0, total.crce, totsec);
2106	length += print_frac (s + length, 1, total.rcrce, totsec);
2107
2108	length += print_frac (s + length, 0, total.es, totsec);
2109	length += print_frac (s + length, 1, total.les, totsec);
2110
2111	length += print_frac (s + length, 0, total.ses, totsec);
2112	length += print_frac (s + length, 1, total.bes, totsec);
2113
2114	length += print_frac (s + length, 0, total.oofs, totsec);
2115	length += print_frac (s + length, 1, total.css, totsec);
2116
2117	length += sprintf (s + length, " -- Total\n");
2118	return length;
2119}
2120
2121static int print_chan (char *s, cp_chan_t *c)
2122{
2123	drv_t *d = c->sys;
2124	int length = 0;
2125
2126	length += sprintf (s + length, "cp%d", c->board->num * NCHAN + c->num);
2127	if (d->chan->debug)
2128		length += sprintf (s + length, " debug=%d", d->chan->debug);
2129
2130	if (c->board->mux) {
2131		length += sprintf (s + length, " cfg=C");
2132	} else {
2133		length += sprintf (s + length, " cfg=A");
2134	}
2135
2136	if (c->baud)
2137		length += sprintf (s + length, " %ld", c->baud);
2138	else
2139		length += sprintf (s + length, " extclock");
2140
2141	if (c->type == T_E1 || c->type == T_G703)
2142		switch (c->gsyn) {
2143		case GSYN_INT   : length += sprintf (s + length, " syn=int");     break;
2144		case GSYN_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2145		case GSYN_RCV0  : length += sprintf (s + length, " syn=rcv0");    break;
2146		case GSYN_RCV1  : length += sprintf (s + length, " syn=rcv1");    break;
2147		case GSYN_RCV2  : length += sprintf (s + length, " syn=rcv2");    break;
2148		case GSYN_RCV3  : length += sprintf (s + length, " syn=rcv3");    break;
2149		}
2150	if (c->type == T_SERIAL) {
2151		length += sprintf (s + length, " dpll=%s",   c->dpll   ? "on" : "off");
2152		length += sprintf (s + length, " nrzi=%s",   c->nrzi   ? "on" : "off");
2153		length += sprintf (s + length, " invclk=%s", c->invtxc ? "on" : "off");
2154	}
2155	if (c->type == T_E1)
2156		length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off");
2157
2158	length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off");
2159
2160	if (c->type == T_E1)
2161		length += sprintf (s + length, " ts=%s", format_timeslots (c->ts));
2162	if (c->type == T_G703) {
2163		int lq, x;
2164
2165		x = splimp ();
2166		lq = cp_get_lq (c);
2167		splx (x);
2168		length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2169	}
2170	length += sprintf (s + length, "\n");
2171	return length;
2172}
2173
2174#if __FreeBSD_version >= 500000
2175static int ng_cp_rcvmsg (node_p node, item_p item, hook_p lasthook)
2176{
2177	drv_t *d = NG_NODE_PRIVATE (node);
2178	struct ng_mesg *msg;
2179#else
2180static int ng_cp_rcvmsg (node_p node, struct ng_mesg *msg,
2181	const char *retaddr, struct ng_mesg **rptr)
2182{
2183	drv_t *d = node->private;
2184#endif
2185	struct ng_mesg *resp = NULL;
2186	int error = 0;
2187
2188	CP_DEBUG (d, ("Rcvmsg\n"));
2189#if __FreeBSD_version >= 500000
2190	NGI_GET_MSG (item, msg);
2191#endif
2192	switch (msg->header.typecookie) {
2193	default:
2194		error = EINVAL;
2195		break;
2196
2197	case NGM_CP_COOKIE:
2198		printf ("Not implemented yet\n");
2199		error = EINVAL;
2200		break;
2201
2202	case NGM_GENERIC_COOKIE:
2203		switch (msg->header.cmd) {
2204		default:
2205			error = EINVAL;
2206			break;
2207
2208		case NGM_TEXT_STATUS: {
2209			char *s;
2210			int l = 0;
2211			int dl = sizeof (struct ng_mesg) + 730;
2212
2213#if __FreeBSD_version >= 500000
2214			NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2215			if (! resp) {
2216				error = ENOMEM;
2217				break;
2218			}
2219#else
2220			MALLOC (resp, struct ng_mesg *, dl,
2221				M_NETGRAPH, M_NOWAIT);
2222			if (! resp) {
2223				error = ENOMEM;
2224				break;
2225			}
2226			bzero (resp, dl);
2227#endif
2228			s = (resp)->data;
2229			if (d) {
2230			l += print_chan (s + l, d->chan);
2231			l += print_stats (s + l, d->chan, 1);
2232			l += print_modems (s + l, d->chan, 1);
2233			l += print_e1_stats (s + l, d->chan);
2234			} else
2235				l += sprintf (s + l, "Error: node not connect to channel");
2236#if __FreeBSD_version < 500000
2237			(resp)->header.version = NG_VERSION;
2238			(resp)->header.arglen = strlen (s) + 1;
2239			(resp)->header.token = msg->header.token;
2240			(resp)->header.typecookie = NGM_CP_COOKIE;
2241			(resp)->header.cmd = msg->header.cmd;
2242#endif
2243			strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2244			}
2245			break;
2246		}
2247		break;
2248	}
2249#if __FreeBSD_version >= 500000
2250	NG_RESPOND_MSG (error, node, item, resp);
2251	NG_FREE_MSG (msg);
2252#else
2253	*rptr = resp;
2254	FREE (msg, M_NETGRAPH);
2255#endif
2256	return error;
2257}
2258
2259#if __FreeBSD_version >= 500000
2260static int ng_cp_rcvdata (hook_p hook, item_p item)
2261{
2262	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2263	struct mbuf *m;
2264	struct ng_tag_prio *ptag;
2265#else
2266static int ng_cp_rcvdata (hook_p hook, struct mbuf *m, meta_p meta)
2267{
2268	drv_t *d = hook->node->private;
2269#endif
2270	struct ifqueue *q;
2271	int s;
2272
2273	CP_DEBUG2 (d, ("Rcvdata\n"));
2274#if __FreeBSD_version >= 500000
2275	NGI_GET_M (item, m);
2276	NG_FREE_ITEM (item);
2277	if (! NG_HOOK_PRIVATE (hook) || ! d) {
2278		NG_FREE_M (m);
2279#else
2280	if (! hook->private || ! d) {
2281		NG_FREE_DATA (m,meta);
2282#endif
2283		return ENETDOWN;
2284	}
2285
2286	/* Check for high priority data */
2287	if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2288	    NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2289		q = &d->hi_queue;
2290	else
2291		q = &d->queue;
2292
2293	s = splimp ();
2294#if __FreeBSD_version >= 500000
2295	IF_LOCK (q);
2296	if (_IF_QFULL (q)) {
2297		_IF_DROP (q);
2298		IF_UNLOCK (q);
2299		splx (s);
2300		NG_FREE_M (m);
2301		return ENOBUFS;
2302	}
2303	_IF_ENQUEUE (q, m);
2304	IF_UNLOCK (q);
2305#else
2306	if (IF_QFULL (q)) {
2307		IF_DROP (q);
2308		splx (s);
2309		NG_FREE_DATA (m, meta);
2310		return ENOBUFS;
2311	}
2312	IF_ENQUEUE (q, m);
2313#endif
2314	cp_start (d);
2315	splx (s);
2316	return 0;
2317}
2318
2319static int ng_cp_rmnode (node_p node)
2320{
2321#if __FreeBSD_version >= 500000
2322	drv_t *d = NG_NODE_PRIVATE (node);
2323
2324	CP_DEBUG (d, ("Rmnode\n"));
2325	if (d && d->running) {
2326		int s = splimp ();
2327		cp_down (d);
2328		splx (s);
2329	}
2330#ifdef	KLD_MODULE
2331	if (node->nd_flags & NG_REALLY_DIE) {
2332		NG_NODE_SET_PRIVATE (node, NULL);
2333		NG_NODE_UNREF (node);
2334	}
2335	node->nd_flags &= ~NG_INVALID;
2336#endif
2337#else /* __FreeBSD_version < 500000 */
2338	drv_t *d = node->private;
2339
2340	if (d && d->running) {
2341		int s = splimp ();
2342		cp_down (d);
2343	splx (s);
2344	}
2345
2346	node->flags |= NG_INVALID;
2347	ng_cutlinks (node);
2348#ifdef	KLD_MODULE
2349	ng_unname (node);
2350	ng_unref (node);
2351#endif
2352#endif
2353	return 0;
2354}
2355
2356static void ng_cp_watchdog (void *arg)
2357{
2358	drv_t *d = arg;
2359
2360	if (d) {
2361		if (d->timeout == 1)
2362			cp_watchdog (d);
2363		if (d->timeout)
2364			d->timeout--;
2365		d->timeout_handle = timeout (ng_cp_watchdog, d, hz);
2366	}
2367}
2368
2369static int ng_cp_connect (hook_p hook)
2370{
2371#if __FreeBSD_version >= 500000
2372	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2373#else
2374	drv_t *d = hook->node->private;
2375#endif
2376
2377	if (d) {
2378		CP_DEBUG (d, ("Connect\n"));
2379		d->timeout_handle = timeout (ng_cp_watchdog, d, hz);
2380	}
2381
2382	return 0;
2383}
2384
2385static int ng_cp_disconnect (hook_p hook)
2386{
2387#if __FreeBSD_version >= 500000
2388	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2389#else
2390	drv_t *d = hook->node->private;
2391#endif
2392
2393	if (d) {
2394		CP_DEBUG (d, ("Disconnect\n"));
2395#if __FreeBSD_version >= 500000
2396		if (NG_HOOK_PRIVATE (hook))
2397#else
2398		if (hook->private)
2399#endif
2400		{
2401			int s = splimp ();
2402			cp_down (d);
2403			splx (s);
2404		}
2405		untimeout (ng_cp_watchdog, d, d->timeout_handle);
2406	}
2407	return 0;
2408}
2409#endif
2410
2411static int cp_modevent (module_t mod, int type, void *unused)
2412{
2413        struct cdev *dev;
2414	static int load_count = 0;
2415	struct cdevsw *cdsw;
2416
2417#if __FreeBSD_version >= 502103
2418	dev = findcdev (makedev(CDEV_MAJOR, 0));
2419#else
2420	dev = makedev (CDEV_MAJOR, 0);
2421#endif
2422	switch (type) {
2423	case MOD_LOAD:
2424		if (dev != NULL &&
2425		    (cdsw = devsw (dev)) &&
2426		    cdsw->d_maj == CDEV_MAJOR) {
2427			printf ("Tau-PCI driver is already in system\n");
2428			return (ENXIO);
2429		}
2430#if __FreeBSD_version >= 500000 && defined NETGRAPH
2431		if (ng_newtype (&typestruct))
2432			printf ("Failed to register ng_cp\n");
2433#endif
2434		++load_count;
2435#if __FreeBSD_version <= 500000
2436		cdevsw_add (&cp_cdevsw);
2437#endif
2438		timeout_handle = timeout (cp_timeout, 0, hz*5);
2439		break;
2440	case MOD_UNLOAD:
2441		if (load_count == 1) {
2442			printf ("Removing device entry for Tau-PCI\n");
2443#if __FreeBSD_version <= 500000
2444			cdevsw_remove (&cp_cdevsw);
2445#endif
2446#if __FreeBSD_version >= 500000 && defined NETGRAPH
2447			ng_rmtype (&typestruct);
2448#endif
2449		}
2450		untimeout (cp_timeout, 0, timeout_handle);
2451		--load_count;
2452		break;
2453	case MOD_SHUTDOWN:
2454		break;
2455	}
2456	return 0;
2457}
2458
2459#ifdef NETGRAPH
2460static struct ng_type typestruct = {
2461	.version	= NG_ABI_VERSION,
2462	.name		= NG_CP_NODE_TYPE,
2463	.constructor	= ng_cp_constructor,
2464	.rcvmsg		= ng_cp_rcvmsg,
2465	.shutdown	= ng_cp_rmnode,
2466	.newhook	= ng_cp_newhook,
2467	.connect	= ng_cp_connect,
2468	.rcvdata	= ng_cp_rcvdata,
2469	.disconnect	= ng_cp_disconnect,
2470};
2471#endif /*NETGRAPH*/
2472
2473#if __FreeBSD_version >= 500000
2474#ifdef NETGRAPH
2475MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2476#else
2477MODULE_DEPEND (cp, sppp, 1, 1, 1);
2478#endif
2479#ifdef KLD_MODULE
2480DRIVER_MODULE (cpmod, pci, cp_driver, cp_devclass, cp_modevent, NULL);
2481#else
2482DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL);
2483#endif
2484#elif __FreeBSD_version >= 400000
2485#ifdef NETGRAPH
2486DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, ng_mod_event, &typestruct);
2487#else
2488DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL);
2489#endif
2490#endif /* __FreeBSD_version >= 400000 */
2491#endif /* NPCI */
2492