if_cp.c revision 314667
1207340Sjkim/*-
2207340Sjkim * Cronyx-Tau-PCI adapter driver for FreeBSD.
3207340Sjkim * Supports PPP/HDLC, Cisco/HDLC and FrameRelay protocol in synchronous mode,
4207340Sjkim * and asynchronous channels with full modem control.
5207340Sjkim * Keepalive protocol implemented in both Cisco and PPP modes.
6207340Sjkim *
7217365Sjkim * Copyright (C) 1999-2004 Cronyx Engineering.
8306536Sjkim * Author: Kurakin Roman, <rik@cronyx.ru>
9207340Sjkim *
10207340Sjkim * Copyright (C) 1999-2002 Cronyx Engineering.
11217365Sjkim * Author: Serge Vakulenko, <vak@cronyx.ru>
12217365Sjkim *
13217365Sjkim * This software is distributed with NO WARRANTIES, not even the implied
14217365Sjkim * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15217365Sjkim *
16217365Sjkim * Authors grant any other persons or organisations a permission to use,
17217365Sjkim * modify and redistribute this software in source and binary forms,
18217365Sjkim * as long as this message is kept with the software, all derivative
19217365Sjkim * works or modified versions.
20217365Sjkim *
21217365Sjkim * Cronyx Id: if_cp.c,v 1.1.2.41 2004/06/23 17:09:13 rik Exp $
22217365Sjkim */
23217365Sjkim
24217365Sjkim#include <sys/cdefs.h>
25207340Sjkim__FBSDID("$FreeBSD: stable/10/sys/dev/cp/if_cp.c 314667 2017-03-04 13:03:31Z avg $");
26217365Sjkim
27217365Sjkim#include <sys/param.h>
28217365Sjkim#include <sys/ucred.h>
29207340Sjkim#include <sys/proc.h>
30217365Sjkim#include <sys/systm.h>
31217365Sjkim#include <sys/mbuf.h>
32217365Sjkim#include <sys/kernel.h>
33217365Sjkim#include <sys/module.h>
34217365Sjkim#include <sys/conf.h>
35217365Sjkim#include <sys/malloc.h>
36217365Sjkim#include <sys/priv.h>
37217365Sjkim#include <sys/socket.h>
38217365Sjkim#include <sys/sockio.h>
39217365Sjkim#include <sys/sysctl.h>
40217365Sjkim#include <sys/tty.h>
41217365Sjkim#include <sys/bus.h>
42217365Sjkim#include <vm/vm.h>
43207340Sjkim#include <vm/pmap.h>
44207344Sjkim#include <net/if.h>
45207340Sjkim#include <dev/pci/pcivar.h>
46207340Sjkim#include <dev/pci/pcireg.h>
47207340Sjkim#include <machine/bus.h>
48207340Sjkim#include <sys/rman.h>
49207340Sjkim#include "opt_ng_cronyx.h"
50207340Sjkim#ifdef NETGRAPH_CRONYX
51207340Sjkim#   include "opt_netgraph.h"
52207340Sjkim#   ifndef NETGRAPH
53207340Sjkim#	error #option	NETGRAPH missed from configuration
54207340Sjkim#   endif
55207340Sjkim#   include <netgraph/ng_message.h>
56207340Sjkim#   include <netgraph/netgraph.h>
57207340Sjkim#   include <dev/cp/ng_cp.h>
58207340Sjkim#else
59207340Sjkim#   include <net/if_sppp.h>
60207340Sjkim#   include <net/if_types.h>
61207340Sjkim#include <dev/pci/pcivar.h>
62281075Sdim#   define PP_CISCO IFF_LINK2
63207340Sjkim#   include <net/bpf.h>
64207340Sjkim#endif
65207340Sjkim#include <dev/cx/machdep.h>
66207340Sjkim#include <dev/cp/cpddk.h>
67207340Sjkim#include <machine/cserial.h>
68207340Sjkim#include <machine/resource.h>
69207340Sjkim#include <machine/pmap.h>
70207340Sjkim
71207340Sjkim/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
72281075Sdim#ifndef PP_FR
73207340Sjkim#define PP_FR 0
74207340Sjkim#endif
75207340Sjkim
76207340Sjkim#define CP_DEBUG(d,s)	({if (d->chan->debug) {\
77207340Sjkim				printf ("%s: ", d->name); printf s;}})
78207340Sjkim#define CP_DEBUG2(d,s)	({if (d->chan->debug>1) {\
79207340Sjkim				printf ("%s: ", d->name); printf s;}})
80207340Sjkim#define CP_LOCK_NAME	"cpX"
81207340Sjkim
82207340Sjkim#define CP_LOCK(_bd)		mtx_lock (&(_bd)->cp_mtx)
83207340Sjkim#define CP_UNLOCK(_bd)		mtx_unlock (&(_bd)->cp_mtx)
84281075Sdim#define CP_LOCK_ASSERT(_bd)	mtx_assert (&(_bd)->cp_mtx, MA_OWNED)
85207340Sjkim
86207340Sjkimstatic	int cp_probe		__P((device_t));
87207340Sjkimstatic	int cp_attach		__P((device_t));
88207340Sjkimstatic	int cp_detach		__P((device_t));
89281075Sdim
90207340Sjkimstatic	device_method_t cp_methods[] = {
91281075Sdim	/* Device interface */
92207340Sjkim	DEVMETHOD(device_probe,		cp_probe),
93207340Sjkim	DEVMETHOD(device_attach,	cp_attach),
94306536Sjkim	DEVMETHOD(device_detach,	cp_detach),
95207340Sjkim
96207340Sjkim	DEVMETHOD_END
97306536Sjkim};
98306536Sjkim
99207340Sjkimtypedef struct _cp_dma_mem_t {
100207340Sjkim	unsigned long	phys;
101207340Sjkim	void		*virt;
102207340Sjkim	size_t		size;
103207340Sjkim	bus_dma_tag_t	dmat;
104207340Sjkim	bus_dmamap_t	mapp;
105207340Sjkim} cp_dma_mem_t;
106207340Sjkim
107207340Sjkimtypedef struct _drv_t {
108207340Sjkim	char	name [8];
109207340Sjkim	int	running;
110207340Sjkim	cp_chan_t	*chan;
111207340Sjkim	cp_board_t	*board;
112207340Sjkim	cp_dma_mem_t	dmamem;
113207340Sjkim#ifdef NETGRAPH
114207340Sjkim	char	nodename [NG_NODESIZE];
115207340Sjkim	hook_p	hook;
116207340Sjkim	hook_p	debug_hook;
117207340Sjkim	node_p	node;
118207340Sjkim	struct	ifqueue queue;
119207340Sjkim	struct	ifqueue hi_queue;
120207340Sjkim#else
121207340Sjkim	struct	ifqueue queue;
122207340Sjkim	struct	ifnet *ifp;
123207340Sjkim#endif
124207340Sjkim	short	timeout;
125207340Sjkim	struct	callout timeout_handle;
126207340Sjkim	struct	cdev *devt;
127207340Sjkim} drv_t;
128207340Sjkim
129207340Sjkimtypedef	struct _bdrv_t {
130207340Sjkim	cp_board_t	*board;
131207340Sjkim	struct resource *cp_res;
132207340Sjkim	struct resource *cp_irq;
133207340Sjkim	void		*cp_intrhand;
134207340Sjkim	cp_dma_mem_t	dmamem;
135207340Sjkim	drv_t		channel [NCHAN];
136207340Sjkim	struct mtx	cp_mtx;
137207340Sjkim} bdrv_t;
138207340Sjkim
139207340Sjkimstatic	driver_t cp_driver = {
140207340Sjkim	"cp",
141207340Sjkim	cp_methods,
142207340Sjkim	sizeof(bdrv_t),
143207340Sjkim};
144228110Sjkim
145228110Sjkimstatic	devclass_t cp_devclass;
146207340Sjkim
147207340Sjkimstatic void cp_receive (cp_chan_t *c, unsigned char *data, int len);
148207340Sjkimstatic void cp_transmit (cp_chan_t *c, void *attachment, int len);
149207340Sjkimstatic void cp_error (cp_chan_t *c, int data);
150207340Sjkimstatic void cp_up (drv_t *d);
151228110Sjkimstatic void cp_start (drv_t *d);
152207340Sjkimstatic void cp_down (drv_t *d);
153207340Sjkimstatic void cp_watchdog (drv_t *d);
154207340Sjkimstatic void cp_watchdog_timer (void *arg);
155207340Sjkim#ifdef NETGRAPH
156207340Sjkimextern struct ng_type typestruct;
157207340Sjkim#else
158207340Sjkimstatic void cp_ifstart (struct ifnet *ifp);
159228110Sjkimstatic void cp_tlf (struct sppp *sp);
160207340Sjkimstatic void cp_tls (struct sppp *sp);
161207340Sjkimstatic int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
162207340Sjkimstatic void cp_initialize (void *softc);
163207340Sjkim#endif
164207340Sjkim
165207340Sjkimstatic cp_board_t *adapter [NBRD];
166207340Sjkimstatic drv_t *channel [NBRD*NCHAN];
167228110Sjkimstatic struct callout led_timo [NBRD];
168207340Sjkimstatic struct callout timeout_handle;
169207340Sjkim
170207340Sjkimstatic int cp_destroy = 0;
171207340Sjkim
172207340Sjkimstatic int cp_open (struct cdev *dev, int oflags, int devtype, struct thread *td);
173207340Sjkimstatic int cp_close (struct cdev *dev, int fflag, int devtype, struct thread *td);
174207340Sjkimstatic int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
175228110Sjkimstatic struct cdevsw cp_cdevsw = {
176207340Sjkim	.d_version  = D_VERSION,
177207340Sjkim	.d_open     = cp_open,
178207340Sjkim	.d_close    = cp_close,
179207340Sjkim	.d_ioctl    = cp_ioctl,
180207340Sjkim	.d_name     = "cp",
181207340Sjkim};
182228110Sjkim
183207340Sjkim/*
184207340Sjkim * Print the mbuf chain, for debug purposes only.
185207340Sjkim */
186207340Sjkimstatic void printmbuf (struct mbuf *m)
187207340Sjkim{
188207340Sjkim	printf ("mbuf:");
189207340Sjkim	for (; m; m=m->m_next) {
190207340Sjkim		if (m->m_flags & M_PKTHDR)
191207340Sjkim			printf (" HDR %d:", m->m_pkthdr.len);
192207340Sjkim		if (m->m_flags & M_EXT)
193207340Sjkim			printf (" EXT:");
194207340Sjkim		printf (" %d", m->m_len);
195207340Sjkim	}
196207340Sjkim	printf ("\n");
197207340Sjkim}
198207340Sjkim
199207340Sjkim/*
200207340Sjkim * Make an mbuf from data.
201207340Sjkim */
202207340Sjkimstatic struct mbuf *makembuf (void *buf, unsigned len)
203207340Sjkim{
204207340Sjkim	struct mbuf *m;
205207340Sjkim
206207340Sjkim	MGETHDR (m, M_NOWAIT, MT_DATA);
207207340Sjkim	if (! m)
208207340Sjkim		return 0;
209207340Sjkim	MCLGET (m, M_NOWAIT);
210207340Sjkim	if (! (m->m_flags & M_EXT)) {
211207340Sjkim		m_freem (m);
212207340Sjkim		return 0;
213207340Sjkim	}
214207340Sjkim	m->m_pkthdr.len = m->m_len = len;
215207340Sjkim	bcopy (buf, mtod (m, caddr_t), len);
216207340Sjkim	return m;
217207340Sjkim}
218207340Sjkim
219207340Sjkimstatic int cp_probe (device_t dev)
220207340Sjkim{
221207340Sjkim	if ((pci_get_vendor (dev) == cp_vendor_id) &&
222207340Sjkim	    (pci_get_device (dev) == cp_device_id)) {
223207340Sjkim		device_set_desc (dev, "Cronyx-Tau-PCI serial adapter");
224207340Sjkim		return BUS_PROBE_DEFAULT;
225207340Sjkim	}
226207340Sjkim	return ENXIO;
227207340Sjkim}
228207340Sjkim
229207340Sjkimstatic void cp_timeout (void *arg)
230207340Sjkim{
231207340Sjkim	drv_t *d;
232207340Sjkim	int s, i, k;
233207340Sjkim
234207340Sjkim	for (i = 0; i < NBRD; ++i) {
235207340Sjkim		if (adapter[i] == NULL)
236207340Sjkim			continue;
237281075Sdim		for (k = 0; k < NCHAN; ++k) {
238207340Sjkim			s = splimp ();
239207340Sjkim			if (cp_destroy) {
240207340Sjkim				splx (s);
241207340Sjkim				return;
242207340Sjkim			}
243207340Sjkim			d = channel[i * NCHAN + k];
244207340Sjkim			if (!d) {
245207340Sjkim				splx (s);
246207340Sjkim				continue;
247207340Sjkim			}
248207340Sjkim			CP_LOCK ((bdrv_t *)d->board->sys);
249207340Sjkim			switch (d->chan->type) {
250207340Sjkim			case T_G703:
251207340Sjkim				cp_g703_timer (d->chan);
252207340Sjkim				break;
253207340Sjkim			case T_E1:
254207340Sjkim				cp_e1_timer (d->chan);
255207340Sjkim				break;
256207340Sjkim			case T_E3:
257207340Sjkim			case T_T3:
258207340Sjkim			case T_STS1:
259207340Sjkim				cp_e3_timer (d->chan);
260207340Sjkim				break;
261207340Sjkim			default:
262207340Sjkim				break;
263207340Sjkim			}
264207340Sjkim			CP_UNLOCK ((bdrv_t *)d->board->sys);
265207340Sjkim			splx (s);
266212761Sjkim		}
267212761Sjkim	}
268212761Sjkim	s = splimp ();
269212761Sjkim	if (!cp_destroy)
270207340Sjkim		callout_reset (&timeout_handle, hz, cp_timeout, 0);
271281075Sdim	splx (s);
272207340Sjkim}
273207340Sjkim
274281075Sdimstatic void cp_led_off (void *arg)
275207340Sjkim{
276207340Sjkim	cp_board_t *b = arg;
277207340Sjkim	bdrv_t *bd = (bdrv_t *) b->sys;
278207340Sjkim	int s;
279207340Sjkim	s = splimp ();
280207340Sjkim	if (cp_destroy) {
281207340Sjkim		splx (s);
282207340Sjkim		return;
283281075Sdim	}
284207340Sjkim	CP_LOCK (bd);
285207340Sjkim	cp_led (b, 0);
286207340Sjkim	CP_UNLOCK (bd);
287207340Sjkim	splx (s);
288207340Sjkim}
289207340Sjkim
290207340Sjkimstatic void cp_intr (void *arg)
291207340Sjkim{
292207340Sjkim	bdrv_t *bd = arg;
293281075Sdim	cp_board_t *b = bd->board;
294207340Sjkim#ifndef NETGRAPH
295207340Sjkim	int i;
296207340Sjkim#endif
297207340Sjkim	int s = splimp ();
298207340Sjkim	if (cp_destroy) {
299207340Sjkim		splx (s);
300207340Sjkim		return;
301207340Sjkim	}
302207340Sjkim	CP_LOCK (bd);
303207340Sjkim	/* Check if we are ready */
304207340Sjkim	if (b->sys == NULL) {
305281075Sdim		/* Not we are not, just cleanup. */
306207340Sjkim		cp_interrupt_poll (b, 1);
307207340Sjkim		CP_UNLOCK (bd);
308207340Sjkim		return;
309207340Sjkim	}
310281075Sdim	/* Turn LED on. */
311207340Sjkim	cp_led (b, 1);
312281075Sdim
313207340Sjkim	cp_interrupt (b);
314207340Sjkim
315306536Sjkim	/* Turn LED off 50 msec later. */
316207340Sjkim	callout_reset (&led_timo[b->num], hz/20, cp_led_off, b);
317207340Sjkim	CP_UNLOCK (bd);
318306536Sjkim	splx (s);
319306536Sjkim
320207340Sjkim#ifndef NETGRAPH
321207340Sjkim	/* Pass packets in a lock-free state */
322207340Sjkim	for (i = 0; i < NCHAN && b->chan[i].type; i++) {
323207340Sjkim		drv_t *d = b->chan[i].sys;
324207340Sjkim		struct mbuf *m;
325207340Sjkim		if (!d || !d->running)
326207340Sjkim			continue;
327207340Sjkim		while (_IF_QLEN(&d->queue)) {
328207340Sjkim			IF_DEQUEUE (&d->queue,m);
329207340Sjkim			if (!m)
330207340Sjkim				continue;
331207340Sjkim			sppp_input (d->ifp, m);
332207340Sjkim		}
333207340Sjkim	}
334207340Sjkim#endif
335207340Sjkim}
336207340Sjkim
337207340Sjkimstatic void
338207340Sjkimcp_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
339207340Sjkim{
340207340Sjkim	unsigned long *addr;
341207340Sjkim
342207340Sjkim	if (error)
343207340Sjkim		return;
344207340Sjkim
345207340Sjkim	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
346207340Sjkim	addr = arg;
347207340Sjkim	*addr = segs->ds_addr;
348207340Sjkim}
349207340Sjkim
350207340Sjkimstatic int
351207340Sjkimcp_bus_dma_mem_alloc (int bnum, int cnum, cp_dma_mem_t *dmem)
352207340Sjkim{
353207340Sjkim	int error;
354207340Sjkim
355207340Sjkim	error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
356207340Sjkim		BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
357207340Sjkim		dmem->size, 0, NULL, NULL, &dmem->dmat);
358207340Sjkim	if (error) {
359207340Sjkim		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
360207340Sjkim		else		printf ("cp%d: ", bnum);
361207340Sjkim		printf ("couldn't allocate tag for dma memory\n");
362207340Sjkim 		return 0;
363207340Sjkim	}
364207340Sjkim	error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
365207340Sjkim		BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
366228110Sjkim	if (error) {
367207340Sjkim		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
368207340Sjkim		else		printf ("cp%d: ", bnum);
369207340Sjkim		printf ("couldn't allocate mem for dma memory\n");
370207340Sjkim		bus_dma_tag_destroy (dmem->dmat);
371207340Sjkim 		return 0;
372207340Sjkim	}
373207340Sjkim	error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
374207340Sjkim		dmem->size, cp_bus_dmamap_addr, &dmem->phys, 0);
375228110Sjkim	if (error) {
376207340Sjkim		if (cnum >= 0)	printf ("cp%d-%d: ", bnum, cnum);
377207340Sjkim		else		printf ("cp%d: ", bnum);
378207340Sjkim		printf ("couldn't load mem map for dma memory\n");
379207340Sjkim		bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
380207340Sjkim		bus_dma_tag_destroy (dmem->dmat);
381207340Sjkim 		return 0;
382207340Sjkim	}
383207340Sjkim	return 1;
384228110Sjkim}
385207340Sjkim
386207340Sjkimstatic void
387207340Sjkimcp_bus_dma_mem_free (cp_dma_mem_t *dmem)
388207340Sjkim{
389207340Sjkim	bus_dmamap_unload (dmem->dmat, dmem->mapp);
390207340Sjkim	bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
391207340Sjkim	bus_dma_tag_destroy (dmem->dmat);
392207340Sjkim}
393228110Sjkim
394207340Sjkim/*
395207340Sjkim * Called if the probe succeeded.
396207340Sjkim */
397207340Sjkimstatic int cp_attach (device_t dev)
398207340Sjkim{
399207340Sjkim	bdrv_t *bd = device_get_softc (dev);
400207340Sjkim	int unit = device_get_unit (dev);
401228110Sjkim	char *cp_ln = CP_LOCK_NAME;
402207340Sjkim	unsigned short res;
403207340Sjkim	vm_offset_t vbase;
404207340Sjkim	int rid, error;
405207340Sjkim	cp_board_t *b;
406207340Sjkim	cp_chan_t *c;
407207340Sjkim	drv_t *d;
408207340Sjkim	int s = splimp ();
409207340Sjkim
410207340Sjkim	b = malloc (sizeof(cp_board_t), M_DEVBUF, M_WAITOK);
411207340Sjkim	if (!b) {
412207340Sjkim		printf ("cp%d: couldn't allocate memory\n", unit);
413207340Sjkim		splx (s);
414207340Sjkim		return (ENXIO);
415207340Sjkim	}
416207340Sjkim	bzero (b, sizeof(cp_board_t));
417207340Sjkim
418207340Sjkim	bd->board = b;
419207340Sjkim	rid = PCIR_BAR(0);
420207340Sjkim	bd->cp_res = bus_alloc_resource (dev, SYS_RES_MEMORY, &rid,
421207340Sjkim			0, ~0, 1, RF_ACTIVE);
422207340Sjkim	if (! bd->cp_res) {
423207340Sjkim		printf ("cp%d: cannot map memory\n", unit);
424207340Sjkim		free (b, M_DEVBUF);
425207340Sjkim		splx (s);
426207340Sjkim		return (ENXIO);
427207340Sjkim	}
428207340Sjkim	vbase = (vm_offset_t) rman_get_virtual (bd->cp_res);
429207340Sjkim
430207340Sjkim	cp_ln[2] = '0' + unit;
431207340Sjkim	mtx_init (&bd->cp_mtx, cp_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
432207340Sjkim	res = cp_init (b, unit, (u_char*) vbase);
433207340Sjkim	if (res) {
434207340Sjkim		printf ("cp%d: can't init, error code:%x\n", unit, res);
435207340Sjkim		bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
436207340Sjkim		free (b, M_DEVBUF);
437207340Sjkim		splx (s);
438207340Sjkim 		return (ENXIO);
439207340Sjkim	}
440207340Sjkim
441207340Sjkim	bd->dmamem.size = sizeof(cp_qbuf_t);
442207340Sjkim	if (! cp_bus_dma_mem_alloc (unit, -1, &bd->dmamem)) {
443207340Sjkim		free (b, M_DEVBUF);
444207340Sjkim		splx (s);
445207340Sjkim 		return (ENXIO);
446207340Sjkim	}
447207340Sjkim	CP_LOCK (bd);
448207340Sjkim	cp_reset (b, bd->dmamem.virt, bd->dmamem.phys);
449207340Sjkim	CP_UNLOCK (bd);
450207340Sjkim
451207340Sjkim	rid = 0;
452207340Sjkim	bd->cp_irq = bus_alloc_resource (dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
453207340Sjkim			RF_SHAREABLE | RF_ACTIVE);
454207340Sjkim	if (! bd->cp_irq) {
455207340Sjkim		cp_destroy = 1;
456281075Sdim		printf ("cp%d: cannot map interrupt\n", unit);
457207340Sjkim		bus_release_resource (dev, SYS_RES_MEMORY,
458207340Sjkim				PCIR_BAR(0), bd->cp_res);
459207340Sjkim		mtx_destroy (&bd->cp_mtx);
460207340Sjkim		free (b, M_DEVBUF);
461207340Sjkim		splx (s);
462207340Sjkim		return (ENXIO);
463207340Sjkim	}
464207340Sjkim	callout_init (&led_timo[unit], 1);
465207340Sjkim	error  = bus_setup_intr (dev, bd->cp_irq,
466207340Sjkim				INTR_TYPE_NET|INTR_MPSAFE,
467207340Sjkim				NULL, cp_intr, bd, &bd->cp_intrhand);
468207340Sjkim	if (error) {
469207340Sjkim		cp_destroy = 1;
470207340Sjkim		printf ("cp%d: cannot set up irq\n", unit);
471212761Sjkim		bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
472212761Sjkim		bus_release_resource (dev, SYS_RES_MEMORY,
473212761Sjkim				PCIR_BAR(0), bd->cp_res);
474212761Sjkim		mtx_destroy (&bd->cp_mtx);
475207340Sjkim		free (b, M_DEVBUF);
476281075Sdim		splx (s);
477207340Sjkim		return (ENXIO);
478207340Sjkim	}
479281075Sdim	printf ("cp%d: %s, clock %ld MHz\n", unit, b->name, b->osc / 1000000);
480207340Sjkim
481207340Sjkim	for (c = b->chan; c < b->chan + NCHAN; ++c) {
482207340Sjkim		if (! c->type)
483207340Sjkim			continue;
484207340Sjkim		d = &bd->channel[c->num];
485207340Sjkim		d->dmamem.size = sizeof(cp_buf_t);
486207340Sjkim		if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
487207340Sjkim			continue;
488281075Sdim		channel [b->num*NCHAN + c->num] = d;
489207340Sjkim		sprintf (d->name, "cp%d.%d", b->num, c->num);
490207340Sjkim		d->board = b;
491207340Sjkim		d->chan = c;
492207340Sjkim		c->sys = d;
493207340Sjkim		callout_init (&d->timeout_handle, 1);
494207340Sjkim#ifdef NETGRAPH
495207340Sjkim		if (ng_make_node_common (&typestruct, &d->node) != 0) {
496207340Sjkim			printf ("%s: cannot make common node\n", d->name);
497207340Sjkim			d->node = NULL;
498281075Sdim			continue;
499207340Sjkim		}
500207340Sjkim		NG_NODE_SET_PRIVATE (d->node, d);
501207340Sjkim		sprintf (d->nodename, "%s%d", NG_CP_NODE_TYPE,
502207340Sjkim			 c->board->num*NCHAN + c->num);
503207340Sjkim		if (ng_name_node (d->node, d->nodename)) {
504207340Sjkim			printf ("%s: cannot name node\n", d->nodename);
505207340Sjkim			NG_NODE_UNREF (d->node);
506207340Sjkim			continue;
507207340Sjkim		}
508207340Sjkim		d->queue.ifq_maxlen = ifqmaxlen;
509207340Sjkim		d->hi_queue.ifq_maxlen = ifqmaxlen;
510281075Sdim		mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF);
511207340Sjkim		mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF);
512207340Sjkim#else /*NETGRAPH*/
513207340Sjkim		d->ifp = if_alloc(IFT_PPP);
514207340Sjkim		if (d->ifp == NULL) {
515281075Sdim			printf ("%s: cannot if_alloc() interface\n", d->name);
516207340Sjkim			continue;
517281075Sdim		}
518207340Sjkim		d->ifp->if_softc	= d;
519207340Sjkim		if_initname (d->ifp, "cp", b->num * NCHAN + c->num);
520306536Sjkim		d->ifp->if_mtu		= PP_MTU;
521207340Sjkim		d->ifp->if_flags	= IFF_POINTOPOINT | IFF_MULTICAST;
522207340Sjkim		d->ifp->if_ioctl	= cp_sioctl;
523306536Sjkim		d->ifp->if_start	= cp_ifstart;
524207340Sjkim		d->ifp->if_init		= cp_initialize;
525207340Sjkim		d->queue.ifq_maxlen	= NRBUF;
526207340Sjkim		mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF);
527207340Sjkim		sppp_attach (d->ifp);
528207340Sjkim		if_attach (d->ifp);
529207340Sjkim		IFP2SP(d->ifp)->pp_tlf	= cp_tlf;
530207340Sjkim		IFP2SP(d->ifp)->pp_tls	= cp_tls;
531207340Sjkim		/* If BPF is in the kernel, call the attach for it.
532207340Sjkim		 * The header size of PPP or Cisco/HDLC is 4 bytes. */
533207340Sjkim		bpfattach (d->ifp, DLT_PPP, 4);
534207340Sjkim#endif /*NETGRAPH*/
535207340Sjkim		cp_start_e1 (c);
536207340Sjkim		cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys);
537207340Sjkim
538207340Sjkim		/* Register callback functions. */
539207340Sjkim		cp_register_transmit (c, &cp_transmit);
540207340Sjkim		cp_register_receive (c, &cp_receive);
541207340Sjkim		cp_register_error (c, &cp_error);
542207340Sjkim		d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
543207340Sjkim				GID_WHEEL, 0600, "cp%d", b->num*NCHAN+c->num);
544207340Sjkim	}
545207340Sjkim	CP_LOCK (bd);
546207340Sjkim	b->sys = bd;
547207340Sjkim	adapter[unit] = b;
548207340Sjkim	CP_UNLOCK (bd);
549207340Sjkim	splx (s);
550207340Sjkim	return 0;
551207340Sjkim}
552207340Sjkim
553207340Sjkimstatic int cp_detach (device_t dev)
554207340Sjkim{
555207340Sjkim	bdrv_t *bd = device_get_softc (dev);
556207340Sjkim	cp_board_t *b = bd->board;
557207340Sjkim	cp_chan_t *c;
558207340Sjkim	int s;
559207340Sjkim
560207340Sjkim	KASSERT (mtx_initialized (&bd->cp_mtx), ("cp mutex not initialized"));
561207340Sjkim	s = splimp ();
562207340Sjkim	CP_LOCK (bd);
563207340Sjkim	/* Check if the device is busy (open). */
564207340Sjkim	for (c = b->chan; c < b->chan + NCHAN; ++c) {
565207340Sjkim		drv_t *d = (drv_t*) c->sys;
566207340Sjkim
567207340Sjkim		if (! d || ! d->chan->type)
568207340Sjkim			continue;
569207340Sjkim		if (d->running) {
570207340Sjkim			CP_UNLOCK (bd);
571207340Sjkim			splx (s);
572207340Sjkim			return EBUSY;
573207340Sjkim		}
574207340Sjkim	}
575207340Sjkim
576207340Sjkim	/* Ok, we can unload driver */
577207340Sjkim	/* At first we should stop all channels */
578207340Sjkim	for (c = b->chan; c < b->chan + NCHAN; ++c) {
579207340Sjkim		drv_t *d = (drv_t*) c->sys;
580207340Sjkim
581207340Sjkim		if (! d || ! d->chan->type)
582228110Sjkim			continue;
583207340Sjkim
584207340Sjkim		cp_stop_chan (c);
585207340Sjkim		cp_stop_e1 (c);
586207340Sjkim		cp_set_dtr (d->chan, 0);
587207340Sjkim		cp_set_rts (d->chan, 0);
588207340Sjkim	}
589207340Sjkim
590207340Sjkim	/* Reset the adapter. */
591228110Sjkim	cp_destroy = 1;
592207340Sjkim	cp_interrupt_poll (b, 1);
593207340Sjkim	cp_led_off (b);
594207340Sjkim	cp_reset (b, 0 ,0);
595207340Sjkim	callout_stop (&led_timo[b->num]);
596207340Sjkim
597207340Sjkim	/* Disable the interrupt request. */
598207340Sjkim	bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand);
599207340Sjkim
600228110Sjkim	for (c=b->chan; c<b->chan+NCHAN; ++c) {
601207340Sjkim		drv_t *d = (drv_t*) c->sys;
602207340Sjkim
603207340Sjkim		if (! d || ! d->chan->type)
604207340Sjkim			continue;
605207340Sjkim		callout_stop (&d->timeout_handle);
606207340Sjkim#ifndef NETGRAPH
607207340Sjkim		/* Detach from the packet filter list of interfaces. */
608207340Sjkim		bpfdetach (d->ifp);
609228110Sjkim
610207340Sjkim		/* Detach from the sync PPP list. */
611207340Sjkim		sppp_detach (d->ifp);
612207340Sjkim
613207340Sjkim		/* Detach from the system list of interfaces. */
614207340Sjkim		if_detach (d->ifp);
615207340Sjkim		if_free (d->ifp);
616207340Sjkim		IF_DRAIN (&d->queue);
617228110Sjkim		mtx_destroy (&d->queue.ifq_mtx);
618207340Sjkim#else
619207340Sjkim		if (d->node) {
620207340Sjkim			ng_rmnode_self (d->node);
621207340Sjkim			NG_NODE_UNREF (d->node);
622207340Sjkim			d->node = NULL;
623207340Sjkim		}
624207340Sjkim		mtx_destroy (&d->queue.ifq_mtx);
625207340Sjkim		mtx_destroy (&d->hi_queue.ifq_mtx);
626207340Sjkim#endif
627207340Sjkim		destroy_dev (d->devt);
628207340Sjkim	}
629207340Sjkim
630207340Sjkim	b->sys = NULL;
631207340Sjkim	CP_UNLOCK (bd);
632207340Sjkim
633207340Sjkim	bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq);
634207340Sjkim	bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res);
635207340Sjkim
636207340Sjkim	CP_LOCK (bd);
637207340Sjkim	cp_led_off (b);
638207340Sjkim	CP_UNLOCK (bd);
639207340Sjkim	callout_drain (&led_timo[b->num]);
640207340Sjkim	splx (s);
641207340Sjkim
642207340Sjkim	for (c = b->chan; c < b->chan + NCHAN; ++c) {
643207340Sjkim		drv_t *d = (drv_t*) c->sys;
644207340Sjkim
645207340Sjkim		if (! d || ! d->chan->type)
646207340Sjkim			continue;
647207340Sjkim		callout_drain (&d->timeout_handle);
648207340Sjkim		channel [b->num*NCHAN + c->num] = 0;
649207340Sjkim		/* Deallocate buffers. */
650207340Sjkim		cp_bus_dma_mem_free (&d->dmamem);
651207340Sjkim	}
652207340Sjkim	adapter [b->num] = 0;
653207340Sjkim	cp_bus_dma_mem_free (&bd->dmamem);
654207340Sjkim	free (b, M_DEVBUF);
655207340Sjkim	mtx_destroy (&bd->cp_mtx);
656207340Sjkim	return 0;
657207340Sjkim}
658207340Sjkim
659207340Sjkim#ifndef NETGRAPH
660207340Sjkimstatic void cp_ifstart (struct ifnet *ifp)
661207340Sjkim{
662207340Sjkim	drv_t *d = ifp->if_softc;
663207340Sjkim	bdrv_t *bd = d->board->sys;
664207340Sjkim
665207340Sjkim	CP_LOCK (bd);
666207340Sjkim	cp_start (d);
667207340Sjkim	CP_UNLOCK (bd);
668207340Sjkim}
669207340Sjkim
670207340Sjkimstatic void cp_tlf (struct sppp *sp)
671207340Sjkim{
672281075Sdim	drv_t *d = SP2IFP(sp)->if_softc;
673207340Sjkim
674207340Sjkim	CP_DEBUG2 (d, ("cp_tlf\n"));
675207340Sjkim	/* XXXRIK: Don't forget to protect them by LOCK, or kill them. */
676207340Sjkim/*	cp_set_dtr (d->chan, 0);*/
677207340Sjkim/*	cp_set_rts (d->chan, 0);*/
678207340Sjkim	if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
679207340Sjkim		sp->pp_down (sp);
680207340Sjkim}
681207340Sjkim
682207340Sjkimstatic void cp_tls (struct sppp *sp)
683207340Sjkim{
684207340Sjkim	drv_t *d = SP2IFP(sp)->if_softc;
685207340Sjkim
686207340Sjkim	CP_DEBUG2 (d, ("cp_tls\n"));
687212761Sjkim	if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
688212761Sjkim		sp->pp_up (sp);
689212761Sjkim}
690212761Sjkim
691207340Sjkim/*
692281075Sdim * Process an ioctl request.
693207340Sjkim */
694207340Sjkimstatic int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
695281075Sdim{
696207340Sjkim	drv_t *d = ifp->if_softc;
697207340Sjkim	bdrv_t *bd = d->board->sys;
698	int error, s, was_up, should_be_up;
699
700	was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
701	error = sppp_ioctl (ifp, cmd, data);
702
703	if (error)
704		return error;
705
706	if (! (ifp->if_flags & IFF_DEBUG))
707		d->chan->debug = 0;
708	else
709		d->chan->debug = d->chan->debug_shadow;
710
711	switch (cmd) {
712	default:	   CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd));   return 0;
713	case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0;
714	case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0;
715	case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break;
716	case SIOCSIFADDR:  CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n"));  break;
717	}
718
719	/* We get here only in case of SIFFLAGS or SIFADDR. */
720	s = splimp ();
721	CP_LOCK (bd);
722	should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
723	if (! was_up && should_be_up) {
724		/* Interface goes up -- start it. */
725		cp_up (d);
726		cp_start (d);
727	} else if (was_up && ! should_be_up) {
728		/* Interface is going down -- stop it. */
729/*		if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
730		cp_down (d);
731	}
732	CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd));
733	CP_UNLOCK (bd);
734	splx (s);
735	return 0;
736}
737
738/*
739 * Initialization of interface.
740 * It seems to be never called by upper level?
741 */
742static void cp_initialize (void *softc)
743{
744	drv_t *d = softc;
745
746	CP_DEBUG (d, ("cp_initialize\n"));
747}
748#endif /*NETGRAPH*/
749
750/*
751 * Stop the interface.  Called on splimp().
752 */
753static void cp_down (drv_t *d)
754{
755	CP_DEBUG (d, ("cp_down\n"));
756	/* Interface is going down -- stop it. */
757	cp_set_dtr (d->chan, 0);
758	cp_set_rts (d->chan, 0);
759
760	d->running = 0;
761	callout_stop (&d->timeout_handle);
762}
763
764/*
765 * Start the interface.  Called on splimp().
766 */
767static void cp_up (drv_t *d)
768{
769	CP_DEBUG (d, ("cp_up\n"));
770	cp_set_dtr (d->chan, 1);
771	cp_set_rts (d->chan, 1);
772	d->running = 1;
773}
774
775/*
776 * Start output on the interface.  Get another datagram to send
777 * off of the interface queue, and copy it to the interface
778 * before starting the output.
779 */
780static void cp_send (drv_t *d)
781{
782	struct mbuf *m;
783	u_short len;
784
785	CP_DEBUG2 (d, ("cp_send, tn=%d te=%d\n", d->chan->tn, d->chan->te));
786
787	/* No output if the interface is down. */
788	if (! d->running)
789		return;
790
791	/* No output if the modem is off. */
792	if (! (d->chan->lloop || d->chan->type != T_SERIAL ||
793		cp_get_dsr (d->chan)))
794		return;
795
796	while (cp_transmit_space (d->chan)) {
797		/* Get the packet to send. */
798#ifdef NETGRAPH
799		IF_DEQUEUE (&d->hi_queue, m);
800		if (! m)
801			IF_DEQUEUE (&d->queue, m);
802#else
803		m = sppp_dequeue (d->ifp);
804#endif
805		if (! m)
806			return;
807#ifndef NETGRAPH
808		BPF_MTAP (d->ifp, m);
809#endif
810		len = m_length (m, NULL);
811		if (len >= BUFSZ)
812			printf ("%s: too long packet: %d bytes: ",
813				d->name, len);
814		else if (! m->m_next)
815			cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0);
816		else {
817			u_char *buf = d->chan->tbuf[d->chan->te];
818			m_copydata (m, 0, len, buf);
819			cp_send_packet (d->chan, buf, len, 0);
820		}
821		m_freem (m);
822		/* Set up transmit timeout, if the transmit ring is not empty.*/
823		d->timeout = 10;
824	}
825#ifndef NETGRAPH
826	d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
827#endif
828}
829
830/*
831 * Start output on the interface.
832 * Always called on splimp().
833 */
834static void cp_start (drv_t *d)
835{
836	if (d->running) {
837		if (! d->chan->dtr)
838			cp_set_dtr (d->chan, 1);
839		if (! d->chan->rts)
840			cp_set_rts (d->chan, 1);
841		cp_send (d);
842		callout_reset (&d->timeout_handle, hz, cp_watchdog_timer, d);
843	}
844}
845
846/*
847 * Handle transmit timeouts.
848 * Recover after lost transmit interrupts.
849 * Always called on splimp().
850 */
851static void cp_watchdog (drv_t *d)
852{
853	CP_DEBUG (d, ("device timeout\n"));
854	if (d->running) {
855		cp_stop_chan (d->chan);
856		cp_stop_e1 (d->chan);
857		cp_start_e1 (d->chan);
858		cp_start_chan (d->chan, 1, 1, 0, 0);
859		cp_set_dtr (d->chan, 1);
860		cp_set_rts (d->chan, 1);
861		cp_start (d);
862	}
863}
864
865static void cp_watchdog_timer (void *arg)
866{
867	drv_t *d = arg;
868	bdrv_t *bd = d->board->sys;
869
870	CP_LOCK (bd);
871	if (d->timeout == 1)
872		cp_watchdog (d);
873	if (d->timeout)
874		d->timeout--;
875	callout_reset (&d->timeout_handle, hz, cp_watchdog_timer, d);
876	CP_UNLOCK (bd);
877}
878
879static void cp_transmit (cp_chan_t *c, void *attachment, int len)
880{
881	drv_t *d = c->sys;
882
883	d->timeout = 0;
884#ifndef NETGRAPH
885	++d->ifp->if_opackets;
886	d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
887#endif
888	cp_start (d);
889}
890
891static void cp_receive (cp_chan_t *c, unsigned char *data, int len)
892{
893	drv_t *d = c->sys;
894	struct mbuf *m;
895#ifdef NETGRAPH
896	int error;
897#endif
898
899	if (! d->running)
900		return;
901
902	m = makembuf (data, len);
903	if (! m) {
904		CP_DEBUG (d, ("no memory for packet\n"));
905#ifndef NETGRAPH
906		++d->ifp->if_iqdrops;
907#endif
908		return;
909	}
910	if (c->debug > 1)
911		printmbuf (m);
912#ifdef NETGRAPH
913	m->m_pkthdr.rcvif = 0;
914	NG_SEND_DATA_ONLY (error, d->hook, m);
915#else
916	++d->ifp->if_ipackets;
917	m->m_pkthdr.rcvif = d->ifp;
918	/* Check if there's a BPF listener on this interface.
919	 * If so, hand off the raw packet to bpf. */
920	BPF_TAP (d->ifp, data, len);
921	IF_ENQUEUE (&d->queue, m);
922#endif
923}
924
925static void cp_error (cp_chan_t *c, int data)
926{
927	drv_t *d = c->sys;
928
929	switch (data) {
930	case CP_FRAME:
931		CP_DEBUG (d, ("frame error\n"));
932#ifndef NETGRAPH
933		++d->ifp->if_ierrors;
934#endif
935		break;
936	case CP_CRC:
937		CP_DEBUG (d, ("crc error\n"));
938#ifndef NETGRAPH
939		++d->ifp->if_ierrors;
940#endif
941		break;
942	case CP_OVERRUN:
943		CP_DEBUG (d, ("overrun error\n"));
944#ifndef NETGRAPH
945		++d->ifp->if_collisions;
946		++d->ifp->if_ierrors;
947#endif
948		break;
949	case CP_OVERFLOW:
950		CP_DEBUG (d, ("overflow error\n"));
951#ifndef NETGRAPH
952		++d->ifp->if_ierrors;
953#endif
954		break;
955	case CP_UNDERRUN:
956		CP_DEBUG (d, ("underrun error\n"));
957		d->timeout = 0;
958#ifndef NETGRAPH
959		++d->ifp->if_oerrors;
960		d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
961#endif
962		cp_start (d);
963		break;
964	default:
965		CP_DEBUG (d, ("error #%d\n", data));
966		break;
967	}
968}
969
970/*
971 * You also need read, write, open, close routines.
972 * This should get you started
973 */
974static int cp_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
975{
976	int unit = dev2unit (dev);
977	drv_t *d;
978
979	if (unit >= NBRD*NCHAN || ! (d = channel[unit]))
980		return ENXIO;
981	CP_DEBUG2 (d, ("cp_open\n"));
982	return 0;
983}
984
985/*
986 * Only called on the LAST close.
987 */
988static int cp_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
989{
990	drv_t *d = channel [dev2unit (dev)];
991
992	CP_DEBUG2 (d, ("cp_close\n"));
993	return 0;
994}
995
996static int cp_modem_status (cp_chan_t *c)
997{
998	drv_t *d = c->sys;
999	bdrv_t *bd = d->board->sys;
1000	int status, s;
1001
1002	status = d->running ? TIOCM_LE : 0;
1003	s = splimp ();
1004	CP_LOCK (bd);
1005	if (cp_get_cd  (c)) status |= TIOCM_CD;
1006	if (cp_get_cts (c)) status |= TIOCM_CTS;
1007	if (cp_get_dsr (c)) status |= TIOCM_DSR;
1008	if (c->dtr)	    status |= TIOCM_DTR;
1009	if (c->rts)	    status |= TIOCM_RTS;
1010	CP_UNLOCK (bd);
1011	splx (s);
1012	return status;
1013}
1014
1015static int cp_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1016{
1017	drv_t *d = channel [dev2unit (dev)];
1018	bdrv_t *bd = d->board->sys;
1019	cp_chan_t *c = d->chan;
1020	struct serial_statistics *st;
1021	struct e1_statistics *opte1;
1022	struct e3_statistics *opte3;
1023	int error, s;
1024	char mask[16];
1025
1026	switch (cmd) {
1027	case SERIAL_GETREGISTERED:
1028		CP_DEBUG2 (d, ("ioctl: getregistered\n"));
1029		bzero (mask, sizeof(mask));
1030		for (s=0; s<NBRD*NCHAN; ++s)
1031			if (channel [s])
1032				mask [s/8] |= 1 << (s & 7);
1033		bcopy (mask, data, sizeof (mask));
1034		return 0;
1035
1036#ifndef NETGRAPH
1037	case SERIAL_GETPROTO:
1038		CP_DEBUG2 (d, ("ioctl: getproto\n"));
1039		strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1040			(d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1041		return 0;
1042
1043	case SERIAL_SETPROTO:
1044		CP_DEBUG2 (d, ("ioctl: setproto\n"));
1045		/* Only for superuser! */
1046		error = priv_check (td, PRIV_DRIVER);
1047		if (error)
1048			return error;
1049		if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
1050			return EBUSY;
1051		if (! strcmp ("cisco", (char*)data)) {
1052			IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1053			IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1054			d->ifp->if_flags |= PP_CISCO;
1055#if PP_FR != 0
1056		} else if (! strcmp ("fr", (char*)data)) {
1057			d->ifp->if_flags &= ~(PP_CISCO);
1058			IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1059#endif
1060		} else if (! strcmp ("ppp", (char*)data)) {
1061			IFP2SP(d->ifp)->pp_flags &= ~PP_FR;
1062			IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1063			d->ifp->if_flags &= ~(PP_CISCO);
1064		} else
1065			return EINVAL;
1066		return 0;
1067
1068	case SERIAL_GETKEEPALIVE:
1069		CP_DEBUG2 (d, ("ioctl: getkeepalive\n"));
1070		if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1071			(d->ifp->if_flags & PP_CISCO))
1072			return EINVAL;
1073		*(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1074		return 0;
1075
1076	case SERIAL_SETKEEPALIVE:
1077		CP_DEBUG2 (d, ("ioctl: setkeepalive\n"));
1078		/* Only for superuser! */
1079		error = priv_check (td, PRIV_DRIVER);
1080		if (error)
1081			return error;
1082		if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1083			(d->ifp->if_flags & PP_CISCO))
1084			return EINVAL;
1085		s = splimp ();
1086		CP_LOCK (bd);
1087		if (*(int*)data)
1088			IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1089		else
1090			IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1091		CP_UNLOCK (bd);
1092		splx (s);
1093		return 0;
1094#endif /*NETGRAPH*/
1095
1096	case SERIAL_GETMODE:
1097		CP_DEBUG2 (d, ("ioctl: getmode\n"));
1098		*(int*)data = SERIAL_HDLC;
1099		return 0;
1100
1101	case SERIAL_SETMODE:
1102		/* Only for superuser! */
1103		error = priv_check (td, PRIV_DRIVER);
1104		if (error)
1105			return error;
1106		if (*(int*)data != SERIAL_HDLC)
1107			return EINVAL;
1108		return 0;
1109
1110	case SERIAL_GETCFG:
1111		CP_DEBUG2 (d, ("ioctl: getcfg\n"));
1112		if (c->type != T_E1 || c->unfram)
1113			return EINVAL;
1114		*(char*)data = c->board->mux ? 'c' : 'a';
1115		return 0;
1116
1117	case SERIAL_SETCFG:
1118		CP_DEBUG2 (d, ("ioctl: setcfg\n"));
1119		error = priv_check (td, PRIV_DRIVER);
1120		if (error)
1121			return error;
1122		if (c->type != T_E1)
1123			return EINVAL;
1124		s = splimp ();
1125		CP_LOCK (bd);
1126		cp_set_mux (c->board, *((char*)data) == 'c');
1127		CP_UNLOCK (bd);
1128		splx (s);
1129		return 0;
1130
1131	case SERIAL_GETSTAT:
1132		CP_DEBUG2 (d, ("ioctl: getstat\n"));
1133		st = (struct serial_statistics*) data;
1134		st->rintr  = c->rintr;
1135		st->tintr  = c->tintr;
1136		st->mintr  = 0;
1137		st->ibytes = c->ibytes;
1138		st->ipkts  = c->ipkts;
1139		st->obytes = c->obytes;
1140		st->opkts  = c->opkts;
1141		st->ierrs  = c->overrun + c->frame + c->crc;
1142		st->oerrs  = c->underrun;
1143		return 0;
1144
1145	case SERIAL_GETESTAT:
1146		CP_DEBUG2 (d, ("ioctl: getestat\n"));
1147		if (c->type != T_E1 && c->type != T_G703)
1148			return EINVAL;
1149		opte1 = (struct e1_statistics*) data;
1150		opte1->status	    = c->status;
1151		opte1->cursec	    = c->cursec;
1152		opte1->totsec	    = c->totsec + c->cursec;
1153
1154		opte1->currnt.bpv   = c->currnt.bpv;
1155		opte1->currnt.fse   = c->currnt.fse;
1156		opte1->currnt.crce  = c->currnt.crce;
1157		opte1->currnt.rcrce = c->currnt.rcrce;
1158		opte1->currnt.uas   = c->currnt.uas;
1159		opte1->currnt.les   = c->currnt.les;
1160		opte1->currnt.es    = c->currnt.es;
1161		opte1->currnt.bes   = c->currnt.bes;
1162		opte1->currnt.ses   = c->currnt.ses;
1163		opte1->currnt.oofs  = c->currnt.oofs;
1164		opte1->currnt.css   = c->currnt.css;
1165		opte1->currnt.dm    = c->currnt.dm;
1166
1167		opte1->total.bpv    = c->total.bpv   + c->currnt.bpv;
1168		opte1->total.fse    = c->total.fse   + c->currnt.fse;
1169		opte1->total.crce   = c->total.crce  + c->currnt.crce;
1170		opte1->total.rcrce  = c->total.rcrce + c->currnt.rcrce;
1171		opte1->total.uas    = c->total.uas   + c->currnt.uas;
1172		opte1->total.les    = c->total.les   + c->currnt.les;
1173		opte1->total.es	    = c->total.es    + c->currnt.es;
1174		opte1->total.bes    = c->total.bes   + c->currnt.bes;
1175		opte1->total.ses    = c->total.ses   + c->currnt.ses;
1176		opte1->total.oofs   = c->total.oofs  + c->currnt.oofs;
1177		opte1->total.css    = c->total.css   + c->currnt.css;
1178		opte1->total.dm	    = c->total.dm    + c->currnt.dm;
1179		for (s=0; s<48; ++s) {
1180			opte1->interval[s].bpv   = c->interval[s].bpv;
1181			opte1->interval[s].fse   = c->interval[s].fse;
1182			opte1->interval[s].crce  = c->interval[s].crce;
1183			opte1->interval[s].rcrce = c->interval[s].rcrce;
1184			opte1->interval[s].uas   = c->interval[s].uas;
1185			opte1->interval[s].les   = c->interval[s].les;
1186			opte1->interval[s].es	 = c->interval[s].es;
1187			opte1->interval[s].bes   = c->interval[s].bes;
1188			opte1->interval[s].ses   = c->interval[s].ses;
1189			opte1->interval[s].oofs  = c->interval[s].oofs;
1190			opte1->interval[s].css   = c->interval[s].css;
1191			opte1->interval[s].dm	 = c->interval[s].dm;
1192		}
1193		return 0;
1194
1195	case SERIAL_GETE3STAT:
1196		CP_DEBUG2 (d, ("ioctl: gete3stat\n"));
1197		if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1198			return EINVAL;
1199		opte3 = (struct e3_statistics*) data;
1200
1201		opte3->status = c->e3status;
1202		opte3->cursec = (c->e3csec_5 * 2 + 1) / 10;
1203		opte3->totsec = c->e3tsec + opte3->cursec;
1204
1205		opte3->ccv = c->e3ccv;
1206		opte3->tcv = c->e3tcv + opte3->ccv;
1207
1208		for (s = 0; s < 48; ++s) {
1209			opte3->icv[s] = c->e3icv[s];
1210		}
1211		return 0;
1212
1213	case SERIAL_CLRSTAT:
1214		CP_DEBUG2 (d, ("ioctl: clrstat\n"));
1215		/* Only for superuser! */
1216		error = priv_check (td, PRIV_DRIVER);
1217		if (error)
1218			return error;
1219		c->rintr    = 0;
1220		c->tintr    = 0;
1221		c->ibytes   = 0;
1222		c->obytes   = 0;
1223		c->ipkts    = 0;
1224		c->opkts    = 0;
1225		c->overrun  = 0;
1226		c->frame    = 0;
1227		c->crc	    = 0;
1228		c->underrun = 0;
1229		bzero (&c->currnt, sizeof (c->currnt));
1230		bzero (&c->total, sizeof (c->total));
1231		bzero (c->interval, sizeof (c->interval));
1232		c->e3ccv    = 0;
1233		c->e3tcv    = 0;
1234		bzero (c->e3icv, sizeof (c->e3icv));
1235		return 0;
1236
1237	case SERIAL_GETBAUD:
1238		CP_DEBUG2 (d, ("ioctl: getbaud\n"));
1239		*(long*)data = c->baud;
1240		return 0;
1241
1242	case SERIAL_SETBAUD:
1243		CP_DEBUG2 (d, ("ioctl: setbaud\n"));
1244		/* Only for superuser! */
1245		error = priv_check (td, PRIV_DRIVER);
1246		if (error)
1247			return error;
1248		s = splimp ();
1249		CP_LOCK (bd);
1250		cp_set_baud (c, *(long*)data);
1251		CP_UNLOCK (bd);
1252		splx (s);
1253		return 0;
1254
1255	case SERIAL_GETLOOP:
1256		CP_DEBUG2 (d, ("ioctl: getloop\n"));
1257		*(int*)data = c->lloop;
1258		return 0;
1259
1260	case SERIAL_SETLOOP:
1261		CP_DEBUG2 (d, ("ioctl: setloop\n"));
1262		/* Only for superuser! */
1263		error = priv_check (td, PRIV_DRIVER);
1264		if (error)
1265			return error;
1266		s = splimp ();
1267		CP_LOCK (bd);
1268		cp_set_lloop (c, *(int*)data);
1269		CP_UNLOCK (bd);
1270		splx (s);
1271		return 0;
1272
1273	case SERIAL_GETDPLL:
1274		CP_DEBUG2 (d, ("ioctl: getdpll\n"));
1275		if (c->type != T_SERIAL)
1276			return EINVAL;
1277		*(int*)data = c->dpll;
1278		return 0;
1279
1280	case SERIAL_SETDPLL:
1281		CP_DEBUG2 (d, ("ioctl: setdpll\n"));
1282		/* Only for superuser! */
1283		error = priv_check (td, PRIV_DRIVER);
1284		if (error)
1285			return error;
1286		if (c->type != T_SERIAL)
1287			return EINVAL;
1288		s = splimp ();
1289		CP_LOCK (bd);
1290		cp_set_dpll (c, *(int*)data);
1291		CP_UNLOCK (bd);
1292		splx (s);
1293		return 0;
1294
1295	case SERIAL_GETNRZI:
1296		CP_DEBUG2 (d, ("ioctl: getnrzi\n"));
1297		if (c->type != T_SERIAL)
1298			return EINVAL;
1299		*(int*)data = c->nrzi;
1300		return 0;
1301
1302	case SERIAL_SETNRZI:
1303		CP_DEBUG2 (d, ("ioctl: setnrzi\n"));
1304		/* Only for superuser! */
1305		error = priv_check (td, PRIV_DRIVER);
1306		if (error)
1307			return error;
1308		if (c->type != T_SERIAL)
1309			return EINVAL;
1310		s = splimp ();
1311		CP_LOCK (bd);
1312		cp_set_nrzi (c, *(int*)data);
1313		CP_UNLOCK (bd);
1314		splx (s);
1315		return 0;
1316
1317	case SERIAL_GETDEBUG:
1318		CP_DEBUG2 (d, ("ioctl: getdebug\n"));
1319		*(int*)data = d->chan->debug;
1320		return 0;
1321
1322	case SERIAL_SETDEBUG:
1323		CP_DEBUG2 (d, ("ioctl: setdebug\n"));
1324		/* Only for superuser! */
1325		error = priv_check (td, PRIV_DRIVER);
1326		if (error)
1327			return error;
1328#ifndef	NETGRAPH
1329		/*
1330		 * The debug_shadow is always greater than zero for logic
1331		 * simplicity.  For switching debug off the IFF_DEBUG is
1332		 * responsible.
1333		 */
1334		d->chan->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
1335		if (d->ifp->if_flags & IFF_DEBUG)
1336			d->chan->debug = d->chan->debug_shadow;
1337#else
1338		d->chan->debug = *(int*)data;
1339#endif
1340		return 0;
1341
1342	case SERIAL_GETHIGAIN:
1343		CP_DEBUG2 (d, ("ioctl: gethigain\n"));
1344		if (c->type != T_E1)
1345			return EINVAL;
1346		*(int*)data = c->higain;
1347		return 0;
1348
1349	case SERIAL_SETHIGAIN:
1350		CP_DEBUG2 (d, ("ioctl: sethigain\n"));
1351		/* Only for superuser! */
1352		error = priv_check (td, PRIV_DRIVER);
1353		if (error)
1354			return error;
1355		if (c->type != T_E1)
1356			return EINVAL;
1357		s = splimp ();
1358		CP_LOCK (bd);
1359		cp_set_higain (c, *(int*)data);
1360		CP_UNLOCK (bd);
1361		splx (s);
1362		return 0;
1363
1364	case SERIAL_GETPHONY:
1365		CP_DEBUG2 (d, ("ioctl: getphony\n"));
1366		if (c->type != T_E1)
1367			return EINVAL;
1368		*(int*)data = c->phony;
1369		return 0;
1370
1371	case SERIAL_SETPHONY:
1372		CP_DEBUG2 (d, ("ioctl: setphony\n"));
1373		/* Only for superuser! */
1374		error = priv_check (td, PRIV_DRIVER);
1375		if (error)
1376			return error;
1377		if (c->type != T_E1)
1378			return EINVAL;
1379		s = splimp ();
1380		CP_LOCK (bd);
1381		cp_set_phony (c, *(int*)data);
1382		CP_UNLOCK (bd);
1383		splx (s);
1384		return 0;
1385
1386	case SERIAL_GETUNFRAM:
1387		CP_DEBUG2 (d, ("ioctl: getunfram\n"));
1388		if (c->type != T_E1)
1389			return EINVAL;
1390		*(int*)data = c->unfram;
1391		return 0;
1392
1393	case SERIAL_SETUNFRAM:
1394		CP_DEBUG2 (d, ("ioctl: setunfram\n"));
1395		/* Only for superuser! */
1396		error = priv_check (td, PRIV_DRIVER);
1397		if (error)
1398			return error;
1399		if (c->type != T_E1)
1400			return EINVAL;
1401		s = splimp ();
1402		CP_LOCK (bd);
1403		cp_set_unfram (c, *(int*)data);
1404		CP_UNLOCK (bd);
1405		splx (s);
1406		return 0;
1407
1408	case SERIAL_GETSCRAMBLER:
1409		CP_DEBUG2 (d, ("ioctl: getscrambler\n"));
1410		if (c->type != T_G703 && !c->unfram)
1411			return EINVAL;
1412		*(int*)data = c->scrambler;
1413		return 0;
1414
1415	case SERIAL_SETSCRAMBLER:
1416		CP_DEBUG2 (d, ("ioctl: setscrambler\n"));
1417		/* Only for superuser! */
1418		error = priv_check (td, PRIV_DRIVER);
1419		if (error)
1420			return error;
1421		if (c->type != T_G703 && !c->unfram)
1422			return EINVAL;
1423		s = splimp ();
1424		CP_LOCK (bd);
1425		cp_set_scrambler (c, *(int*)data);
1426		CP_UNLOCK (bd);
1427		splx (s);
1428		return 0;
1429
1430	case SERIAL_GETMONITOR:
1431		CP_DEBUG2 (d, ("ioctl: getmonitor\n"));
1432		if (c->type != T_E1 &&
1433		    c->type != T_E3 &&
1434		    c->type != T_T3 &&
1435		    c->type != T_STS1)
1436			return EINVAL;
1437		*(int*)data = c->monitor;
1438		return 0;
1439
1440	case SERIAL_SETMONITOR:
1441		CP_DEBUG2 (d, ("ioctl: setmonitor\n"));
1442		/* Only for superuser! */
1443		error = priv_check (td, PRIV_DRIVER);
1444		if (error)
1445			return error;
1446		if (c->type != T_E1)
1447			return EINVAL;
1448		s = splimp ();
1449		CP_LOCK (bd);
1450		cp_set_monitor (c, *(int*)data);
1451		CP_UNLOCK (bd);
1452		splx (s);
1453		return 0;
1454
1455	case SERIAL_GETUSE16:
1456		CP_DEBUG2 (d, ("ioctl: getuse16\n"));
1457		if (c->type != T_E1 || c->unfram)
1458			return EINVAL;
1459		*(int*)data = c->use16;
1460		return 0;
1461
1462	case SERIAL_SETUSE16:
1463		CP_DEBUG2 (d, ("ioctl: setuse16\n"));
1464		/* Only for superuser! */
1465		error = priv_check (td, PRIV_DRIVER);
1466		if (error)
1467			return error;
1468		if (c->type != T_E1)
1469			return EINVAL;
1470		s = splimp ();
1471		CP_LOCK (bd);
1472		cp_set_use16 (c, *(int*)data);
1473		CP_UNLOCK (bd);
1474		splx (s);
1475		return 0;
1476
1477	case SERIAL_GETCRC4:
1478		CP_DEBUG2 (d, ("ioctl: getcrc4\n"));
1479		if (c->type != T_E1 || c->unfram)
1480			return EINVAL;
1481		*(int*)data = c->crc4;
1482		return 0;
1483
1484	case SERIAL_SETCRC4:
1485		CP_DEBUG2 (d, ("ioctl: setcrc4\n"));
1486		/* Only for superuser! */
1487		error = priv_check (td, PRIV_DRIVER);
1488		if (error)
1489			return error;
1490		if (c->type != T_E1)
1491			return EINVAL;
1492		s = splimp ();
1493		CP_LOCK (bd);
1494		cp_set_crc4 (c, *(int*)data);
1495		CP_UNLOCK (bd);
1496		splx (s);
1497		return 0;
1498
1499	case SERIAL_GETCLK:
1500		CP_DEBUG2 (d, ("ioctl: getclk\n"));
1501		if (c->type != T_E1 &&
1502		    c->type != T_G703 &&
1503		    c->type != T_E3 &&
1504		    c->type != T_T3 &&
1505		    c->type != T_STS1)
1506			return EINVAL;
1507		switch (c->gsyn) {
1508		default:	*(int*)data = E1CLK_INTERNAL;		break;
1509		case GSYN_RCV:	*(int*)data = E1CLK_RECEIVE;		break;
1510		case GSYN_RCV0:	*(int*)data = E1CLK_RECEIVE_CHAN0;	break;
1511		case GSYN_RCV1:	*(int*)data = E1CLK_RECEIVE_CHAN1;	break;
1512		case GSYN_RCV2:	*(int*)data = E1CLK_RECEIVE_CHAN2;	break;
1513		case GSYN_RCV3:	*(int*)data = E1CLK_RECEIVE_CHAN3;	break;
1514		}
1515		return 0;
1516
1517	case SERIAL_SETCLK:
1518		CP_DEBUG2 (d, ("ioctl: setclk\n"));
1519		/* Only for superuser! */
1520		error = priv_check (td, PRIV_DRIVER);
1521		if (error)
1522			return error;
1523		if (c->type != T_E1 &&
1524		    c->type != T_G703 &&
1525		    c->type != T_E3 &&
1526		    c->type != T_T3 &&
1527		    c->type != T_STS1)
1528			return EINVAL;
1529		s = splimp ();
1530		CP_LOCK (bd);
1531		switch (*(int*)data) {
1532		default:		  cp_set_gsyn (c, GSYN_INT);  break;
1533		case E1CLK_RECEIVE:	  cp_set_gsyn (c, GSYN_RCV);  break;
1534		case E1CLK_RECEIVE_CHAN0: cp_set_gsyn (c, GSYN_RCV0); break;
1535		case E1CLK_RECEIVE_CHAN1: cp_set_gsyn (c, GSYN_RCV1); break;
1536		case E1CLK_RECEIVE_CHAN2: cp_set_gsyn (c, GSYN_RCV2); break;
1537		case E1CLK_RECEIVE_CHAN3: cp_set_gsyn (c, GSYN_RCV3); break;
1538		}
1539		CP_UNLOCK (bd);
1540		splx (s);
1541		return 0;
1542
1543	case SERIAL_GETTIMESLOTS:
1544		CP_DEBUG2 (d, ("ioctl: gettimeslots\n"));
1545		if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1546			return EINVAL;
1547		*(u_long*)data = c->ts;
1548		return 0;
1549
1550	case SERIAL_SETTIMESLOTS:
1551		CP_DEBUG2 (d, ("ioctl: settimeslots\n"));
1552		/* Only for superuser! */
1553		error = priv_check (td, PRIV_DRIVER);
1554		if (error)
1555			return error;
1556		if ((c->type != T_E1 || c->unfram) && c->type != T_DATA)
1557			return EINVAL;
1558		s = splimp ();
1559		CP_LOCK (bd);
1560		cp_set_ts (c, *(u_long*)data);
1561		CP_UNLOCK (bd);
1562		splx (s);
1563		return 0;
1564
1565	case SERIAL_GETINVCLK:
1566		CP_DEBUG2 (d, ("ioctl: getinvclk\n"));
1567#if 1
1568		return EINVAL;
1569#else
1570		if (c->type != T_SERIAL)
1571			return EINVAL;
1572		*(int*)data = c->invtxc;
1573		return 0;
1574#endif
1575
1576	case SERIAL_SETINVCLK:
1577		CP_DEBUG2 (d, ("ioctl: setinvclk\n"));
1578		/* Only for superuser! */
1579		error = priv_check (td, PRIV_DRIVER);
1580		if (error)
1581			return error;
1582		if (c->type != T_SERIAL)
1583			return EINVAL;
1584		s = splimp ();
1585		CP_LOCK (bd);
1586		cp_set_invtxc (c, *(int*)data);
1587		cp_set_invrxc (c, *(int*)data);
1588		CP_UNLOCK (bd);
1589		splx (s);
1590		return 0;
1591
1592	case SERIAL_GETINVTCLK:
1593		CP_DEBUG2 (d, ("ioctl: getinvtclk\n"));
1594		if (c->type != T_SERIAL)
1595			return EINVAL;
1596		*(int*)data = c->invtxc;
1597		return 0;
1598
1599	case SERIAL_SETINVTCLK:
1600		CP_DEBUG2 (d, ("ioctl: setinvtclk\n"));
1601		/* Only for superuser! */
1602		error = priv_check (td, PRIV_DRIVER);
1603		if (error)
1604			return error;
1605		if (c->type != T_SERIAL)
1606			return EINVAL;
1607		s = splimp ();
1608		CP_LOCK (bd);
1609		cp_set_invtxc (c, *(int*)data);
1610		CP_UNLOCK (bd);
1611		splx (s);
1612		return 0;
1613
1614	case SERIAL_GETINVRCLK:
1615		CP_DEBUG2 (d, ("ioctl: getinvrclk\n"));
1616		if (c->type != T_SERIAL)
1617			return EINVAL;
1618		*(int*)data = c->invrxc;
1619		return 0;
1620
1621	case SERIAL_SETINVRCLK:
1622		CP_DEBUG2 (d, ("ioctl: setinvrclk\n"));
1623		/* Only for superuser! */
1624		error = priv_check (td, PRIV_DRIVER);
1625		if (error)
1626			return error;
1627		if (c->type != T_SERIAL)
1628			return EINVAL;
1629		s = splimp ();
1630		CP_LOCK (bd);
1631		cp_set_invrxc (c, *(int*)data);
1632		CP_UNLOCK (bd);
1633		splx (s);
1634		return 0;
1635
1636	case SERIAL_GETLEVEL:
1637		CP_DEBUG2 (d, ("ioctl: getlevel\n"));
1638		if (c->type != T_G703)
1639			return EINVAL;
1640		s = splimp ();
1641		CP_LOCK (bd);
1642		*(int*)data = cp_get_lq (c);
1643		CP_UNLOCK (bd);
1644		splx (s);
1645		return 0;
1646
1647#if 0
1648	case SERIAL_RESET:
1649		CP_DEBUG2 (d, ("ioctl: reset\n"));
1650		/* Only for superuser! */
1651		error = priv_check (td, PRIV_DRIVER);
1652		if (error)
1653			return error;
1654		s = splimp ();
1655		CP_LOCK (bd);
1656		cp_reset (c->board, 0, 0);
1657		CP_UNLOCK (bd);
1658		splx (s);
1659		return 0;
1660
1661	case SERIAL_HARDRESET:
1662		CP_DEBUG2 (d, ("ioctl: hardreset\n"));
1663		/* Only for superuser! */
1664		error = priv_check (td, PRIV_DRIVER);
1665		if (error)
1666			return error;
1667		s = splimp ();
1668		CP_LOCK (bd);
1669		/* hard_reset (c->board); */
1670		CP_UNLOCK (bd);
1671		splx (s);
1672		return 0;
1673#endif
1674
1675	case SERIAL_GETCABLE:
1676		CP_DEBUG2 (d, ("ioctl: getcable\n"));
1677		if (c->type != T_SERIAL)
1678			return EINVAL;
1679		s = splimp ();
1680		CP_LOCK (bd);
1681		*(int*)data = cp_get_cable (c);
1682		CP_UNLOCK (bd);
1683		splx (s);
1684		return 0;
1685
1686	case SERIAL_GETDIR:
1687		CP_DEBUG2 (d, ("ioctl: getdir\n"));
1688		if (c->type != T_E1 && c->type != T_DATA)
1689			return EINVAL;
1690		*(int*)data = c->dir;
1691		return 0;
1692
1693	case SERIAL_SETDIR:
1694		CP_DEBUG2 (d, ("ioctl: setdir\n"));
1695		/* Only for superuser! */
1696		error = priv_check (td, PRIV_DRIVER);
1697		if (error)
1698			return error;
1699		s = splimp ();
1700		CP_LOCK (bd);
1701		cp_set_dir (c, *(int*)data);
1702		CP_UNLOCK (bd);
1703		splx (s);
1704		return 0;
1705
1706	case SERIAL_GETRLOOP:
1707		CP_DEBUG2 (d, ("ioctl: getrloop\n"));
1708		if (c->type != T_G703 &&
1709		    c->type != T_E3 &&
1710		    c->type != T_T3 &&
1711		    c->type != T_STS1)
1712			return EINVAL;
1713		*(int*)data = cp_get_rloop (c);
1714		return 0;
1715
1716	case SERIAL_SETRLOOP:
1717		CP_DEBUG2 (d, ("ioctl: setloop\n"));
1718		if (c->type != T_E3 && c->type != T_T3 && c->type != T_STS1)
1719			return EINVAL;
1720		/* Only for superuser! */
1721		error = priv_check (td, PRIV_DRIVER);
1722		if (error)
1723			return error;
1724		s = splimp ();
1725		CP_LOCK (bd);
1726		cp_set_rloop (c, *(int*)data);
1727		CP_UNLOCK (bd);
1728		splx (s);
1729		return 0;
1730
1731	case SERIAL_GETCABLEN:
1732		CP_DEBUG2 (d, ("ioctl: getcablen\n"));
1733		if (c->type != T_T3 && c->type != T_STS1)
1734			return EINVAL;
1735		*(int*)data = c->cablen;
1736		return 0;
1737
1738	case SERIAL_SETCABLEN:
1739		CP_DEBUG2 (d, ("ioctl: setloop\n"));
1740		if (c->type != T_T3 && c->type != T_STS1)
1741			return EINVAL;
1742		/* Only for superuser! */
1743		error = priv_check (td, PRIV_DRIVER);
1744		if (error)
1745			return error;
1746		s = splimp ();
1747		CP_LOCK (bd);
1748		cp_set_cablen (c, *(int*)data);
1749		CP_UNLOCK (bd);
1750		splx (s);
1751		return 0;
1752
1753	case TIOCSDTR:	/* Set DTR */
1754		s = splimp ();
1755		CP_LOCK (bd);
1756		cp_set_dtr (c, 1);
1757		CP_UNLOCK (bd);
1758		splx (s);
1759		return 0;
1760
1761	case TIOCCDTR:	/* Clear DTR */
1762		s = splimp ();
1763		CP_LOCK (bd);
1764		cp_set_dtr (c, 0);
1765		CP_UNLOCK (bd);
1766		splx (s);
1767		return 0;
1768
1769	case TIOCMSET:	/* Set DTR/RTS */
1770		s = splimp ();
1771		CP_LOCK (bd);
1772		cp_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1773		cp_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1774		CP_UNLOCK (bd);
1775		splx (s);
1776		return 0;
1777
1778	case TIOCMBIS:	/* Add DTR/RTS */
1779		s = splimp ();
1780		CP_LOCK (bd);
1781		if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 1);
1782		if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 1);
1783		CP_UNLOCK (bd);
1784		splx (s);
1785		return 0;
1786
1787	case TIOCMBIC:	/* Clear DTR/RTS */
1788		s = splimp ();
1789		CP_LOCK (bd);
1790		if (*(int*)data & TIOCM_DTR) cp_set_dtr (c, 0);
1791		if (*(int*)data & TIOCM_RTS) cp_set_rts (c, 0);
1792		CP_UNLOCK (bd);
1793		splx (s);
1794		return 0;
1795
1796	case TIOCMGET:	/* Get modem status */
1797		*(int*)data = cp_modem_status (c);
1798		return 0;
1799	}
1800	return ENOTTY;
1801}
1802
1803#ifdef NETGRAPH
1804static int ng_cp_constructor (node_p node)
1805{
1806	drv_t *d = NG_NODE_PRIVATE (node);
1807	CP_DEBUG (d, ("Constructor\n"));
1808	return EINVAL;
1809}
1810
1811static int ng_cp_newhook (node_p node, hook_p hook, const char *name)
1812{
1813	int s;
1814	drv_t *d = NG_NODE_PRIVATE (node);
1815	bdrv_t *bd = d->board->sys;
1816
1817	CP_DEBUG (d, ("Newhook\n"));
1818	/* Attach debug hook */
1819	if (strcmp (name, NG_CP_HOOK_DEBUG) == 0) {
1820		NG_HOOK_SET_PRIVATE (hook, NULL);
1821		d->debug_hook = hook;
1822		return 0;
1823	}
1824
1825	/* Check for raw hook */
1826	if (strcmp (name, NG_CP_HOOK_RAW) != 0)
1827		return EINVAL;
1828
1829	NG_HOOK_SET_PRIVATE (hook, d);
1830	d->hook = hook;
1831	s = splimp ();
1832	CP_LOCK (bd);
1833	cp_up (d);
1834	CP_UNLOCK (bd);
1835	splx (s);
1836	return 0;
1837}
1838
1839static char *format_timeslots (u_long s)
1840{
1841	static char buf [100];
1842	char *p = buf;
1843	int i;
1844
1845	for (i=1; i<32; ++i)
1846		if ((s >> i) & 1) {
1847			int prev = (i > 1)  & (s >> (i-1));
1848			int next = (i < 31) & (s >> (i+1));
1849
1850			if (prev) {
1851				if (next)
1852					continue;
1853				*p++ = '-';
1854			} else if (p > buf)
1855				*p++ = ',';
1856
1857			if (i >= 10)
1858				*p++ = '0' + i / 10;
1859			*p++ = '0' + i % 10;
1860		}
1861	*p = 0;
1862	return buf;
1863}
1864
1865static int print_modems (char *s, cp_chan_t *c, int need_header)
1866{
1867	int status = cp_modem_status (c);
1868	int length = 0;
1869
1870	if (need_header)
1871		length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1872	length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1873		status & TIOCM_LE  ? "On" : "-",
1874		status & TIOCM_DTR ? "On" : "-",
1875		status & TIOCM_DSR ? "On" : "-",
1876		status & TIOCM_RTS ? "On" : "-",
1877		status & TIOCM_CTS ? "On" : "-",
1878		status & TIOCM_CD  ? "On" : "-");
1879	return length;
1880}
1881
1882static int print_stats (char *s, cp_chan_t *c, int need_header)
1883{
1884	int length = 0;
1885
1886	if (need_header)
1887		length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1888	length += sprintf (s + length, "%7ld %7ld %7ld %8lu %7ld %7ld %8lu %7ld %7ld\n",
1889		c->rintr, c->tintr, 0l, (unsigned long) c->ibytes,
1890		c->ipkts, c->overrun + c->frame + c->crc,
1891		(unsigned long) c->obytes, c->opkts, c->underrun);
1892	return length;
1893}
1894
1895static char *format_e1_status (u_char status)
1896{
1897	static char buf [80];
1898
1899	if (status & E1_NOALARM)
1900		return "Ok";
1901	buf[0] = 0;
1902	if (status & E1_LOS)     strcat (buf, ",LOS");
1903	if (status & E1_AIS)     strcat (buf, ",AIS");
1904	if (status & E1_LOF)     strcat (buf, ",LOF");
1905	if (status & E1_LOMF)    strcat (buf, ",LOMF");
1906	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
1907	if (status & E1_AIS16)   strcat (buf, ",AIS16");
1908	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
1909	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
1910	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
1911	if (buf[0] == ',')
1912		return buf+1;
1913	return "Unknown";
1914}
1915
1916static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
1917{
1918	int n, length = 0;
1919
1920	if (numerator < 1 || divider < 1) {
1921		length += sprintf (s+length, leftalign ? "/-   " : "    -");
1922		return length;
1923	}
1924	n = (int) (0.5 + 1000.0 * numerator / divider);
1925	if (n < 1000) {
1926		length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
1927		return length;
1928	}
1929	*(s + length) = leftalign ? '/' : ' ';
1930	length ++;
1931
1932	if      (n >= 1000000) n = (n+500) / 1000 * 1000;
1933	else if (n >= 100000)  n = (n+50)  / 100 * 100;
1934	else if (n >= 10000)   n = (n+5)   / 10 * 10;
1935
1936	switch (n) {
1937	case 1000:    length += printf (s+length, ".999"); return length;
1938	case 10000:   n = 9990;   break;
1939	case 100000:  n = 99900;  break;
1940	case 1000000: n = 999000; break;
1941	}
1942	if (n < 10000)	      length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
1943	else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
1944	else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
1945	else		      length += sprintf (s+length, "%d", n/1000);
1946
1947	return length;
1948}
1949
1950static int print_e1_stats (char *s, cp_chan_t *c)
1951{
1952	struct e1_counters total;
1953	u_long totsec;
1954	int length = 0;
1955
1956	totsec		= c->totsec + c->cursec;
1957	total.bpv	= c->total.bpv   + c->currnt.bpv;
1958	total.fse	= c->total.fse   + c->currnt.fse;
1959	total.crce	= c->total.crce  + c->currnt.crce;
1960	total.rcrce	= c->total.rcrce + c->currnt.rcrce;
1961	total.uas	= c->total.uas   + c->currnt.uas;
1962	total.les	= c->total.les   + c->currnt.les;
1963	total.es	= c->total.es    + c->currnt.es;
1964	total.bes	= c->total.bes   + c->currnt.bes;
1965	total.ses	= c->total.ses   + c->currnt.ses;
1966	total.oofs	= c->total.oofs  + c->currnt.oofs;
1967	total.css	= c->total.css   + c->currnt.css;
1968	total.dm	= c->total.dm    + c->currnt.dm;
1969
1970	length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
1971
1972	/* Unavailable seconds, degraded minutes */
1973	length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
1974	length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
1975
1976	/* Bipolar violations, frame sync errors */
1977	length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
1978	length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
1979
1980	/* CRC errors, remote CRC errors (E-bit) */
1981	length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
1982	length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
1983
1984	/* Errored seconds, line errored seconds */
1985	length += print_frac (s + length, 0, c->currnt.es, c->cursec);
1986	length += print_frac (s + length, 1, c->currnt.les, c->cursec);
1987
1988	/* Severely errored seconds, burst errored seconds */
1989	length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
1990	length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
1991
1992	/* Out of frame seconds, controlled slip seconds */
1993	length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
1994	length += print_frac (s + length, 1, c->currnt.css, c->cursec);
1995
1996	length += sprintf (s + length, " %s\n", format_e1_status (c->status));
1997
1998	/* Print total statistics. */
1999	length += print_frac (s + length, 0, total.uas, totsec);
2000	length += print_frac (s + length, 1, 60 * total.dm, totsec);
2001
2002	length += print_frac (s + length, 0, total.bpv, totsec);
2003	length += print_frac (s + length, 1, total.fse, totsec);
2004
2005	length += print_frac (s + length, 0, total.crce, totsec);
2006	length += print_frac (s + length, 1, total.rcrce, totsec);
2007
2008	length += print_frac (s + length, 0, total.es, totsec);
2009	length += print_frac (s + length, 1, total.les, totsec);
2010
2011	length += print_frac (s + length, 0, total.ses, totsec);
2012	length += print_frac (s + length, 1, total.bes, totsec);
2013
2014	length += print_frac (s + length, 0, total.oofs, totsec);
2015	length += print_frac (s + length, 1, total.css, totsec);
2016
2017	length += sprintf (s + length, " -- Total\n");
2018	return length;
2019}
2020
2021static int print_chan (char *s, cp_chan_t *c)
2022{
2023	drv_t *d = c->sys;
2024	bdrv_t *bd = d->board->sys;
2025	int length = 0;
2026
2027	length += sprintf (s + length, "cp%d", c->board->num * NCHAN + c->num);
2028	if (d->chan->debug)
2029		length += sprintf (s + length, " debug=%d", d->chan->debug);
2030
2031	if (c->board->mux) {
2032		length += sprintf (s + length, " cfg=C");
2033	} else {
2034		length += sprintf (s + length, " cfg=A");
2035	}
2036
2037	if (c->baud)
2038		length += sprintf (s + length, " %ld", c->baud);
2039	else
2040		length += sprintf (s + length, " extclock");
2041
2042	if (c->type == T_E1 || c->type == T_G703)
2043		switch (c->gsyn) {
2044		case GSYN_INT   : length += sprintf (s + length, " syn=int");     break;
2045		case GSYN_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2046		case GSYN_RCV0  : length += sprintf (s + length, " syn=rcv0");    break;
2047		case GSYN_RCV1  : length += sprintf (s + length, " syn=rcv1");    break;
2048		case GSYN_RCV2  : length += sprintf (s + length, " syn=rcv2");    break;
2049		case GSYN_RCV3  : length += sprintf (s + length, " syn=rcv3");    break;
2050		}
2051	if (c->type == T_SERIAL) {
2052		length += sprintf (s + length, " dpll=%s",   c->dpll   ? "on" : "off");
2053		length += sprintf (s + length, " nrzi=%s",   c->nrzi   ? "on" : "off");
2054		length += sprintf (s + length, " invclk=%s", c->invtxc ? "on" : "off");
2055	}
2056	if (c->type == T_E1)
2057		length += sprintf (s + length, " higain=%s", c->higain ? "on" : "off");
2058
2059	length += sprintf (s + length, " loop=%s", c->lloop ? "on" : "off");
2060
2061	if (c->type == T_E1)
2062		length += sprintf (s + length, " ts=%s", format_timeslots (c->ts));
2063	if (c->type == T_G703) {
2064		int lq, x;
2065
2066		x = splimp ();
2067		CP_LOCK (bd);
2068		lq = cp_get_lq (c);
2069		CP_UNLOCK (bd);
2070		splx (x);
2071		length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2072	}
2073	length += sprintf (s + length, "\n");
2074	return length;
2075}
2076
2077static int ng_cp_rcvmsg (node_p node, item_p item, hook_p lasthook)
2078{
2079	drv_t *d = NG_NODE_PRIVATE (node);
2080	struct ng_mesg *msg;
2081	struct ng_mesg *resp = NULL;
2082	int error = 0;
2083
2084	CP_DEBUG (d, ("Rcvmsg\n"));
2085	NGI_GET_MSG (item, msg);
2086	switch (msg->header.typecookie) {
2087	default:
2088		error = EINVAL;
2089		break;
2090
2091	case NGM_CP_COOKIE:
2092		printf ("Not implemented yet\n");
2093		error = EINVAL;
2094		break;
2095
2096	case NGM_GENERIC_COOKIE:
2097		switch (msg->header.cmd) {
2098		default:
2099			error = EINVAL;
2100			break;
2101
2102		case NGM_TEXT_STATUS: {
2103			char *s;
2104			int l = 0;
2105			int dl = sizeof (struct ng_mesg) + 730;
2106
2107			NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2108			if (! resp) {
2109				error = ENOMEM;
2110				break;
2111			}
2112			s = (resp)->data;
2113			if (d) {
2114			l += print_chan (s + l, d->chan);
2115			l += print_stats (s + l, d->chan, 1);
2116			l += print_modems (s + l, d->chan, 1);
2117			l += print_e1_stats (s + l, d->chan);
2118			} else
2119				l += sprintf (s + l, "Error: node not connect to channel");
2120			strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ);
2121			}
2122			break;
2123		}
2124		break;
2125	}
2126	NG_RESPOND_MSG (error, node, item, resp);
2127	NG_FREE_MSG (msg);
2128	return error;
2129}
2130
2131static int ng_cp_rcvdata (hook_p hook, item_p item)
2132{
2133	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2134	struct mbuf *m;
2135	struct ng_tag_prio *ptag;
2136	bdrv_t *bd = d->board->sys;
2137	struct ifqueue *q;
2138	int s;
2139
2140	CP_DEBUG2 (d, ("Rcvdata\n"));
2141	NGI_GET_M (item, m);
2142	NG_FREE_ITEM (item);
2143	if (! NG_HOOK_PRIVATE (hook) || ! d) {
2144		NG_FREE_M (m);
2145		return ENETDOWN;
2146	}
2147
2148	/* Check for high priority data */
2149	if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2150	    NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2151		q = &d->hi_queue;
2152	else
2153		q = &d->queue;
2154
2155	s = splimp ();
2156	CP_LOCK (bd);
2157	IF_LOCK (q);
2158	if (_IF_QFULL (q)) {
2159		_IF_DROP (q);
2160		IF_UNLOCK (q);
2161		CP_UNLOCK (bd);
2162		splx (s);
2163		NG_FREE_M (m);
2164		return ENOBUFS;
2165	}
2166	_IF_ENQUEUE (q, m);
2167	IF_UNLOCK (q);
2168	cp_start (d);
2169	CP_UNLOCK (bd);
2170	splx (s);
2171	return 0;
2172}
2173
2174static int ng_cp_rmnode (node_p node)
2175{
2176	drv_t *d = NG_NODE_PRIVATE (node);
2177
2178	CP_DEBUG (d, ("Rmnode\n"));
2179	if (d && d->running) {
2180		bdrv_t *bd = d->board->sys;
2181		int s = splimp ();
2182		CP_LOCK (bd);
2183		cp_down (d);
2184		CP_UNLOCK (bd);
2185		splx (s);
2186	}
2187#ifdef	KLD_MODULE
2188	if (node->nd_flags & NGF_REALLY_DIE) {
2189		NG_NODE_SET_PRIVATE (node, NULL);
2190		NG_NODE_UNREF (node);
2191	}
2192	NG_NODE_REVIVE(node);		/* Persistant node */
2193#endif
2194	return 0;
2195}
2196
2197static int ng_cp_connect (hook_p hook)
2198{
2199	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2200
2201	if (d) {
2202		CP_DEBUG (d, ("Connect\n"));
2203		callout_reset (&d->timeout_handle, hz, cp_watchdog_timer, d);
2204	}
2205
2206	return 0;
2207}
2208
2209static int ng_cp_disconnect (hook_p hook)
2210{
2211	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2212
2213	if (d) {
2214		CP_DEBUG (d, ("Disconnect\n"));
2215		if (NG_HOOK_PRIVATE (hook))
2216		{
2217			bdrv_t *bd = d->board->sys;
2218			int s = splimp ();
2219			CP_LOCK (bd);
2220			cp_down (d);
2221			CP_UNLOCK (bd);
2222			splx (s);
2223		}
2224		/* If we were wait it than it reasserted now, just stop it. */
2225		if (!callout_drain (&d->timeout_handle))
2226			callout_stop (&d->timeout_handle);
2227	}
2228	return 0;
2229}
2230#endif
2231
2232static int cp_modevent (module_t mod, int type, void *unused)
2233{
2234	static int load_count = 0;
2235
2236	switch (type) {
2237	case MOD_LOAD:
2238#ifdef NETGRAPH
2239		if (ng_newtype (&typestruct))
2240			printf ("Failed to register ng_cp\n");
2241#endif
2242		++load_count;
2243		callout_init (&timeout_handle, 1);
2244		callout_reset (&timeout_handle, hz*5, cp_timeout, 0);
2245		break;
2246	case MOD_UNLOAD:
2247		if (load_count == 1) {
2248			printf ("Removing device entry for Tau-PCI\n");
2249#ifdef NETGRAPH
2250			ng_rmtype (&typestruct);
2251#endif
2252		}
2253		/* If we were wait it than it reasserted now, just stop it.
2254		 * Actually we shouldn't get this condition. But code could be
2255		 * changed in the future, so just be a litle paranoid.
2256		 */
2257		if (!callout_drain (&timeout_handle))
2258			callout_stop (&timeout_handle);
2259		--load_count;
2260		break;
2261	case MOD_SHUTDOWN:
2262		break;
2263	}
2264	return 0;
2265}
2266
2267#ifdef NETGRAPH
2268static struct ng_type typestruct = {
2269	.version	= NG_ABI_VERSION,
2270	.name		= NG_CP_NODE_TYPE,
2271	.constructor	= ng_cp_constructor,
2272	.rcvmsg		= ng_cp_rcvmsg,
2273	.shutdown	= ng_cp_rmnode,
2274	.newhook	= ng_cp_newhook,
2275	.connect	= ng_cp_connect,
2276	.rcvdata	= ng_cp_rcvdata,
2277	.disconnect	= ng_cp_disconnect,
2278};
2279#endif /*NETGRAPH*/
2280
2281#ifdef NETGRAPH
2282MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2283#else
2284MODULE_DEPEND (cp, sppp, 1, 1, 1);
2285#endif
2286DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL);
2287MODULE_VERSION (cp, 1);
2288