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