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