if_ct.c revision 256219
12088Ssos/*-
25536Ssos * Cronyx-Tau adapter driver for FreeBSD.
32088Ssos * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
42088Ssos * and asynchronous channels with full modem control.
52088Ssos * Keepalive protocol implemented in both Cisco and PPP modes.
62088Ssos *
72088Ssos * Copyright (C) 1994-2002 Cronyx Engineering.
82088Ssos * Author: Serge Vakulenko, <vak@cronyx.ru>
95994Ssos *
105994Ssos * Copyright (C) 1999-2004 Cronyx Engineering.
112088Ssos * Author: Roman Kurakin, <rik@cronyx.ru>
122088Ssos *
132088Ssos * This software is distributed with NO WARRANTIES, not even the implied
142088Ssos * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
152088Ssos *
162088Ssos * Authors grant any other persons or organisations a permission to use,
172088Ssos * modify and redistribute this software in source and binary forms,
182088Ssos * as long as this message is kept with the software, all derivative
192088Ssos * works or modified versions.
202088Ssos *
212088Ssos * Cronyx Id: if_ct.c,v 1.1.2.31 2004/06/23 17:09:13 rik Exp $
222088Ssos */
232088Ssos
242088Ssos#include <sys/cdefs.h>
252088Ssos__FBSDID("$FreeBSD: stable/9/sys/dev/ctau/if_ct.c 256219 2013-10-09 19:04:48Z mav $");
262088Ssos
272088Ssos#include <sys/param.h>
282088Ssos#include <sys/proc.h>
2929603Scharnier#include <sys/systm.h>
3029603Scharnier#include <sys/kernel.h>
3150479Speter#include <sys/module.h>
3229603Scharnier#include <sys/mbuf.h>
3329603Scharnier#include <sys/sockio.h>
342088Ssos#include <sys/malloc.h>
3529603Scharnier#include <sys/priv.h>
362088Ssos#include <sys/socket.h>
3729603Scharnier#include <sys/sysctl.h>
383864Sswallace#include <sys/conf.h>
3929603Scharnier#include <sys/errno.h>
4042505Syokota#include <sys/tty.h>
4166834Sphk#include <sys/bus.h>
4266834Sphk#include <machine/bus.h>
432088Ssos#include <sys/rman.h>
442088Ssos#include <isa/isavar.h>
452088Ssos#include <sys/interrupt.h>
4676643Simp#include <vm/vm.h>
4776643Simp#include <vm/pmap.h>
4876643Simp#include <net/if.h>
4976643Simp#include <machine/cpufunc.h>
5076643Simp#include <machine/cserial.h>
5176643Simp#include <machine/resource.h>
5276643Simp#include <dev/cx/machdep.h>
5376643Simp#include <dev/ctau/ctddk.h>
542088Ssos#include <dev/cx/cronyxfw.h>
558857Srgrimes#include "opt_ng_cronyx.h"
562088Ssos#ifdef NETGRAPH_CRONYX
572088Ssos#   include "opt_netgraph.h"
5838139Syokota#   include <netgraph/ng_message.h>
592088Ssos#   include <netgraph/netgraph.h>
602088Ssos#   include <dev/ctau/ng_ct.h>
6132316Syokota#else
6232316Syokota#   include <net/if_types.h>
6332316Syokota#   include <net/if_sppp.h>
6432316Syokota#   define PP_CISCO IFF_LINK2
6532316Syokota#   include <net/bpf.h>
6632316Syokota#endif
6732316Syokota
6832316Syokota#define NCTAU 1
6932316Syokota
7032316Syokota/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
7132316Syokota#ifndef PP_FR
7232316Syokota#define PP_FR 0
735994Ssos#endif
745994Ssos
755994Ssos#define CT_DEBUG(d,s)	({if (d->chan->debug) {\
765994Ssos				printf ("%s: ", d->name); printf s;}})
775994Ssos#define CT_DEBUG2(d,s)	({if (d->chan->debug>1) {\
785994Ssos				printf ("%s: ", d->name); printf s;}})
795994Ssos
805994Ssos#define CT_LOCK_NAME	"ctX"
815994Ssos
825994Ssos#define CT_LOCK(_bd)		mtx_lock (&(_bd)->ct_mtx)
835994Ssos#define CT_UNLOCK(_bd)		mtx_unlock (&(_bd)->ct_mtx)
845994Ssos#define CT_LOCK_ASSERT(_bd)	mtx_assert (&(_bd)->ct_mtx, MA_OWNED)
859202Srgrimes
865994Ssosstatic void ct_identify		__P((driver_t *, device_t));
875994Ssosstatic int ct_probe		__P((device_t));
885994Ssosstatic int ct_attach		__P((device_t));
899202Srgrimesstatic int ct_detach		__P((device_t));
905994Ssos
915994Ssosstatic device_method_t ct_isa_methods [] = {
925994Ssos	DEVMETHOD(device_identify,	ct_identify),
935994Ssos	DEVMETHOD(device_probe,		ct_probe),
945994Ssos	DEVMETHOD(device_attach,	ct_attach),
955994Ssos	DEVMETHOD(device_detach,	ct_detach),
965994Ssos	{0, 0}
975994Ssos};
982088Ssos
992088Ssostypedef struct _ct_dma_mem_t {
10046761Syokota	unsigned long	phys;
10146761Syokota	void		*virt;
10246761Syokota	size_t		size;
10346761Syokota	bus_dma_tag_t	dmat;
10446761Syokota	bus_dmamap_t	mapp;
10546761Syokota} ct_dma_mem_t;
10646761Syokota
1072088Ssostypedef struct _drv_t {
1086046Ssos	char name [8];
1092088Ssos	ct_chan_t *chan;
11032316Syokota	ct_board_t *board;
1112088Ssos	struct _bdrv_t *bd;
11229603Scharnier	ct_dma_mem_t dmamem;
1132088Ssos	int running;
1142088Ssos#ifdef NETGRAPH
1152088Ssos	char	nodename [NG_NODESIZ];
1162088Ssos	hook_p	hook;
1172088Ssos	hook_p	debug_hook;
1182088Ssos	node_p	node;
11929603Scharnier	struct	ifqueue queue;
1202088Ssos	struct	ifqueue hi_queue;
1212088Ssos#else
1222088Ssos	struct	ifqueue queue;
1232088Ssos	struct	ifnet *ifp;
1242088Ssos#endif
1252088Ssos	short	timeout;
1262088Ssos	struct	callout timeout_handle;
1272088Ssos	struct	cdev *devt;
1285536Ssos} drv_t;
1295536Ssos
1305536Ssostypedef struct _bdrv_t {
1312088Ssos	ct_board_t	*board;
1322088Ssos	struct resource	*base_res;
1332088Ssos	struct resource	*drq_res;
1342088Ssos	struct resource	*irq_res;
1352088Ssos	int		base_rid;
1362088Ssos	int		drq_rid;
1372088Ssos	int		irq_rid;
1382088Ssos	void		*intrhand;
1392088Ssos	drv_t		channel [NCHAN];
1402088Ssos	struct mtx	ct_mtx;
1412088Ssos} bdrv_t;
1422088Ssos
1432088Ssosstatic driver_t ct_isa_driver = {
1442088Ssos	"ct",
1452088Ssos	ct_isa_methods,
1462088Ssos	sizeof (bdrv_t),
1472088Ssos};
1482088Ssos
1492088Ssosstatic devclass_t ct_devclass;
1502088Ssos
1512088Ssosstatic void ct_receive (ct_chan_t *c, char *data, int len);
1522088Ssosstatic void ct_transmit (ct_chan_t *c, void *attachment, int len);
1532088Ssosstatic void ct_error (ct_chan_t *c, int data);
15432316Syokotastatic void ct_up (drv_t *d);
1552088Ssosstatic void ct_start (drv_t *d);
1562088Ssosstatic void ct_down (drv_t *d);
1572088Ssosstatic void ct_watchdog (drv_t *d);
1582088Ssosstatic void ct_watchdog_timer (void *arg);
1592088Ssos#ifdef NETGRAPH
1602088Ssosextern struct ng_type typestruct;
1612088Ssos#else
1622088Ssosstatic void ct_ifstart (struct ifnet *ifp);
1632088Ssosstatic void ct_tlf (struct sppp *sp);
1642088Ssosstatic void ct_tls (struct sppp *sp);
1652088Ssosstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
1662088Ssosstatic void ct_initialize (void *softc);
1672088Ssos#endif
1682088Ssos
1692088Ssosstatic ct_board_t *adapter [NCTAU];
1702088Ssosstatic drv_t *channel [NCTAU*NCHAN];
1712088Ssosstatic struct callout led_timo [NCTAU];
1722088Ssosstatic struct callout timeout_handle;
1732088Ssos
1742088Ssosstatic int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td);
17548105Syokotastatic int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td);
17648105Syokotastatic int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td);
1772088Ssosstatic struct cdevsw ct_cdevsw = {
1782088Ssos	.d_version  = D_VERSION,
1792088Ssos	.d_open     = ct_open,
1802088Ssos	.d_close    = ct_close,
1812088Ssos	.d_ioctl    = ct_ioctl,
1822088Ssos	.d_name     = "ct",
1832088Ssos};
1842088Ssos
1852088Ssos/*
1862088Ssos * Print the mbuf chain, for debug purposes only.
1872088Ssos */
1882088Ssosstatic void printmbuf (struct mbuf *m)
1892088Ssos{
1902088Ssos	printf ("mbuf:");
1915994Ssos	for (; m; m=m->m_next) {
1925994Ssos		if (m->m_flags & M_PKTHDR)
19338053Syokota			printf (" HDR %d:", m->m_pkthdr.len);
19438053Syokota		if (m->m_flags & M_EXT)
19554380Syokota			printf (" EXT:");
19654380Syokota		printf (" %d", m->m_len);
19754380Syokota	}
19854380Syokota	printf ("\n");
19954380Syokota}
20054380Syokota
20154380Syokota/*
20254380Syokota * Make an mbuf from data.
20354380Syokota */
20454380Syokotastatic struct mbuf *makembuf (void *buf, u_int len)
20554380Syokota{
20654380Syokota	struct mbuf *m;
20754380Syokota
20854380Syokota	MGETHDR (m, M_NOWAIT, MT_DATA);
20965759Sdwmalone	if (! m)
21065759Sdwmalone		return 0;
21165759Sdwmalone	MCLGET (m, M_NOWAIT);
21265759Sdwmalone	if (! (m->m_flags & M_EXT)) {
21374118Sache		m_freem (m);
21474118Sache		return 0;
21532316Syokota	}
21632316Syokota	m->m_pkthdr.len = m->m_len = len;
21732316Syokota	bcopy (buf, mtod (m, caddr_t), len);
21832316Syokota	return m;
2192088Ssos}
2202088Ssos
2212088Ssosstatic void ct_timeout (void *arg)
2222088Ssos{
2232088Ssos	drv_t *d;
2242088Ssos	int s, i, k;
2252088Ssos
2262088Ssos	for (i = 0; i < NCTAU; ++i) {
2272088Ssos		if (adapter[i] == NULL)
2282088Ssos			continue;
2292088Ssos		for (k = 0; k < NCHAN; k++) {
2302088Ssos			d = channel[i * NCHAN + k];
2312088Ssos			if (! d)
2322088Ssos				continue;
2332088Ssos			if (d->chan->mode != M_G703)
2342088Ssos				continue;
2352088Ssos			s = splimp ();
2362088Ssos			CT_LOCK ((bdrv_t *)d->bd);
2372088Ssos			ct_g703_timer (d->chan);
2382088Ssos			CT_UNLOCK ((bdrv_t *)d->bd);
23932316Syokota			splx (s);
2402088Ssos		}
24132316Syokota	}
2422088Ssos
2432088Ssos	callout_reset (&timeout_handle, hz, ct_timeout, 0);
2442088Ssos}
24532316Syokota
24632316Syokotastatic void ct_led_off (void *arg)
24732316Syokota{
24832316Syokota	ct_board_t *b = arg;
24932316Syokota	bdrv_t *bd = ((drv_t *)b->chan->sys)->bd;
25032316Syokota	int s = splimp ();
25132316Syokota
25232316Syokota	CT_LOCK (bd);
25332316Syokota	ct_led (b, 0);
25432316Syokota	CT_UNLOCK (bd);
25532316Syokota	splx (s);
25632316Syokota}
25732316Syokota
25832316Syokota/*
25932316Syokota * Activate interrupt handler from DDK.
26032316Syokota */
26132316Syokotastatic void ct_intr (void *arg)
26232316Syokota{
26332316Syokota	bdrv_t *bd = arg;
2642088Ssos	ct_board_t *b = bd->board;
26532316Syokota#ifndef NETGRAPH
26632316Syokota	int i;
26732316Syokota#endif
26832316Syokota	int s = splimp ();
26932316Syokota
27032316Syokota	CT_LOCK (bd);
27132316Syokota	/* Turn LED on. */
27232316Syokota	ct_led (b, 1);
27332316Syokota
27432316Syokota	ct_int_handler (b);
27532316Syokota
27632316Syokota	/* Turn LED off 50 msec later. */
2772088Ssos	callout_reset (&led_timo[b->num], hz/20, ct_led_off, b);
2782088Ssos	CT_UNLOCK (bd);
2792088Ssos	splx (s);
2802088Ssos
2812088Ssos#ifndef NETGRAPH
2822088Ssos	/* Pass packets in a lock-free state */
2832088Ssos	for (i = 0; i < NCHAN && b->chan[i].type; i++) {
2842088Ssos		drv_t *d = b->chan[i].sys;
2852088Ssos		struct mbuf *m;
2862088Ssos		if (!d || !d->running)
2872088Ssos			continue;
2882088Ssos		while (_IF_QLEN(&d->queue)) {
2892088Ssos			IF_DEQUEUE (&d->queue,m);
2902088Ssos			if (!m)
29132316Syokota				continue;
2922088Ssos			sppp_input (d->ifp, m);
2932088Ssos		}
29432316Syokota	}
29532316Syokota#endif
2962088Ssos}
2972088Ssos
29832316Syokotastatic int probe_irq (ct_board_t *b, int irq)
29932316Syokota{
30032316Syokota	int mask, busy, cnt;
30132316Syokota
30232316Syokota	/* Clear pending irq, if any. */
30332316Syokota	ct_probe_irq (b, -irq);
3042088Ssos	DELAY (100);
30532316Syokota	for (cnt=0; cnt<5; ++cnt) {
30632316Syokota		/* Get the mask of pending irqs, assuming they are busy.
30732316Syokota		 * Activate the adapter on given irq. */
30832316Syokota		busy = ct_probe_irq (b, irq);
30932316Syokota		DELAY (1000);
31032316Syokota
31132316Syokota		/* Get the mask of active irqs.
31232316Syokota		 * Deactivate our irq. */
31332316Syokota		mask = ct_probe_irq (b, -irq);
31432316Syokota		DELAY (100);
31532316Syokota		if ((mask & ~busy) == 1 << irq) {
31632316Syokota			ct_probe_irq (b, 0);
31732316Syokota			/* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
31832316Syokota				b->num, irq, mask, busy); */
31932316Syokota			return 1;
32032316Syokota		}
32132316Syokota	}
32232316Syokota	/* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
32332316Syokota		b->num, irq, mask, busy); */
32432316Syokota	ct_probe_irq (b, 0);
32532316Syokota	return 0;
32632316Syokota}
32732316Syokota
32832316Syokotastatic	short porttab [] = {
32932316Syokota		0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
33032316Syokota		0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
33132316Syokota	};
33232316Syokotastatic	char dmatab [] = { 7, 6, 5, 0 };
33332316Syokotastatic	char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
33432316Syokota
33532316Syokotastatic int ct_is_free_res (device_t dev, int rid, int type, u_long start,
33632316Syokota	u_long end, u_long count)
33732316Syokota{
33832316Syokota	struct resource *res;
33932316Syokota
34032316Syokota	if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
34132316Syokota	    RF_ALLOCATED)))
34232316Syokota		return 0;
34332316Syokota
34432316Syokota	bus_release_resource (dev, type, rid, res);
34532316Syokota
34632316Syokota	return 1;
34732316Syokota}
34832316Syokota
34932316Syokotastatic void ct_identify (driver_t *driver, device_t dev)
35032316Syokota{
35132316Syokota	u_long iobase, rescount;
35232316Syokota	int devcount;
35332316Syokota	device_t *devices;
35432316Syokota	device_t child;
35532316Syokota	devclass_t my_devclass;
35632316Syokota	int i, k;
35732316Syokota
35832316Syokota	if ((my_devclass = devclass_find ("ct")) == NULL)
35929603Scharnier		return;
3602088Ssos
3612088Ssos	devclass_get_devices (my_devclass, &devices, &devcount);
3622088Ssos
3632088Ssos	if (devcount == 0) {
3642088Ssos		/* We should find all devices by our self. We could alter other
3652088Ssos		 * devices, but we don't have a choise
3668857Srgrimes		 */
3672088Ssos		for (i = 0; (iobase = porttab [i]) != 0; i++) {
3682088Ssos			if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
3692088Ssos			    iobase, iobase + NPORT, NPORT))
3702088Ssos				continue;
3712088Ssos			if (ct_probe_board (iobase, -1, -1) == 0)
3722088Ssos				continue;
3732088Ssos
3742088Ssos			devcount++;
3752088Ssos			child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct",
3762088Ssos			    -1);
3772088Ssos
3782088Ssos			if (child == NULL)
3792088Ssos				return;
3802088Ssos
3812088Ssos			device_set_desc_copy (child, "Cronyx Tau-ISA");
3822088Ssos			device_set_driver (child, driver);
3832088Ssos			bus_set_resource (child, SYS_RES_IOPORT, 0,
3842088Ssos			    iobase, NPORT);
3852088Ssos
3862088Ssos			if (devcount >= NCTAU)
3872088Ssos				break;
3882088Ssos		}
3892088Ssos	} else {
3902088Ssos		static	short porttab [] = {
3912088Ssos			0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
3922088Ssos			0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
3932088Ssos		};
3942088Ssos		/* Lets check user choise.
39548105Syokota		 */
39648105Syokota		for (k = 0; k < devcount; k++) {
39748105Syokota			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
3982088Ssos			    &iobase, &rescount) != 0)
3992088Ssos				continue;
4002088Ssos
4012088Ssos			for (i = 0; porttab [i] != 0; i++) {
4022088Ssos				if (porttab [i] != iobase)
4032088Ssos					continue;
4042088Ssos
4052088Ssos				if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
4062088Ssos				    iobase, iobase + NPORT, NPORT))
4072088Ssos					continue;
4082088Ssos
4092088Ssos				if (ct_probe_board (iobase, -1, -1) == 0)
4102088Ssos					continue;
4112088Ssos				porttab [i] = -1;
4122088Ssos				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
4132088Ssos				break;
4142088Ssos			}
4152088Ssos			if (porttab [i] == 0) {
4162088Ssos				device_delete_child (
4172088Ssos				    device_get_parent (devices[k]),
4182088Ssos				    devices [k]);
41932316Syokota				devices[k] = 0;
42032316Syokota				continue;
42132316Syokota			}
42238053Syokota		}
42338053Syokota		for (k = 0; k < devcount; k++) {
42438053Syokota			if (devices[k] == 0)
42554380Syokota				continue;
42654380Syokota			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
42754380Syokota			    &iobase, &rescount) == 0)
42854380Syokota				continue;
42954380Syokota			for (i = 0; (iobase = porttab [i]) != 0; i++) {
43054380Syokota				if (porttab [i] == -1)
43154380Syokota					continue;
43254380Syokota				if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
43354380Syokota				    iobase, iobase + NPORT, NPORT))
43454380Syokota					continue;
43554380Syokota				if (ct_probe_board (iobase, -1, -1) == 0)
43654380Syokota					continue;
43754380Syokota
43854380Syokota				bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
43954380Syokota				    iobase, NPORT);
44054380Syokota				porttab [i] = -1;
44154380Syokota				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
44254380Syokota				break;
44354380Syokota			}
44454380Syokota			if (porttab [i] == 0) {
44554380Syokota				device_delete_child (
44665759Sdwmalone				    device_get_parent (devices[k]),
44765759Sdwmalone				    devices [k]);
44865759Sdwmalone			}
44965759Sdwmalone		}
45065759Sdwmalone		free (devices, M_TEMP);
45165759Sdwmalone	}
45274118Sache
45374118Sache	return;
45474118Sache}
4552088Ssos
4562088Ssosstatic int ct_probe (device_t dev)
4578857Srgrimes{
4582088Ssos	int unit = device_get_unit (dev);
4598857Srgrimes	u_long iobase, rescount;
4602088Ssos
46132316Syokota	if (!device_get_desc (dev) ||
46232316Syokota	    strcmp (device_get_desc (dev), "Cronyx Tau-ISA"))
4632088Ssos		return ENXIO;
4648857Srgrimes
4652088Ssos/*	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/
46632316Syokota	if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
4672088Ssos		printf ("ct%d: Couldn't get IOPORT\n", unit);
4682088Ssos		return ENXIO;
4692088Ssos	}
4708857Srgrimes
4712088Ssos	if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
4728857Srgrimes	    iobase, iobase + NPORT, NPORT)) {
4739202Srgrimes		printf ("ct%d: Resource IOPORT isn't free\n", unit);
4748857Srgrimes		return ENXIO;
4752088Ssos	}
4768857Srgrimes
4772088Ssos	if (!ct_probe_board (iobase, -1, -1)) {
4788857Srgrimes		printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
4792088Ssos		return ENXIO;
4802088Ssos	}
4812088Ssos
4822088Ssos	return 0;
4832088Ssos}
4842088Ssos
48542505Syokotastatic void
4862088Ssosct_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
48729603Scharnier{
4882088Ssos	unsigned long *addr;
4892088Ssos
4902088Ssos	if (error)
4912088Ssos		return;
4922088Ssos
4932088Ssos	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
4942088Ssos	addr = arg;
4952088Ssos	*addr = segs->ds_addr;
4962088Ssos}
4972088Ssos
4982088Ssosstatic int
4992088Ssosct_bus_dma_mem_alloc (int bnum, int cnum, ct_dma_mem_t *dmem)
5008857Srgrimes{
5012088Ssos	int error;
5022088Ssos
5032088Ssos	error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT,
5042088Ssos		BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
5052088Ssos		dmem->size, 0, NULL, NULL, &dmem->dmat);
5062088Ssos	if (error) {
5072088Ssos		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
5082088Ssos		else		printf ("ct%d: ", bnum);
5092088Ssos		printf ("couldn't allocate tag for dma memory\n");
5102088Ssos 		return 0;
5112088Ssos	}
5122088Ssos	error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
5132088Ssos		BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
5146046Ssos	if (error) {
5156046Ssos		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
5166046Ssos		else		printf ("ct%d: ", bnum);
5178857Srgrimes		printf ("couldn't allocate mem for dma memory\n");
5182088Ssos		bus_dma_tag_destroy (dmem->dmat);
5192088Ssos 		return 0;
52032316Syokota	}
52132316Syokota	error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
52232316Syokota		dmem->size, ct_bus_dmamap_addr, &dmem->phys, 0);
52332316Syokota	if (error) {
52432316Syokota		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
5252088Ssos		else		printf ("ct%d: ", bnum);
52632316Syokota		printf ("couldn't load mem map for dma memory\n");
52732316Syokota		bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
52832316Syokota		bus_dma_tag_destroy (dmem->dmat);
52932316Syokota 		return 0;
53032316Syokota	}
53132316Syokota	return 1;
53232316Syokota}
53332316Syokota
53432316Syokotastatic void
53532316Syokotact_bus_dma_mem_free (ct_dma_mem_t *dmem)
53632316Syokota{
53732316Syokota	bus_dmamap_unload (dmem->dmat, dmem->mapp);
53832316Syokota	bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
53932316Syokota	bus_dma_tag_destroy (dmem->dmat);
54032316Syokota}
54132316Syokota
54232316Syokota/*
54332316Syokota * The adapter is present, initialize the driver structures.
54432316Syokota */
54532316Syokotastatic int ct_attach (device_t dev)
54632316Syokota{
54732316Syokota	bdrv_t *bd = device_get_softc (dev);
54832316Syokota	u_long iobase, drq, irq, rescount;
54932316Syokota	int unit = device_get_unit (dev);
55032316Syokota	char *ct_ln = CT_LOCK_NAME;
55132316Syokota	ct_board_t *b;
55232316Syokota	ct_chan_t *c;
55332316Syokota	drv_t *d;
55432316Syokota	int i;
55532316Syokota	int s;
55632316Syokota
55732316Syokota	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));
55832316Syokota
55932316Syokota	bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
56032316Syokota	bd->base_rid = 0;
5612088Ssos	bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
56232316Syokota		iobase, iobase + NPORT, NPORT, RF_ACTIVE);
56332316Syokota	if (! bd->base_res) {
56432316Syokota		printf ("ct%d: cannot alloc base address\n", unit);
56532316Syokota		return ENXIO;
56632316Syokota	}
56732316Syokota
56832316Syokota	if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
56932316Syokota		for (i = 0; (drq = dmatab [i]) != 0; i++) {
57032316Syokota			if (!ct_is_free_res (dev, 0, SYS_RES_DRQ,
57132316Syokota			    drq, drq + 1, 1))
57232316Syokota				continue;
57332316Syokota			bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
57432316Syokota			break;
57532316Syokota		}
57632316Syokota
57732316Syokota		if (dmatab[i] == 0) {
57832316Syokota			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
57932316Syokota				bd->base_res);
58032316Syokota			printf ("ct%d: Couldn't get DRQ\n", unit);
58132316Syokota			return ENXIO;
58232316Syokota		}
58332316Syokota	}
58432316Syokota
58532316Syokota	bd->drq_rid = 0;
58632316Syokota	bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
58732316Syokota		drq, drq + 1, 1, RF_ACTIVE);
58832316Syokota	if (! bd->drq_res) {
58932316Syokota		printf ("ct%d: cannot allocate drq\n", unit);
59032316Syokota		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
59132316Syokota			bd->base_res);
59232316Syokota		return ENXIO;
59332316Syokota	}
59432316Syokota
59532316Syokota	if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
59632316Syokota		for (i = 0; (irq = irqtab [i]) != 0; i++) {
59748105Syokota			if (!ct_is_free_res (dev, 0, SYS_RES_IRQ,
59848105Syokota			    irq, irq + 1, 1))
59948105Syokota				continue;
60032316Syokota			bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
60132316Syokota			break;
60232316Syokota		}
60332316Syokota
60432316Syokota		if (irqtab[i] == 0) {
60532316Syokota			bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
60632316Syokota				bd->drq_res);
60732316Syokota			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
60832316Syokota				bd->base_res);
60932316Syokota			printf ("ct%d: Couldn't get IRQ\n", unit);
61032316Syokota			return ENXIO;
61132316Syokota		}
61232316Syokota	}
61332316Syokota
61432316Syokota	bd->irq_rid = 0;
61532316Syokota	bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
61632316Syokota		irq, irq + 1, 1, RF_ACTIVE);
61732316Syokota	if (! bd->irq_res) {
61832316Syokota		printf ("ct%d: Couldn't allocate irq\n", unit);
61932316Syokota		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
62032316Syokota			bd->drq_res);
62132316Syokota		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
62232316Syokota			bd->base_res);
62332316Syokota		return ENXIO;
62438053Syokota	}
62538053Syokota
62638053Syokota	b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
62754380Syokota	if (!b) {
62854380Syokota		printf ("ct:%d: Couldn't allocate memory\n", unit);
62954380Syokota		return (ENXIO);
63054380Syokota	}
63154380Syokota	adapter[unit] = b;
63254380Syokota	bzero (b, sizeof(ct_board_t));
63354380Syokota
63454380Syokota	if (! ct_open_board (b, unit, iobase, irq, drq)) {
63554380Syokota		printf ("ct%d: error loading firmware\n", unit);
63654380Syokota		free (b, M_DEVBUF);
63754380Syokota		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
63854380Syokota			bd->irq_res);
63954380Syokota		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
64054380Syokota			bd->drq_res);
64154380Syokota		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
64254380Syokota			bd->base_res);
64354380Syokota 		return ENXIO;
64454380Syokota	}
64554380Syokota
64654380Syokota	bd->board = b;
64754380Syokota
64865759Sdwmalone	ct_ln[2] = '0' + unit;
64965759Sdwmalone	mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
65065759Sdwmalone	if (! probe_irq (b, irq)) {
65165759Sdwmalone		printf ("ct%d: irq %ld not functional\n", unit, irq);
65265759Sdwmalone		bd->board = 0;
65365759Sdwmalone		adapter [unit] = 0;
65474118Sache		free (b, M_DEVBUF);
65574118Sache		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
65674118Sache			bd->irq_res);
65732316Syokota		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
65832316Syokota			bd->drq_res);
65932316Syokota		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
66032316Syokota			bd->base_res);
66132486Syokota		mtx_destroy (&bd->ct_mtx);
66232316Syokota 		return ENXIO;
66332316Syokota	}
66432316Syokota
66532316Syokota	callout_init (&led_timo[unit], CALLOUT_MPSAFE);
66632316Syokota	s = splimp ();
66732316Syokota	if (bus_setup_intr (dev, bd->irq_res,
66832316Syokota			   INTR_TYPE_NET|INTR_MPSAFE,
66932316Syokota			   NULL, ct_intr, bd, &bd->intrhand)) {
67032316Syokota		printf ("ct%d: Can't setup irq %ld\n", unit, irq);
67132316Syokota		bd->board = 0;
67232316Syokota		adapter [unit] = 0;
67332316Syokota		free (b, M_DEVBUF);
67432316Syokota		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
67532316Syokota			bd->irq_res);
67632316Syokota		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
67732316Syokota			bd->drq_res);
67832316Syokota		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
67932316Syokota			bd->base_res);
68032316Syokota		mtx_destroy (&bd->ct_mtx);
68132316Syokota		splx (s);
68232316Syokota 		return ENXIO;
68332316Syokota	}
68432486Syokota
68532316Syokota	CT_LOCK (bd);
68632316Syokota	ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc);
68732486Syokota	ct_setup_board (b, 0, 0, 0);
68832486Syokota	CT_UNLOCK (bd);
68932486Syokota
69032316Syokota	printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name,
69132316Syokota		b->osc == 20000000 ? "20" : "16.384");
69232316Syokota
69332486Syokota	for (c = b->chan; c < b->chan + NCHAN; ++c) {
69432316Syokota		d = &bd->channel[c->num];
69532316Syokota		d->dmamem.size = sizeof(ct_buf_t);
69632316Syokota		if (! ct_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
69732316Syokota			continue;
69832316Syokota		d->board = b;
69932316Syokota		d->chan = c;
70032486Syokota		d->bd = bd;
70132316Syokota		c->sys = d;
70232316Syokota		channel [b->num*NCHAN + c->num] = d;
70332316Syokota		sprintf (d->name, "ct%d.%d", b->num, c->num);
70432486Syokota		callout_init (&d->timeout_handle, CALLOUT_MPSAFE);
70532316Syokota
70632316Syokota#ifdef NETGRAPH
70732316Syokota		if (ng_make_node_common (&typestruct, &d->node) != 0) {
70832316Syokota			printf ("%s: cannot make common node\n", d->name);
70932316Syokota			channel [b->num*NCHAN + c->num] = 0;
71032316Syokota			c->sys = 0;
71132316Syokota			ct_bus_dma_mem_free (&d->dmamem);
71232316Syokota			continue;
71332486Syokota		}
71432316Syokota		NG_NODE_SET_PRIVATE (d->node, d);
71532486Syokota		sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE,
71632486Syokota			 c->board->num*NCHAN + c->num);
71732486Syokota		if (ng_name_node (d->node, d->nodename)) {
71832486Syokota			printf ("%s: cannot name node\n", d->nodename);
71932486Syokota			NG_NODE_UNREF (d->node);
72032316Syokota			channel [b->num*NCHAN + c->num] = 0;
72132316Syokota			c->sys = 0;
72232316Syokota			ct_bus_dma_mem_free (&d->dmamem);
72332316Syokota			continue;
72432316Syokota		}
72532316Syokota		d->queue.ifq_maxlen = ifqmaxlen;
72632316Syokota		d->hi_queue.ifq_maxlen = ifqmaxlen;
72732316Syokota		mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
72832316Syokota		mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF);
72932316Syokota#else /*NETGRAPH*/
73032316Syokota		d->ifp = if_alloc(IFT_PPP);
73132316Syokota		if (d->ifp == NULL) {
73232316Syokota			printf ("%s: cannot if_alloc common interface\n",
73332316Syokota			    d->name);
73432316Syokota			channel [b->num*NCHAN + c->num] = 0;
73532316Syokota			c->sys = 0;
73632316Syokota			ct_bus_dma_mem_free (&d->dmamem);
73732316Syokota			continue;
73832316Syokota		}
73932316Syokota		d->ifp->if_softc	= d;
74032316Syokota		if_initname (d->ifp, "ct", b->num * NCHAN + c->num);
74132316Syokota		d->ifp->if_mtu		= PP_MTU;
74232316Syokota		d->ifp->if_flags	= IFF_POINTOPOINT | IFF_MULTICAST;
74332316Syokota		d->ifp->if_ioctl	= ct_sioctl;
74432316Syokota		d->ifp->if_start	= ct_ifstart;
74532316Syokota		d->ifp->if_init		= ct_initialize;
74632316Syokota		d->queue.ifq_maxlen	= NBUF;
74732316Syokota		mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
74832486Syokota		sppp_attach (d->ifp);
74932316Syokota		if_attach (d->ifp);
75032316Syokota		IFP2SP(d->ifp)->pp_tlf	= ct_tlf;
75132316Syokota		IFP2SP(d->ifp)->pp_tls	= ct_tls;
75219569Sjoerg		/* If BPF is in the kernel, call the attach for it.
7532088Ssos		 * Header size is 4 bytes. */
75432316Syokota		bpfattach (d->ifp, DLT_PPP, 4);
75532316Syokota#endif /*NETGRAPH*/
7562088Ssos		CT_LOCK (bd);
75776502Ssobomax		ct_start_chan (c, d->dmamem.virt, d->dmamem.phys);
75819569Sjoerg		ct_register_receive (c, &ct_receive);
75976502Ssobomax		ct_register_transmit (c, &ct_transmit);
76076502Ssobomax		ct_register_error (c, &ct_error);
7612088Ssos		CT_UNLOCK (bd);
76276569Ssobomax		d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
76376569Ssobomax				GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num);
76476569Ssobomax	}
76576502Ssobomax	splx (s);
76676643Simp
76776643Simp	return 0;
76876643Simp}
76976502Ssobomax
77076643Simpstatic int ct_detach (device_t dev)
77176502Ssobomax{
77276643Simp	bdrv_t *bd = device_get_softc (dev);
7732088Ssos	ct_board_t *b = bd->board;
77429603Scharnier	ct_chan_t *c;
7752088Ssos	int s;
7762088Ssos
77732316Syokota	KASSERT (mtx_initialized (&bd->ct_mtx), ("ct mutex not initialized"));
77832316Syokota
77932316Syokota	s = splimp ();
7802088Ssos	CT_LOCK (bd);
78132316Syokota	/* Check if the device is busy (open). */
7822088Ssos	for (c = b->chan; c < b->chan + NCHAN; ++c) {
7832088Ssos		drv_t *d = (drv_t*) c->sys;
78419569Sjoerg
78519569Sjoerg		if (!d || !d->chan->type)
78619569Sjoerg			continue;
78719569Sjoerg
78832316Syokota		if (d->running) {
78932316Syokota			CT_UNLOCK (bd);
79032316Syokota			splx (s);
79132316Syokota			return EBUSY;
79232316Syokota		}
79332316Syokota	}
79419569Sjoerg
79519569Sjoerg	/* Deactivate the timeout routine. */
79632316Syokota	callout_stop (&led_timo[b->num]);
79729603Scharnier
7982088Ssos	CT_UNLOCK (bd);
7992088Ssos
8002088Ssos	bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
80132316Syokota	bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
80232316Syokota
80332316Syokota	bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
80432316Syokota
80532316Syokota	bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
80632316Syokota
8072088Ssos	CT_LOCK (bd);
8082088Ssos	ct_close_board (b);
8092088Ssos	CT_UNLOCK (bd);
8102088Ssos
8112088Ssos	/* Detach the interfaces, free buffer memory. */
81232316Syokota	for (c = b->chan; c < b->chan + NCHAN; ++c) {
81332316Syokota		drv_t *d = (drv_t*) c->sys;
8142088Ssos
8152088Ssos		if (!d || !d->chan->type)
81632316Syokota			continue;
81729603Scharnier
81832316Syokota		callout_stop (&d->timeout_handle);
81932316Syokota#ifdef NETGRAPH
8202088Ssos		if (d->node) {
8212088Ssos			ng_rmnode_self (d->node);
8222088Ssos			NG_NODE_UNREF (d->node);
8232088Ssos			d->node = NULL;
8242088Ssos		}
8252088Ssos		mtx_destroy (&d->queue.ifq_mtx);
82632316Syokota		mtx_destroy (&d->hi_queue.ifq_mtx);
82732316Syokota#else
82832316Syokota		/* Detach from the packet filter list of interfaces. */
82932316Syokota		bpfdetach (d->ifp);
83032316Syokota
83132316Syokota		/* Detach from the sync PPP list. */
83232316Syokota		sppp_detach (d->ifp);
8332088Ssos
8342088Ssos		if_detach (d->ifp);
8352088Ssos		if_free (d->ifp);
8362088Ssos		IF_DRAIN (&d->queue);
8372088Ssos		mtx_destroy (&d->queue.ifq_mtx);
8382088Ssos#endif
8392088Ssos		destroy_dev (d->devt);
8402088Ssos	}
8412088Ssos
8422088Ssos	CT_LOCK (bd);
8432088Ssos	ct_led_off (b);
8442088Ssos	CT_UNLOCK (bd);
8452088Ssos	callout_drain (&led_timo[b->num]);
8462088Ssos	splx (s);
84729603Scharnier
8482088Ssos	for (c = b->chan; c < b->chan + NCHAN; ++c) {
8492088Ssos		drv_t *d = (drv_t*) c->sys;
8502088Ssos
8512088Ssos		if (!d || !d->chan->type)
8522088Ssos			continue;
8532088Ssos		callout_drain(&d->timeout_handle);
8542088Ssos
8552088Ssos		/* Deallocate buffers. */
8562088Ssos		ct_bus_dma_mem_free (&d->dmamem);
8572088Ssos	}
8582088Ssos	bd->board = 0;
8592088Ssos	adapter [b->num] = 0;
8602088Ssos	free (b, M_DEVBUF);
8612088Ssos
86229603Scharnier	mtx_destroy (&bd->ct_mtx);
8632088Ssos
8642088Ssos	return 0;
8652088Ssos}
8662088Ssos
86729603Scharnier#ifndef NETGRAPH
8682088Ssosstatic void ct_ifstart (struct ifnet *ifp)
8692088Ssos{
8702088Ssos	drv_t *d = ifp->if_softc;
8712088Ssos	bdrv_t *bd = d->bd;
8722088Ssos
8732088Ssos	CT_LOCK (bd);
87429603Scharnier	ct_start (d);
8752088Ssos	CT_UNLOCK (bd);
8762088Ssos}
8772088Ssos
8782088Ssosstatic void ct_tlf (struct sppp *sp)
8792088Ssos{
8802088Ssos	drv_t *d = SP2IFP(sp)->if_softc;
8815536Ssos
8822088Ssos	CT_DEBUG (d, ("ct_tlf\n"));
88338044Syokota/*	ct_set_dtr (d->chan, 0);*/
88438044Syokota/*	ct_set_rts (d->chan, 0);*/
88538044Syokota	if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
88638044Syokota		sp->pp_down (sp);
88738044Syokota}
8888857Srgrimes
88938044Syokotastatic void ct_tls (struct sppp *sp)
8905536Ssos{
89138044Syokota	drv_t *d = SP2IFP(sp)->if_softc;
89248982Syokota
89348982Syokota	CT_DEBUG (d, ("ct_tls\n"));
8942088Ssos	if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO))
8952088Ssos		sp->pp_up (sp);
8968857Srgrimes}
8975536Ssos
8982088Ssos/*
8992088Ssos * Initialization of interface.
9002088Ssos * Ii seems to be never called by upper level.
9012088Ssos */
9022088Ssosstatic void ct_initialize (void *softc)
9032088Ssos{
9042088Ssos	drv_t *d = softc;
90529603Scharnier
9062088Ssos	CT_DEBUG (d, ("ct_initialize\n"));
9072088Ssos}
90838044Syokota
90938044Syokota/*
91038044Syokota * Process an ioctl request.
9112088Ssos */
9122088Ssosstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
9135536Ssos{
91438044Syokota	drv_t *d = ifp->if_softc;
9155536Ssos	bdrv_t *bd = d->bd;
9162088Ssos	int error, s, was_up, should_be_up;
9172088Ssos
9182088Ssos	was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
9192088Ssos	error = sppp_ioctl (ifp, cmd, data);
9202088Ssos	if (error)
9212088Ssos		return error;
92244628Syokota
92339047Syokota	if (! (ifp->if_flags & IFF_DEBUG))
92439047Syokota		d->chan->debug = 0;
92546761Syokota	else
9262088Ssos		d->chan->debug = d->chan->debug_shadow;
92746761Syokota
92844628Syokota	switch (cmd) {
92946761Syokota	default:	   CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
93046761Syokota	case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
93144628Syokota	case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
93246761Syokota	case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
93346761Syokota	case SIOCSIFADDR:  CT_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
93439047Syokota	}
93546761Syokota
93646761Syokota	/* We get here only in case of SIFFLAGS or SIFADDR. */
9372088Ssos	s = splimp ();
9382088Ssos	CT_LOCK (bd);
9392088Ssos	should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
9402088Ssos	if (! was_up && should_be_up) {
9412088Ssos		/* Interface goes up -- start it. */
9422088Ssos		ct_up (d);
9432088Ssos		ct_start (d);
9442088Ssos	} else if (was_up && ! should_be_up) {
9452088Ssos		/* Interface is going down -- stop it. */
9462088Ssos		/* if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
94729603Scharnier		ct_down (d);
9482088Ssos	}
9492088Ssos	CT_UNLOCK (bd);
95046761Syokota	splx (s);
95146761Syokota	return 0;
95246761Syokota}
95346761Syokota#endif /*NETGRAPH*/
95446761Syokota
95546761Syokota/*
95646761Syokota * Stop the interface.  Called on splimp().
95746761Syokota */
9582088Ssosstatic void ct_down (drv_t *d)
9592088Ssos{
96044628Syokota	int s = splimp ();
96144628Syokota	CT_DEBUG (d, ("ct_down\n"));
96246761Syokota	ct_set_dtr (d->chan, 0);
96346761Syokota	ct_set_rts (d->chan, 0);
96446761Syokota	d->running = 0;
96546761Syokota	callout_stop (&d->timeout_handle);
9662088Ssos	splx (s);
9672088Ssos}
9682088Ssos
9696046Ssos/*
9706046Ssos * Start the interface.  Called on splimp().
9716046Ssos */
9726046Ssosstatic void ct_up (drv_t *d)
9736046Ssos{
9746046Ssos	int s = splimp ();
9756046Ssos	CT_DEBUG (d, ("ct_up\n"));
97629603Scharnier	ct_set_dtr (d->chan, 1);
9776046Ssos	ct_set_rts (d->chan, 1);
9786046Ssos	d->running = 1;
9796046Ssos	splx (s);
98029603Scharnier}
9816046Ssos
9826046Ssos/*
98342505Syokota * Start output on the (slave) interface.  Get another datagram to send
98442505Syokota * off of the interface queue, and copy it to the interface
98542505Syokota * before starting the output.
98642505Syokota */
98742505Syokotastatic void ct_send (drv_t *d)
98842505Syokota{
98942505Syokota	struct mbuf *m;
99042505Syokota	u_short len;
99142505Syokota
99242505Syokota	CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
99342505Syokota
99442505Syokota	/* No output if the interface is down. */
9956046Ssos	if (! d->running)
99642505Syokota		return;
99742505Syokota
99842505Syokota	/* No output if the modem is off. */
99942505Syokota	if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
100042505Syokota		return;
100142505Syokota
100242505Syokota	while (ct_buf_free (d->chan)) {
100342505Syokota		/* Get the packet to send. */
100442505Syokota#ifdef NETGRAPH
100542505Syokota		IF_DEQUEUE (&d->hi_queue, m);
100642505Syokota		if (! m)
100742505Syokota			IF_DEQUEUE (&d->queue, m);
100842505Syokota#else
100942505Syokota		m = sppp_dequeue (d->ifp);
101042505Syokota#endif
101142505Syokota		if (! m)
101242505Syokota			return;
101342505Syokota#ifndef NETGRAPH
101442505Syokota		BPF_MTAP (d->ifp, m);
101542505Syokota#endif
101642505Syokota		len = m_length (m, NULL);
101742505Syokota		if (! m->m_next)
101842505Syokota			ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
101942505Syokota				len, 0);
102042505Syokota		else {
102142505Syokota			m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
102242505Syokota			ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
102342505Syokota				len, 0);
102442505Syokota		}
102542505Syokota		m_freem (m);
102642505Syokota
102742505Syokota		/* Set up transmit timeout, if the transmit ring is not empty.
102842505Syokota		 * Transmit timeout is 10 seconds. */
102942505Syokota		d->timeout = 10;
103042505Syokota	}
103142505Syokota#ifndef NETGRAPH
103242505Syokota	d->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
103342505Syokota#endif
103442505Syokota}
103542505Syokota
103642505Syokota/*
103742505Syokota * Start output on the interface.
103842505Syokota * Always called on splimp().
103942505Syokota */
104042505Syokotastatic void ct_start (drv_t *d)
104142505Syokota{
104242505Syokota	int s = splimp ();
104342505Syokota
104442505Syokota	if (d->running) {
104542505Syokota		if (! d->chan->dtr)
104642505Syokota			ct_set_dtr (d->chan, 1);
104742505Syokota		if (! d->chan->rts)
104842505Syokota			ct_set_rts (d->chan, 1);
104942505Syokota		ct_send (d);
105042505Syokota		callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d);
105142505Syokota	}
105242505Syokota
105342505Syokota	splx (s);
105442505Syokota}
105542505Syokota
105642505Syokota/*
105742505Syokota * Handle transmit timeouts.
105842505Syokota * Recover after lost transmit interrupts.
105942505Syokota * Always called on splimp().
106042505Syokota */
106142505Syokotastatic void ct_watchdog (drv_t *d)
106242505Syokota{
106342505Syokota
106442505Syokota	CT_DEBUG (d, ("device timeout\n"));
106542505Syokota	if (d->running) {
106642505Syokota		ct_setup_chan (d->chan);
106742505Syokota		ct_start_chan (d->chan, 0, 0);
106842505Syokota		ct_set_dtr (d->chan, 1);
106942505Syokota		ct_set_rts (d->chan, 1);
107042505Syokota		ct_start (d);
107142505Syokota	}
107242505Syokota}
107342505Syokota
107442505Syokotastatic void ct_watchdog_timer (void *arg)
107542505Syokota{
107642505Syokota	drv_t *d = arg;
107742505Syokota	bdrv_t *bd = d->bd;
107829603Scharnier
10792088Ssos	CT_LOCK (bd);
10802088Ssos	if (d->timeout == 1)
108129603Scharnier		ct_watchdog (d);
108242505Syokota	if (d->timeout)
108329603Scharnier		d->timeout--;
108442505Syokota	callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d);
108529603Scharnier	CT_UNLOCK (bd);
10862088Ssos}
10872088Ssos
10882088Ssos/*
108951287Speter * Transmit callback function.
10902088Ssos */
10912088Ssosstatic void ct_transmit (ct_chan_t *c, void *attachment, int len)
10922088Ssos{
10932088Ssos	drv_t *d = c->sys;
109442505Syokota
10952088Ssos	if (!d)
10962088Ssos		return;
10972088Ssos	d->timeout = 0;
10982088Ssos#ifndef NETGRAPH
10992088Ssos	++d->ifp->if_opackets;
11002088Ssos	d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
11012088Ssos#endif
11022088Ssos	ct_start (d);
110319569Sjoerg}
11042088Ssos
110519569Sjoerg/*
110619569Sjoerg * Process the received packet.
110719569Sjoerg */
11082088Ssosstatic void ct_receive (ct_chan_t *c, char *data, int len)
11098857Srgrimes{
11102088Ssos	drv_t *d = c->sys;
11112088Ssos	struct mbuf *m;
11122088Ssos#ifdef NETGRAPH
11132088Ssos	int error;
11142088Ssos#endif
11156046Ssos
11166046Ssos	if (!d || !d->running)
11176046Ssos		return;
111842505Syokota
111942505Syokota	m = makembuf (data, len);
112042505Syokota	if (! m) {
112142505Syokota		CT_DEBUG (d, ("no memory for packet\n"));
112242505Syokota#ifndef NETGRAPH
112342505Syokota		++d->ifp->if_iqdrops;
112442505Syokota#endif
112542505Syokota		return;
112642505Syokota	}
11272088Ssos	if (c->debug > 1)
11282088Ssos		printmbuf (m);
11292088Ssos#ifdef NETGRAPH
11302088Ssos	m->m_pkthdr.rcvif = 0;
11312088Ssos	NG_SEND_DATA_ONLY (error, d->hook, m);
11322088Ssos#else
11332088Ssos	++d->ifp->if_ipackets;
11342088Ssos	m->m_pkthdr.rcvif = d->ifp;
11352088Ssos	/* Check if there's a BPF listener on this interface.
113629603Scharnier	 * If so, hand off the raw packet to bpf. */
11372088Ssos	BPF_TAP (d->ifp, data, len);
11382088Ssos	IF_ENQUEUE (&d->queue, m);
11392088Ssos#endif
1140}
1141
1142/*
1143 * Error callback function.
1144 */
1145static void ct_error (ct_chan_t *c, int data)
1146{
1147	drv_t *d = c->sys;
1148
1149	if (!d)
1150		return;
1151
1152	switch (data) {
1153	case CT_FRAME:
1154		CT_DEBUG (d, ("frame error\n"));
1155#ifndef NETGRAPH
1156		++d->ifp->if_ierrors;
1157#endif
1158		break;
1159	case CT_CRC:
1160		CT_DEBUG (d, ("crc error\n"));
1161#ifndef NETGRAPH
1162		++d->ifp->if_ierrors;
1163#endif
1164		break;
1165	case CT_OVERRUN:
1166		CT_DEBUG (d, ("overrun error\n"));
1167#ifndef NETGRAPH
1168		++d->ifp->if_collisions;
1169		++d->ifp->if_ierrors;
1170#endif
1171		break;
1172	case CT_OVERFLOW:
1173		CT_DEBUG (d, ("overflow error\n"));
1174#ifndef NETGRAPH
1175		++d->ifp->if_ierrors;
1176#endif
1177		break;
1178	case CT_UNDERRUN:
1179		CT_DEBUG (d, ("underrun error\n"));
1180		d->timeout = 0;
1181#ifndef NETGRAPH
1182		++d->ifp->if_oerrors;
1183		d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1184#endif
1185		ct_start (d);
1186		break;
1187	default:
1188		CT_DEBUG (d, ("error #%d\n", data));
1189	}
1190}
1191
1192static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1193{
1194	drv_t *d;
1195
1196	if (dev2unit(dev) >= NCTAU*NCHAN || ! (d = channel[dev2unit(dev)]))
1197		return ENXIO;
1198
1199	CT_DEBUG2 (d, ("ct_open\n"));
1200	return 0;
1201}
1202
1203static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1204{
1205	drv_t *d = channel [dev2unit(dev)];
1206
1207	if (!d)
1208		return 0;
1209
1210	CT_DEBUG2 (d, ("ct_close\n"));
1211	return 0;
1212}
1213
1214static int ct_modem_status (ct_chan_t *c)
1215{
1216	drv_t *d = c->sys;
1217	bdrv_t *bd;
1218	int status, s;
1219
1220	if (!d)
1221		return 0;
1222
1223	bd = d->bd;
1224
1225	status = d->running ? TIOCM_LE : 0;
1226	s = splimp ();
1227	CT_LOCK (bd);
1228	if (ct_get_cd  (c)) status |= TIOCM_CD;
1229	if (ct_get_cts (c)) status |= TIOCM_CTS;
1230	if (ct_get_dsr (c)) status |= TIOCM_DSR;
1231	if (c->dtr)	    status |= TIOCM_DTR;
1232	if (c->rts)	    status |= TIOCM_RTS;
1233	CT_UNLOCK (bd);
1234	splx (s);
1235	return status;
1236}
1237
1238/*
1239 * Process an ioctl request on /dev/cronyx/ctauN.
1240 */
1241static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1242{
1243	drv_t *d = channel [dev2unit (dev)];
1244	bdrv_t *bd;
1245	ct_chan_t *c;
1246	struct serial_statistics *st;
1247	struct e1_statistics *opte1;
1248	int error, s;
1249	char mask[16];
1250
1251	if (!d || !d->chan)
1252		return 0;
1253
1254	bd = d->bd;
1255	c = d->chan;
1256
1257	switch (cmd) {
1258	case SERIAL_GETREGISTERED:
1259		bzero (mask, sizeof(mask));
1260		for (s=0; s<NCTAU*NCHAN; ++s)
1261			if (channel [s])
1262				mask [s/8] |= 1 << (s & 7);
1263		bcopy (mask, data, sizeof (mask));
1264		return 0;
1265
1266#ifndef NETGRAPH
1267	case SERIAL_GETPROTO:
1268		strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" :
1269			(d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp");
1270		return 0;
1271
1272	case SERIAL_SETPROTO:
1273		/* Only for superuser! */
1274		error = priv_check (td, PRIV_DRIVER);
1275		if (error)
1276			return error;
1277		if (d->ifp->if_drv_flags & IFF_DRV_RUNNING)
1278			return EBUSY;
1279		if (! strcmp ("cisco", (char*)data)) {
1280			IFP2SP(d->ifp)->pp_flags &= ~(PP_FR);
1281			IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1282			d->ifp->if_flags |= PP_CISCO;
1283		} else if (! strcmp ("fr", (char*)data)) {
1284			d->ifp->if_flags &= ~(PP_CISCO);
1285			IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE;
1286		} else if (! strcmp ("ppp", (char*)data)) {
1287			IFP2SP(d->ifp)->pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1288			d->ifp->if_flags &= ~(PP_CISCO);
1289		} else
1290			return EINVAL;
1291		return 0;
1292
1293	case SERIAL_GETKEEPALIVE:
1294		if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1295			(d->ifp->if_flags & PP_CISCO))
1296			return EINVAL;
1297		*(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0;
1298		return 0;
1299
1300	case SERIAL_SETKEEPALIVE:
1301		/* Only for superuser! */
1302		error = priv_check (td, PRIV_DRIVER);
1303		if (error)
1304			return error;
1305		if ((IFP2SP(d->ifp)->pp_flags & PP_FR) ||
1306			(d->ifp->if_flags & PP_CISCO))
1307			return EINVAL;
1308		if (*(int*)data)
1309			IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE;
1310		else
1311			IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE;
1312		return 0;
1313#endif /*NETGRAPH*/
1314
1315	case SERIAL_GETMODE:
1316		*(int*)data = SERIAL_HDLC;
1317		return 0;
1318
1319	case SERIAL_GETCFG:
1320		if (c->mode == M_HDLC)
1321			return EINVAL;
1322		switch (ct_get_config (c->board)) {
1323		default:    *(char*)data = 'a'; break;
1324		case CFG_B: *(char*)data = 'b'; break;
1325		case CFG_C: *(char*)data = 'c'; break;
1326		}
1327		return 0;
1328
1329	case SERIAL_SETCFG:
1330		/* Only for superuser! */
1331		error = priv_check (td, PRIV_DRIVER);
1332		if (error)
1333			return error;
1334		if (c->mode == M_HDLC)
1335			return EINVAL;
1336		s = splimp ();
1337		CT_LOCK (bd);
1338		switch (*(char*)data) {
1339		case 'a': ct_set_config (c->board, CFG_A); break;
1340		case 'b': ct_set_config (c->board, CFG_B); break;
1341		case 'c': ct_set_config (c->board, CFG_C); break;
1342		}
1343		CT_UNLOCK (bd);
1344		splx (s);
1345		return 0;
1346
1347	case SERIAL_GETSTAT:
1348		st = (struct serial_statistics*) data;
1349		st->rintr  = c->rintr;
1350		st->tintr  = c->tintr;
1351		st->mintr  = c->mintr;
1352		st->ibytes = c->ibytes;
1353		st->ipkts  = c->ipkts;
1354		st->ierrs  = c->ierrs;
1355		st->obytes = c->obytes;
1356		st->opkts  = c->opkts;
1357		st->oerrs  = c->oerrs;
1358		return 0;
1359
1360	case SERIAL_GETESTAT:
1361		opte1 = (struct e1_statistics*)data;
1362		opte1->status	   = c->status;
1363		opte1->cursec	   = c->cursec;
1364		opte1->totsec	   = c->totsec + c->cursec;
1365
1366		opte1->currnt.bpv   = c->currnt.bpv;
1367		opte1->currnt.fse   = c->currnt.fse;
1368		opte1->currnt.crce  = c->currnt.crce;
1369		opte1->currnt.rcrce = c->currnt.rcrce;
1370		opte1->currnt.uas   = c->currnt.uas;
1371		opte1->currnt.les   = c->currnt.les;
1372		opte1->currnt.es    = c->currnt.es;
1373		opte1->currnt.bes   = c->currnt.bes;
1374		opte1->currnt.ses   = c->currnt.ses;
1375		opte1->currnt.oofs  = c->currnt.oofs;
1376		opte1->currnt.css   = c->currnt.css;
1377		opte1->currnt.dm    = c->currnt.dm;
1378
1379		opte1->total.bpv   = c->total.bpv   + c->currnt.bpv;
1380		opte1->total.fse   = c->total.fse   + c->currnt.fse;
1381		opte1->total.crce  = c->total.crce  + c->currnt.crce;
1382		opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1383		opte1->total.uas   = c->total.uas   + c->currnt.uas;
1384		opte1->total.les   = c->total.les   + c->currnt.les;
1385		opte1->total.es	   = c->total.es    + c->currnt.es;
1386		opte1->total.bes   = c->total.bes   + c->currnt.bes;
1387		opte1->total.ses   = c->total.ses   + c->currnt.ses;
1388		opte1->total.oofs  = c->total.oofs  + c->currnt.oofs;
1389		opte1->total.css   = c->total.css   + c->currnt.css;
1390		opte1->total.dm	   = c->total.dm    + c->currnt.dm;
1391		for (s=0; s<48; ++s) {
1392			opte1->interval[s].bpv   = c->interval[s].bpv;
1393			opte1->interval[s].fse   = c->interval[s].fse;
1394			opte1->interval[s].crce  = c->interval[s].crce;
1395			opte1->interval[s].rcrce = c->interval[s].rcrce;
1396			opte1->interval[s].uas   = c->interval[s].uas;
1397			opte1->interval[s].les   = c->interval[s].les;
1398			opte1->interval[s].es	 = c->interval[s].es;
1399			opte1->interval[s].bes   = c->interval[s].bes;
1400			opte1->interval[s].ses   = c->interval[s].ses;
1401			opte1->interval[s].oofs  = c->interval[s].oofs;
1402			opte1->interval[s].css   = c->interval[s].css;
1403			opte1->interval[s].dm	 = c->interval[s].dm;
1404		}
1405		return 0;
1406
1407	case SERIAL_CLRSTAT:
1408		/* Only for superuser! */
1409		error = priv_check (td, PRIV_DRIVER);
1410		if (error)
1411			return error;
1412		c->rintr = 0;
1413		c->tintr = 0;
1414		c->mintr = 0;
1415		c->ibytes = 0;
1416		c->ipkts = 0;
1417		c->ierrs = 0;
1418		c->obytes = 0;
1419		c->opkts = 0;
1420		c->oerrs = 0;
1421		bzero (&c->currnt, sizeof (c->currnt));
1422		bzero (&c->total, sizeof (c->total));
1423		bzero (c->interval, sizeof (c->interval));
1424		return 0;
1425
1426	case SERIAL_GETBAUD:
1427		*(long*)data = ct_get_baud(c);
1428		return 0;
1429
1430	case SERIAL_SETBAUD:
1431		/* Only for superuser! */
1432		error = priv_check (td, PRIV_DRIVER);
1433		if (error)
1434			return error;
1435		s = splimp ();
1436		CT_LOCK (bd);
1437		ct_set_baud (c, *(long*)data);
1438		CT_UNLOCK (bd);
1439		splx (s);
1440		return 0;
1441
1442	case SERIAL_GETLOOP:
1443		*(int*)data = ct_get_loop (c);
1444		return 0;
1445
1446	case SERIAL_SETLOOP:
1447		/* Only for superuser! */
1448		error = priv_check (td, PRIV_DRIVER);
1449		if (error)
1450			return error;
1451		s = splimp ();
1452		CT_LOCK (bd);
1453		ct_set_loop (c, *(int*)data);
1454		CT_UNLOCK (bd);
1455		splx (s);
1456		return 0;
1457
1458	case SERIAL_GETDPLL:
1459		if (c->mode == M_E1 || c->mode == M_G703)
1460			return EINVAL;
1461		*(int*)data = ct_get_dpll (c);
1462		return 0;
1463
1464	case SERIAL_SETDPLL:
1465		/* Only for superuser! */
1466		error = priv_check (td, PRIV_DRIVER);
1467		if (error)
1468			return error;
1469		if (c->mode == M_E1 || c->mode == M_G703)
1470			return EINVAL;
1471		s = splimp ();
1472		CT_LOCK (bd);
1473		ct_set_dpll (c, *(int*)data);
1474		CT_UNLOCK (bd);
1475		splx (s);
1476		return 0;
1477
1478	case SERIAL_GETNRZI:
1479		if (c->mode == M_E1 || c->mode == M_G703)
1480			return EINVAL;
1481		*(int*)data = ct_get_nrzi (c);
1482		return 0;
1483
1484	case SERIAL_SETNRZI:
1485		/* Only for superuser! */
1486		error = priv_check (td, PRIV_DRIVER);
1487		if (error)
1488			return error;
1489		if (c->mode == M_E1 || c->mode == M_G703)
1490			return EINVAL;
1491		s = splimp ();
1492		CT_LOCK (bd);
1493		ct_set_nrzi (c, *(int*)data);
1494		CT_UNLOCK (bd);
1495		splx (s);
1496		return 0;
1497
1498	case SERIAL_GETDEBUG:
1499		*(int*)data = c->debug;
1500		return 0;
1501
1502	case SERIAL_SETDEBUG:
1503		/* Only for superuser! */
1504		error = priv_check (td, PRIV_DRIVER);
1505		if (error)
1506			return error;
1507#ifndef	NETGRAPH
1508		/*
1509		 * The debug_shadow is always greater than zero for logic
1510		 * simplicity.  For switching debug off the IFF_DEBUG is
1511		 * responsible.
1512		 */
1513		c->debug_shadow = (*(int*)data) ? (*(int*)data) : 1;
1514		if (d->ifp->if_flags & IFF_DEBUG)
1515			c->debug = c->debug_shadow;
1516#else
1517		c->debug = *(int*)data;
1518#endif
1519		return 0;
1520
1521	case SERIAL_GETHIGAIN:
1522		if (c->mode != M_E1)
1523			return EINVAL;
1524		*(int*)data = ct_get_higain (c);
1525		return 0;
1526
1527	case SERIAL_SETHIGAIN:
1528		/* Only for superuser! */
1529		error = priv_check (td, PRIV_DRIVER);
1530		if (error)
1531			return error;
1532		s = splimp ();
1533		CT_LOCK (bd);
1534		ct_set_higain (c, *(int*)data);
1535		CT_UNLOCK (bd);
1536		splx (s);
1537		return 0;
1538
1539	case SERIAL_GETPHONY:
1540		CT_DEBUG2 (d, ("ioctl: getphony\n"));
1541		if (c->mode != M_E1)
1542			return EINVAL;
1543		*(int*)data = c->gopt.phony;
1544		return 0;
1545
1546	case SERIAL_SETPHONY:
1547		CT_DEBUG2 (d, ("ioctl: setphony\n"));
1548		if (c->mode != M_E1)
1549			return EINVAL;
1550		/* Only for superuser! */
1551		error = priv_check (td, PRIV_DRIVER);
1552		if (error)
1553			return error;
1554		s = splimp ();
1555		CT_LOCK (bd);
1556		ct_set_phony (c, *(int*)data);
1557		CT_UNLOCK (bd);
1558		splx (s);
1559		return 0;
1560
1561	case SERIAL_GETCLK:
1562		if (c->mode != M_E1 && c->mode != M_G703)
1563			return EINVAL;
1564		switch (ct_get_clk(c)) {
1565		default:	 *(int*)data = E1CLK_INTERNAL;		break;
1566		case GCLK_RCV:   *(int*)data = E1CLK_RECEIVE;		break;
1567		case GCLK_RCLKO: *(int*)data = c->num ?
1568			E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1;	break;
1569		}
1570		return 0;
1571
1572	case SERIAL_SETCLK:
1573		/* Only for superuser! */
1574		error = priv_check (td, PRIV_DRIVER);
1575		if (error)
1576			return error;
1577		s = splimp ();
1578		CT_LOCK (bd);
1579		switch (*(int*)data) {
1580		default:		    ct_set_clk (c, GCLK_INT);   break;
1581		case E1CLK_RECEIVE:	    ct_set_clk (c, GCLK_RCV);   break;
1582		case E1CLK_RECEIVE_CHAN0:
1583		case E1CLK_RECEIVE_CHAN1:
1584					    ct_set_clk (c, GCLK_RCLKO); break;
1585		}
1586		CT_UNLOCK (bd);
1587		splx (s);
1588		return 0;
1589
1590	case SERIAL_GETTIMESLOTS:
1591		if (c->mode != M_E1)
1592			return EINVAL;
1593		*(long*)data = ct_get_ts (c);
1594		return 0;
1595
1596	case SERIAL_SETTIMESLOTS:
1597		/* Only for superuser! */
1598		error = priv_check (td, PRIV_DRIVER);
1599		if (error)
1600			return error;
1601		s = splimp ();
1602		CT_LOCK (bd);
1603		ct_set_ts (c, *(long*)data);
1604		CT_UNLOCK (bd);
1605		splx (s);
1606		return 0;
1607
1608	case SERIAL_GETSUBCHAN:
1609		if (c->mode != M_E1)
1610			return EINVAL;
1611		*(long*)data = ct_get_subchan (c->board);
1612		return 0;
1613
1614	case SERIAL_SETSUBCHAN:
1615		/* Only for superuser! */
1616		error = priv_check (td, PRIV_DRIVER);
1617		if (error)
1618			return error;
1619		s = splimp ();
1620		CT_LOCK (bd);
1621		ct_set_subchan (c->board, *(long*)data);
1622		CT_UNLOCK (bd);
1623		splx (s);
1624		return 0;
1625
1626	case SERIAL_GETINVCLK:
1627	case SERIAL_GETINVTCLK:
1628		if (c->mode == M_E1 || c->mode == M_G703)
1629			return EINVAL;
1630		*(int*)data = ct_get_invtxc (c);
1631		return 0;
1632
1633	case SERIAL_GETINVRCLK:
1634		if (c->mode == M_E1 || c->mode == M_G703)
1635			return EINVAL;
1636		*(int*)data = ct_get_invrxc (c);
1637		return 0;
1638
1639	case SERIAL_SETINVCLK:
1640	case SERIAL_SETINVTCLK:
1641		/* Only for superuser! */
1642		error = priv_check (td, PRIV_DRIVER);
1643		if (error)
1644			return error;
1645		if (c->mode == M_E1 || c->mode == M_G703)
1646			return EINVAL;
1647		s = splimp ();
1648		CT_LOCK (bd);
1649		ct_set_invtxc (c, *(int*)data);
1650		CT_UNLOCK (bd);
1651		splx (s);
1652		return 0;
1653
1654	case SERIAL_SETINVRCLK:
1655		/* Only for superuser! */
1656		error = priv_check (td, PRIV_DRIVER);
1657		if (error)
1658			return error;
1659		if (c->mode == M_E1 || c->mode == M_G703)
1660			return EINVAL;
1661		s = splimp ();
1662		CT_LOCK (bd);
1663		ct_set_invrxc (c, *(int*)data);
1664		CT_UNLOCK (bd);
1665		splx (s);
1666		return 0;
1667
1668	case SERIAL_GETLEVEL:
1669		if (c->mode != M_G703)
1670			return EINVAL;
1671		s = splimp ();
1672		CT_LOCK (bd);
1673		*(int*)data = ct_get_lq (c);
1674		CT_UNLOCK (bd);
1675		splx (s);
1676		return 0;
1677
1678	case TIOCSDTR:	/* Set DTR */
1679		s = splimp ();
1680		CT_LOCK (bd);
1681		ct_set_dtr (c, 1);
1682		CT_UNLOCK (bd);
1683		splx (s);
1684		return 0;
1685
1686	case TIOCCDTR:	/* Clear DTR */
1687		s = splimp ();
1688		CT_LOCK (bd);
1689		ct_set_dtr (c, 0);
1690		CT_UNLOCK (bd);
1691		splx (s);
1692		return 0;
1693
1694	case TIOCMSET:	/* Set DTR/RTS */
1695		s = splimp ();
1696		CT_LOCK (bd);
1697		ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1698		ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1699		CT_UNLOCK (bd);
1700		splx (s);
1701		return 0;
1702
1703	case TIOCMBIS:	/* Add DTR/RTS */
1704		s = splimp ();
1705		CT_LOCK (bd);
1706		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1);
1707		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1);
1708		CT_UNLOCK (bd);
1709		splx (s);
1710		return 0;
1711
1712	case TIOCMBIC:	/* Clear DTR/RTS */
1713		s = splimp ();
1714		CT_LOCK (bd);
1715		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0);
1716		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0);
1717		CT_UNLOCK (bd);
1718		splx (s);
1719		return 0;
1720
1721	case TIOCMGET:	/* Get modem status */
1722		*(int*)data = ct_modem_status (c);
1723		return 0;
1724	}
1725	return ENOTTY;
1726}
1727
1728#ifdef NETGRAPH
1729static int ng_ct_constructor (node_p node)
1730{
1731	drv_t *d = NG_NODE_PRIVATE (node);
1732	CT_DEBUG (d, ("Constructor\n"));
1733	return EINVAL;
1734}
1735
1736static int ng_ct_newhook (node_p node, hook_p hook, const char *name)
1737{
1738	int s;
1739	drv_t *d = NG_NODE_PRIVATE (node);
1740
1741	if (!d)
1742		return EINVAL;
1743
1744	bdrv_t *bd = d->bd;
1745
1746	/* Attach debug hook */
1747	if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) {
1748		NG_HOOK_SET_PRIVATE (hook, NULL);
1749		d->debug_hook = hook;
1750		return 0;
1751	}
1752
1753	/* Check for raw hook */
1754	if (strcmp (name, NG_CT_HOOK_RAW) != 0)
1755		return EINVAL;
1756
1757	NG_HOOK_SET_PRIVATE (hook, d);
1758	d->hook = hook;
1759	s = splimp ();
1760	CT_LOCK (bd);
1761	ct_up (d);
1762	CT_UNLOCK (bd);
1763	splx (s);
1764	return 0;
1765}
1766
1767static char *format_timeslots (u_long s)
1768{
1769	static char buf [100];
1770	char *p = buf;
1771	int i;
1772
1773	for (i=1; i<32; ++i)
1774		if ((s >> i) & 1) {
1775			int prev = (i > 1)  & (s >> (i-1));
1776			int next = (i < 31) & (s >> (i+1));
1777
1778			if (prev) {
1779				if (next)
1780					continue;
1781				*p++ = '-';
1782			} else if (p > buf)
1783				*p++ = ',';
1784
1785			if (i >= 10)
1786				*p++ = '0' + i / 10;
1787			*p++ = '0' + i % 10;
1788		}
1789	*p = 0;
1790	return buf;
1791}
1792
1793static int print_modems (char *s, ct_chan_t *c, int need_header)
1794{
1795	int status = ct_modem_status (c);
1796	int length = 0;
1797
1798	if (need_header)
1799		length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1800	length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1801		status & TIOCM_LE  ? "On" : "-",
1802		status & TIOCM_DTR ? "On" : "-",
1803		status & TIOCM_DSR ? "On" : "-",
1804		status & TIOCM_RTS ? "On" : "-",
1805		status & TIOCM_CTS ? "On" : "-",
1806		status & TIOCM_CD  ? "On" : "-");
1807	return length;
1808}
1809
1810static int print_stats (char *s, ct_chan_t *c, int need_header)
1811{
1812	struct serial_statistics st;
1813	int length = 0;
1814
1815	st.rintr  = c->rintr;
1816	st.tintr  = c->tintr;
1817	st.mintr  = c->mintr;
1818	st.ibytes = c->ibytes;
1819	st.ipkts  = c->ipkts;
1820	st.ierrs  = c->ierrs;
1821	st.obytes = c->obytes;
1822	st.opkts  = c->opkts;
1823	st.oerrs  = c->oerrs;
1824	if (need_header)
1825		length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1826	length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
1827		st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts,
1828		st.ierrs, st.obytes, st.opkts, st.oerrs);
1829	return length;
1830}
1831
1832static char *format_e1_status (u_char status)
1833{
1834	static char buf [80];
1835
1836	if (status & E1_NOALARM)
1837		return "Ok";
1838	buf[0] = 0;
1839	if (status & E1_LOS)     strcat (buf, ",LOS");
1840	if (status & E1_AIS)     strcat (buf, ",AIS");
1841	if (status & E1_LOF)     strcat (buf, ",LOF");
1842	if (status & E1_LOMF)    strcat (buf, ",LOMF");
1843	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
1844	if (status & E1_AIS16)   strcat (buf, ",AIS16");
1845	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
1846	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
1847	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
1848	if (buf[0] == ',')
1849		return buf+1;
1850	return "Unknown";
1851}
1852
1853static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
1854{
1855	int n, length = 0;
1856
1857	if (numerator < 1 || divider < 1) {
1858		length += sprintf (s+length, leftalign ? "/-   " : "    -");
1859		return length;
1860	}
1861	n = (int) (0.5 + 1000.0 * numerator / divider);
1862	if (n < 1000) {
1863		length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
1864		return length;
1865	}
1866	*(s + length) = leftalign ? '/' : ' ';
1867	length ++;
1868
1869	if     (n >= 1000000) n = (n+500) / 1000 * 1000;
1870	else if (n >= 100000)  n = (n+50)  / 100 * 100;
1871	else if (n >= 10000)   n = (n+5)   / 10 * 10;
1872
1873	switch (n) {
1874	case 1000:    length += printf (s+length, ".999"); return length;
1875	case 10000:   n = 9990;   break;
1876	case 100000:  n = 99900;  break;
1877	case 1000000: n = 999000; break;
1878	}
1879	if (n < 10000)	      length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
1880	else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
1881	else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
1882	else		      length += sprintf (s+length, "%d", n/1000);
1883
1884	return length;
1885}
1886
1887static int print_e1_stats (char *s, ct_chan_t *c)
1888{
1889	struct e1_counters total;
1890	u_long totsec;
1891	int length = 0;
1892
1893	totsec		= c->totsec + c->cursec;
1894	total.bpv	= c->total.bpv   + c->currnt.bpv;
1895	total.fse	= c->total.fse   + c->currnt.fse;
1896	total.crce	= c->total.crce  + c->currnt.crce;
1897	total.rcrce	= c->total.rcrce + c->currnt.rcrce;
1898	total.uas	= c->total.uas   + c->currnt.uas;
1899	total.les	= c->total.les   + c->currnt.les;
1900	total.es	= c->total.es    + c->currnt.es;
1901	total.bes	= c->total.bes   + c->currnt.bes;
1902	total.ses	= c->total.ses   + c->currnt.ses;
1903	total.oofs	= c->total.oofs  + c->currnt.oofs;
1904	total.css	= c->total.css   + c->currnt.css;
1905	total.dm	= c->total.dm    + c->currnt.dm;
1906
1907	length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
1908
1909	/* Unavailable seconds, degraded minutes */
1910	length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
1911	length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
1912
1913	/* Bipolar violations, frame sync errors */
1914	length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
1915	length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
1916
1917	/* CRC errors, remote CRC errors (E-bit) */
1918	length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
1919	length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
1920
1921	/* Errored seconds, line errored seconds */
1922	length += print_frac (s + length, 0, c->currnt.es, c->cursec);
1923	length += print_frac (s + length, 1, c->currnt.les, c->cursec);
1924
1925	/* Severely errored seconds, burst errored seconds */
1926	length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
1927	length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
1928
1929	/* Out of frame seconds, controlled slip seconds */
1930	length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
1931	length += print_frac (s + length, 1, c->currnt.css, c->cursec);
1932
1933	length += sprintf (s + length, " %s\n", format_e1_status (c->status));
1934
1935	/* Print total statistics. */
1936	length += print_frac (s + length, 0, total.uas, totsec);
1937	length += print_frac (s + length, 1, 60 * total.dm, totsec);
1938
1939	length += print_frac (s + length, 0, total.bpv, totsec);
1940	length += print_frac (s + length, 1, total.fse, totsec);
1941
1942	length += print_frac (s + length, 0, total.crce, totsec);
1943	length += print_frac (s + length, 1, total.rcrce, totsec);
1944
1945	length += print_frac (s + length, 0, total.es, totsec);
1946	length += print_frac (s + length, 1, total.les, totsec);
1947
1948	length += print_frac (s + length, 0, total.ses, totsec);
1949	length += print_frac (s + length, 1, total.bes, totsec);
1950
1951	length += print_frac (s + length, 0, total.oofs, totsec);
1952	length += print_frac (s + length, 1, total.css, totsec);
1953
1954	length += sprintf (s + length, " -- Total\n");
1955	return length;
1956}
1957
1958static int print_chan (char *s, ct_chan_t *c)
1959{
1960	drv_t *d = c->sys;
1961	bdrv_t *bd = d->bd;
1962	int length = 0;
1963
1964	length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num);
1965	if (d->chan->debug)
1966		length += sprintf (s + length, " debug=%d", d->chan->debug);
1967
1968	switch (ct_get_config (c->board)) {
1969	case CFG_A:	length += sprintf (s + length, " cfg=A");	break;
1970	case CFG_B:	length += sprintf (s + length, " cfg=B");	break;
1971	case CFG_C:	length += sprintf (s + length, " cfg=C");	break;
1972	default:	length += sprintf (s + length, " cfg=unknown"); break;
1973	}
1974
1975	if (ct_get_baud (c))
1976		length += sprintf (s + length, " %ld", ct_get_baud (c));
1977	else
1978		length += sprintf (s + length, " extclock");
1979
1980	if (c->mode == M_E1 || c->mode == M_G703)
1981		switch (ct_get_clk(c)) {
1982		case GCLK_INT   : length += sprintf (s + length, " syn=int");     break;
1983		case GCLK_RCV   : length += sprintf (s + length, " syn=rcv");     break;
1984		case GCLK_RCLKO  : length += sprintf (s + length, " syn=xrcv");    break;
1985		}
1986	if (c->mode == M_HDLC) {
1987		length += sprintf (s + length, " dpll=%s",   ct_get_dpll (c)   ? "on" : "off");
1988		length += sprintf (s + length, " nrzi=%s",   ct_get_nrzi (c)   ? "on" : "off");
1989		length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off");
1990		length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off");
1991	}
1992	if (c->mode == M_E1)
1993		length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off");
1994
1995	length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off");
1996
1997	if (c->mode == M_E1)
1998		length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c)));
1999	if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A)
2000		length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board)));
2001	if (c->mode == M_G703) {
2002		int lq, x;
2003
2004		x = splimp ();
2005		CT_LOCK (bd);
2006		lq = ct_get_lq (c);
2007		CT_UNLOCK (bd);
2008		splx (x);
2009		length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2010	}
2011	length += sprintf (s + length, "\n");
2012	return length;
2013}
2014
2015static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook)
2016{
2017	drv_t *d = NG_NODE_PRIVATE (node);
2018	struct ng_mesg *msg;
2019	struct ng_mesg *resp = NULL;
2020	int error = 0;
2021
2022	if (!d)
2023		return EINVAL;
2024
2025	CT_DEBUG (d, ("Rcvmsg\n"));
2026	NGI_GET_MSG (item, msg);
2027	switch (msg->header.typecookie) {
2028	default:
2029		error = EINVAL;
2030		break;
2031
2032	case NGM_CT_COOKIE:
2033		printf ("Don't forget to implement\n");
2034		error = EINVAL;
2035		break;
2036
2037	case NGM_GENERIC_COOKIE:
2038		switch (msg->header.cmd) {
2039		default:
2040			error = EINVAL;
2041			break;
2042
2043		case NGM_TEXT_STATUS: {
2044			char *s;
2045			int l = 0;
2046			int dl = sizeof (struct ng_mesg) + 730;
2047
2048			NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2049			if (! resp) {
2050				error = ENOMEM;
2051				break;
2052			}
2053			s = (resp)->data;
2054			l += print_chan (s + l, d->chan);
2055			l += print_stats (s + l, d->chan, 1);
2056			l += print_modems (s + l, d->chan, 1);
2057			l += print_e1_stats (s + l, d->chan);
2058			strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRSIZ);
2059			}
2060			break;
2061		}
2062		break;
2063	}
2064	NG_RESPOND_MSG (error, node, item, resp);
2065	NG_FREE_MSG (msg);
2066	return error;
2067}
2068
2069static int ng_ct_rcvdata (hook_p hook, item_p item)
2070{
2071	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2072	struct mbuf *m;
2073	struct ng_tag_prio *ptag;
2074	bdrv_t *bd;
2075	struct ifqueue *q;
2076	int s;
2077
2078	if (!d)
2079		return ENETDOWN;
2080
2081	bd = d->bd;
2082	NGI_GET_M (item, m);
2083	NG_FREE_ITEM (item);
2084	if (! NG_HOOK_PRIVATE (hook) || ! d) {
2085		NG_FREE_M (m);
2086		return ENETDOWN;
2087	}
2088
2089	/* Check for high priority data */
2090	if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2091	    NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2092		q = &d->hi_queue;
2093	else
2094		q = &d->queue;
2095
2096	s = splimp ();
2097	CT_LOCK (bd);
2098	IF_LOCK (q);
2099	if (_IF_QFULL (q)) {
2100		_IF_DROP (q);
2101		IF_UNLOCK (q);
2102		CT_UNLOCK (bd);
2103		splx (s);
2104		NG_FREE_M (m);
2105		return ENOBUFS;
2106	}
2107	_IF_ENQUEUE (q, m);
2108	IF_UNLOCK (q);
2109	ct_start (d);
2110	CT_UNLOCK (bd);
2111	splx (s);
2112	return 0;
2113}
2114
2115static int ng_ct_rmnode (node_p node)
2116{
2117	drv_t *d = NG_NODE_PRIVATE (node);
2118	bdrv_t *bd;
2119
2120	CT_DEBUG (d, ("Rmnode\n"));
2121	if (d && d->running) {
2122		bd = d->bd;
2123		int s = splimp ();
2124		CT_LOCK (bd);
2125		ct_down (d);
2126		CT_UNLOCK (bd);
2127		splx (s);
2128	}
2129#ifdef	KLD_MODULE
2130	if (node->nd_flags & NGF_REALLY_DIE) {
2131		NG_NODE_SET_PRIVATE (node, NULL);
2132		NG_NODE_UNREF (node);
2133	}
2134	NG_NODE_REVIVE(node);		/* Persistant node */
2135#endif
2136	return 0;
2137}
2138
2139static int ng_ct_connect (hook_p hook)
2140{
2141	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2142
2143	if (!d)
2144		return 0;
2145
2146	callout_reset (&d->timeout_handle, hz, ct_watchdog_timer, d);
2147	return 0;
2148}
2149
2150static int ng_ct_disconnect (hook_p hook)
2151{
2152	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2153	bdrv_t *bd;
2154
2155	if (!d)
2156		return 0;
2157
2158	bd = d->bd;
2159
2160	CT_LOCK (bd);
2161	if (NG_HOOK_PRIVATE (hook))
2162		ct_down (d);
2163	CT_UNLOCK (bd);
2164	/* If we were wait it than it reasserted now, just stop it. */
2165	if (!callout_drain (&d->timeout_handle))
2166		callout_stop (&d->timeout_handle);
2167	return 0;
2168}
2169#endif
2170
2171static int ct_modevent (module_t mod, int type, void *unused)
2172{
2173	static int load_count = 0;
2174
2175	switch (type) {
2176	case MOD_LOAD:
2177#ifdef NETGRAPH
2178		if (ng_newtype (&typestruct))
2179			printf ("Failed to register ng_ct\n");
2180#endif
2181		++load_count;
2182		callout_init (&timeout_handle, CALLOUT_MPSAFE);
2183		callout_reset (&timeout_handle, hz*5, ct_timeout, 0);
2184		break;
2185	case MOD_UNLOAD:
2186		if (load_count == 1) {
2187			printf ("Removing device entry for Tau-ISA\n");
2188#ifdef NETGRAPH
2189			ng_rmtype (&typestruct);
2190#endif
2191		}
2192		/* If we were wait it than it reasserted now, just stop it. */
2193		if (!callout_drain (&timeout_handle))
2194			callout_stop (&timeout_handle);
2195		--load_count;
2196		break;
2197	case MOD_SHUTDOWN:
2198		break;
2199	}
2200	return 0;
2201}
2202
2203#ifdef NETGRAPH
2204static struct ng_type typestruct = {
2205	.version	= NG_ABI_VERSION,
2206	.name		= NG_CT_NODE_TYPE,
2207	.constructor	= ng_ct_constructor,
2208	.rcvmsg		= ng_ct_rcvmsg,
2209	.shutdown	= ng_ct_rmnode,
2210	.newhook	= ng_ct_newhook,
2211	.connect	= ng_ct_connect,
2212	.rcvdata	= ng_ct_rcvdata,
2213	.disconnect	= ng_ct_disconnect,
2214};
2215#endif /*NETGRAPH*/
2216
2217#ifdef NETGRAPH
2218MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2219#else
2220MODULE_DEPEND (ct, sppp, 1, 1, 1);
2221#endif
2222DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2223MODULE_VERSION (ct, 1);
2224