if_ct.c revision 142717
133965Sjdp/*-
2218822Sdim * Cronyx-Tau adapter driver for FreeBSD.
378828Sobrien * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
433965Sjdp * and asyncronous channels with full modem control.
533965Sjdp * Keepalive protocol implemented in both Cisco and PPP modes.
6130561Sobrien *
733965Sjdp * Copyright (C) 1994-2002 Cronyx Engineering.
8130561Sobrien * Author: Serge Vakulenko, <vak@cronyx.ru>
9130561Sobrien *
10130561Sobrien * Copyright (C) 1999-2004 Cronyx Engineering.
11130561Sobrien * Author: Roman Kurakin, <rik@cronyx.ru>
1233965Sjdp *
13130561Sobrien * This software is distributed with NO WARRANTIES, not even the implied
14130561Sobrien * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15130561Sobrien *
16130561Sobrien * Authors grant any other persons or organisations a permission to use,
1733965Sjdp * modify and redistribute this software in source and binary forms,
18130561Sobrien * as long as this message is kept with the software, all derivative
19130561Sobrien * works or modified versions.
20218822Sdim *
2133965Sjdp * Cronyx Id: if_ct.c,v 1.1.2.31 2004/06/23 17:09:13 rik Exp $
2233965Sjdp */
2333965Sjdp
2433965Sjdp#include <sys/cdefs.h>
2533965Sjdp__FBSDID("$FreeBSD: head/sys/dev/ctau/if_ct.c 142717 2005-02-27 22:16:58Z phk $");
2633965Sjdp
2733965Sjdp#include <sys/param.h>
2833965Sjdp#include <sys/proc.h>
2933965Sjdp#include <sys/systm.h>
3033965Sjdp#include <sys/kernel.h>
3177298Sobrien#include <sys/module.h>
3277298Sobrien#include <sys/mbuf.h>
3377298Sobrien#include <sys/sockio.h>
3477298Sobrien#include <sys/malloc.h>
3577298Sobrien#include <sys/socket.h>
3633965Sjdp#include <sys/sysctl.h>
3733965Sjdp#include <sys/conf.h>
3833965Sjdp#include <sys/errno.h>
3933965Sjdp#include <sys/tty.h>
4033965Sjdp#include <sys/bus.h>
4133965Sjdp#include <machine/bus.h>
4233965Sjdp#include <sys/rman.h>
4333965Sjdp#include <isa/isavar.h>
4433965Sjdp#include <sys/interrupt.h>
4533965Sjdp#include <vm/vm.h>
4633965Sjdp#include <vm/pmap.h>
4733965Sjdp#include <net/if.h>
4889857Sobrien#include <machine/cpufunc.h>
4989857Sobrien#include <machine/cserial.h>
5033965Sjdp#include <machine/clock.h>
5133965Sjdp#include <machine/resource.h>
5289857Sobrien#include <dev/cx/machdep.h>
5389857Sobrien#include <dev/ctau/ctddk.h>
5433965Sjdp#include <dev/cx/cronyxfw.h>
5577298Sobrien#include "opt_ng_cronyx.h"
5689857Sobrien#ifdef NETGRAPH_CRONYX
5789857Sobrien#   include "opt_netgraph.h"
5877298Sobrien#   include <netgraph/ng_message.h>
5977298Sobrien#   include <netgraph/netgraph.h>
6089857Sobrien#   include <dev/ctau/ng_ct.h>
6189857Sobrien#else
6277298Sobrien#   include <net/if_types.h>
6333965Sjdp#   include <net/if_sppp.h>
6433965Sjdp#   define PP_CISCO IFF_LINK2
6533965Sjdp#   include <net/bpf.h>
6633965Sjdp#endif
6733965Sjdp
68218822Sdim#define NCTAU 1
6933965Sjdp
70218822Sdim/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
7133965Sjdp#ifndef PP_FR
72218822Sdim#define PP_FR 0
7333965Sjdp#endif
74218822Sdim
7533965Sjdp#define CT_DEBUG(d,s)	({if (d->chan->debug) {\
7633965Sjdp				printf ("%s: ", d->name); printf s;}})
7733965Sjdp#define CT_DEBUG2(d,s)	({if (d->chan->debug>1) {\
78218822Sdim				printf ("%s: ", d->name); printf s;}})
79218822Sdim
80218822Sdim#define CT_LOCK_NAME	"ctX"
81218822Sdim
82218822Sdimstatic	int	ct_mpsafenet = 1;
83218822SdimTUNABLE_INT("debug.ctau.mpsafenet", &ct_mpsafenet);
84218822SdimSYSCTL_NODE(_debug, OID_AUTO, ctau, CTLFLAG_RD, 0, "Cronyx Tau-ISA Adapters");
85218822SdimSYSCTL_INT(_debug_ctau, OID_AUTO, mpsafenet, CTLFLAG_RD, &ct_mpsafenet, 0,
86218822Sdim	"Enable/disable MPSAFE network support for Cronyx Tau-ISA Adapters");
87218822Sdim
88218822Sdim#define CT_LOCK(_bd)		do { \
89218822Sdim				    if (ct_mpsafenet) \
90218822Sdim					mtx_lock (&(_bd)->ct_mtx); \
91218822Sdim				} while (0)
92218822Sdim#define CT_UNLOCK(_bd)		do { \
93218822Sdim				    if (ct_mpsafenet) \
9433965Sjdp					mtx_unlock (&(_bd)->ct_mtx); \
9533965Sjdp				} while (0)
9633965Sjdp#define CT_LOCK_ASSERT(_bd)	do { \
9733965Sjdp				    if (ct_mpsafenet) \
98218822Sdim					mtx_assert (&(_bd)->ct_mtx, MA_OWNED); \
9933965Sjdp				} while (0)
10033965Sjdp
10133965Sjdpstatic void ct_identify		__P((driver_t *, device_t));
10233965Sjdpstatic int ct_probe		__P((device_t));
10333965Sjdpstatic int ct_attach		__P((device_t));
10489857Sobrienstatic int ct_detach		__P((device_t));
10589857Sobrien
10689857Sobrienstatic device_method_t ct_isa_methods [] = {
10789857Sobrien	DEVMETHOD(device_identify,	ct_identify),
10889857Sobrien	DEVMETHOD(device_probe,		ct_probe),
10989857Sobrien	DEVMETHOD(device_attach,	ct_attach),
11089857Sobrien	DEVMETHOD(device_detach,	ct_detach),
11189857Sobrien	{0, 0}
11289857Sobrien};
11389857Sobrien
11489857Sobrientypedef struct _ct_dma_mem_t {
11589857Sobrien	unsigned long	phys;
11689857Sobrien	void		*virt;
11789857Sobrien	size_t		size;
11889857Sobrien	bus_dma_tag_t	dmat;
11989857Sobrien	bus_dmamap_t	mapp;
12089857Sobrien} ct_dma_mem_t;
12189857Sobrien
12289857Sobrientypedef struct _drv_t {
12389857Sobrien	char name [8];
12489857Sobrien	ct_chan_t *chan;
12589857Sobrien	ct_board_t *board;
12689857Sobrien	struct _bdrv_t *bd;
12789857Sobrien	ct_dma_mem_t dmamem;
12889857Sobrien	int running;
12933965Sjdp#ifdef NETGRAPH
13033965Sjdp	char	nodename [NG_NODELEN+1];
131218822Sdim	hook_p	hook;
13277298Sobrien	hook_p	debug_hook;
13333965Sjdp	node_p	node;
13433965Sjdp	struct	ifqueue queue;
13533965Sjdp	struct	ifqueue hi_queue;
13633965Sjdp	short	timeout;
13733965Sjdp	struct	callout timeout_handle;
13833965Sjdp#else
139218822Sdim	struct	ifqueue queue;
14033965Sjdp	struct	sppp pp;
14133965Sjdp#endif
14233965Sjdp	struct	cdev *devt;
14333965Sjdp} drv_t;
14433965Sjdp
14533965Sjdptypedef struct _bdrv_t {
14689857Sobrien	ct_board_t	*board;
14789857Sobrien	struct resource	*base_res;
14889857Sobrien	struct resource	*drq_res;
14989857Sobrien	struct resource	*irq_res;
15089857Sobrien	int		base_rid;
15189857Sobrien	int		drq_rid;
15289857Sobrien	int		irq_rid;
15389857Sobrien	void		*intrhand;
15489857Sobrien	drv_t		channel [NCHAN];
15589857Sobrien	struct mtx	ct_mtx;
15689857Sobrien} bdrv_t;
15789857Sobrien
15889857Sobrienstatic driver_t ct_isa_driver = {
15989857Sobrien	"ct",
16089857Sobrien	ct_isa_methods,
16189857Sobrien	sizeof (bdrv_t),
16289857Sobrien};
16389857Sobrien
16489857Sobrienstatic devclass_t ct_devclass;
16589857Sobrien
16689857Sobrienstatic void ct_receive (ct_chan_t *c, char *data, int len);
16789857Sobrienstatic void ct_transmit (ct_chan_t *c, void *attachment, int len);
16889857Sobrienstatic void ct_error (ct_chan_t *c, int data);
16989857Sobrienstatic void ct_up (drv_t *d);
17089857Sobrienstatic void ct_start (drv_t *d);
17133965Sjdpstatic void ct_down (drv_t *d);
17233965Sjdpstatic void ct_watchdog (drv_t *d);
17389857Sobrien#ifdef NETGRAPH
17477298Sobrienextern struct ng_type typestruct;
17533965Sjdp#else
17633965Sjdpstatic void ct_ifstart (struct ifnet *ifp);
17733965Sjdpstatic void ct_tlf (struct sppp *sp);
17833965Sjdpstatic void ct_tls (struct sppp *sp);
17933965Sjdpstatic void ct_ifwatchdog (struct ifnet *ifp);
18033965Sjdpstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
181218822Sdimstatic void ct_initialize (void *softc);
18233965Sjdp#endif
18333965Sjdp
18433965Sjdpstatic ct_board_t *adapter [NCTAU];
18533965Sjdpstatic drv_t *channel [NCTAU*NCHAN];
18677298Sobrienstatic struct callout led_timo [NCTAU];
18789857Sobrienstatic struct callout timeout_handle;
18889857Sobrien
18977298Sobrien/*
19078828Sobrien * Print the mbuf chain, for debug purposes only.
19133965Sjdp */
19233965Sjdpstatic void printmbuf (struct mbuf *m)
19389857Sobrien{
19489857Sobrien	printf ("mbuf:");
19589857Sobrien	for (; m; m=m->m_next) {
19689857Sobrien		if (m->m_flags & M_PKTHDR)
19789857Sobrien			printf (" HDR %d:", m->m_pkthdr.len);
19889857Sobrien		if (m->m_flags & M_EXT)
19989857Sobrien			printf (" EXT:");
20089857Sobrien		printf (" %d", m->m_len);
20177298Sobrien	}
20289857Sobrien	printf ("\n");
20389857Sobrien}
20433965Sjdp
20577298Sobrien/*
20689857Sobrien * Make an mbuf from data.
20789857Sobrien */
20833965Sjdpstatic struct mbuf *makembuf (void *buf, u_int len)
20989857Sobrien{
21089857Sobrien	struct mbuf *m;
21189857Sobrien
21289857Sobrien	MGETHDR (m, M_DONTWAIT, MT_DATA);
21333965Sjdp	if (! m)
214130561Sobrien		return 0;
21589857Sobrien	MCLGET (m, M_DONTWAIT);
21689857Sobrien	if (! (m->m_flags & M_EXT)) {
21789857Sobrien		m_freem (m);
21889857Sobrien		return 0;
21989857Sobrien	}
22089857Sobrien	m->m_pkthdr.len = m->m_len = len;
22189857Sobrien	bcopy (buf, mtod (m, caddr_t), len);
22289857Sobrien	return m;
22389857Sobrien}
22489857Sobrien
22589857Sobrienstatic void ct_timeout (void *arg)
22689857Sobrien{
22789857Sobrien	drv_t *d;
22889857Sobrien	int s, i, k;
22989857Sobrien
23089857Sobrien	for (i = 0; i < NCTAU; ++i) {
23189857Sobrien		if (adapter[i] == NULL)
23289857Sobrien			continue;
23389857Sobrien		for (k = 0; k < NCHAN; k++) {
23489857Sobrien			d = channel[i * NCHAN + k];
23533965Sjdp			if (! d)
23633965Sjdp				continue;
23789857Sobrien			if (d->chan->mode != M_G703)
23889857Sobrien				continue;
23933965Sjdp			s = splimp ();
24033965Sjdp			CT_LOCK ((bdrv_t *)d->bd);
241218822Sdim			ct_g703_timer (d->chan);
24277298Sobrien			CT_UNLOCK ((bdrv_t *)d->bd);
24333965Sjdp			splx (s);
24433965Sjdp		}
24533965Sjdp	}
24633965Sjdp
24733965Sjdp	callout_reset (&timeout_handle, hz, ct_timeout, 0);
24833965Sjdp}
249218822Sdim
25033965Sjdpstatic void ct_led_off (void *arg)
25133965Sjdp{
25233965Sjdp	ct_board_t *b = arg;
25333965Sjdp	bdrv_t *bd = ((drv_t *)b->chan->sys)->bd;
254130561Sobrien	int s = splimp ();
255130561Sobrien
25677298Sobrien	CT_LOCK (bd);
25789857Sobrien	ct_led (b, 0);
25889857Sobrien	CT_UNLOCK (bd);
25989857Sobrien	splx (s);
26089857Sobrien}
26189857Sobrien
26289857Sobrien/*
26389857Sobrien * Activate interupt handler from DDK.
26489857Sobrien */
26589857Sobrienstatic void ct_intr (void *arg)
26689857Sobrien{
26777298Sobrien	bdrv_t *bd = arg;
26889857Sobrien	ct_board_t *b = bd->board;
26989857Sobrien#ifndef NETGRAPH
27033965Sjdp	int i;
27177298Sobrien#endif
27289857Sobrien	int s = splimp ();
27389857Sobrien
27433965Sjdp	CT_LOCK (bd);
27589857Sobrien	/* Turn LED on. */
27689857Sobrien	ct_led (b, 1);
27789857Sobrien
27889857Sobrien	ct_int_handler (b);
27933965Sjdp
280130561Sobrien	/* Turn LED off 50 msec later. */
28189857Sobrien	callout_reset (&led_timo[b->num], hz/20, ct_led_off, b);
28289857Sobrien	CT_UNLOCK (bd);
28389857Sobrien	splx (s);
28489857Sobrien
28589857Sobrien#ifndef NETGRAPH
28689857Sobrien	/* Pass packets in a lock-free state */
28789857Sobrien	for (i = 0; i < NCHAN && b->chan[i].type; i++) {
28889857Sobrien		drv_t *d = b->chan[i].sys;
28989857Sobrien		struct mbuf *m;
29089857Sobrien		while (_IF_QLEN(&d->queue)) {
29189857Sobrien			IF_DEQUEUE (&d->queue,m);
29289857Sobrien			if (!m)
29389857Sobrien				continue;
29489857Sobrien			sppp_input (&d->pp.pp_if, m);
29589857Sobrien		}
29689857Sobrien	}
29789857Sobrien#endif
29889857Sobrien}
29989857Sobrien
30089857Sobrienstatic int probe_irq (ct_board_t *b, int irq)
30189857Sobrien{
30289857Sobrien	int mask, busy, cnt;
30389857Sobrien
30489857Sobrien	/* Clear pending irq, if any. */
30533965Sjdp	ct_probe_irq (b, -irq);
30689857Sobrien	DELAY (100);
30789857Sobrien	for (cnt=0; cnt<5; ++cnt) {
30833965Sjdp		/* Get the mask of pending irqs, assuming they are busy.
30933965Sjdp		 * Activate the adapter on given irq. */
310218822Sdim		busy = ct_probe_irq (b, irq);
31177298Sobrien		DELAY (1000);
31233965Sjdp
31333965Sjdp		/* Get the mask of active irqs.
31433965Sjdp		 * Deactivate our irq. */
31533965Sjdp		mask = ct_probe_irq (b, -irq);
31633965Sjdp		DELAY (100);
31733965Sjdp		if ((mask & ~busy) == 1 << irq) {
318218822Sdim			ct_probe_irq (b, 0);
31933965Sjdp			/* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
32033965Sjdp				b->num, irq, mask, busy); */
32133965Sjdp			return 1;
32233965Sjdp		}
32333965Sjdp	}
324218822Sdim	/* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
32533965Sjdp		b->num, irq, mask, busy); */
32689857Sobrien	ct_probe_irq (b, 0);
32789857Sobrien	return 0;
32889857Sobrien}
32989857Sobrien
33089857Sobrienstatic	short porttab [] = {
33189857Sobrien		0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
33289857Sobrien		0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
33389857Sobrien	};
33489857Sobrienstatic	char dmatab [] = { 7, 6, 5, 0 };
33589857Sobrienstatic	char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
33689857Sobrien
33789857Sobrienstatic int ct_is_free_res (device_t dev, int rid, int type, u_long start,
33889857Sobrien	u_long end, u_long count)
33989857Sobrien{
34033965Sjdp	struct resource *res;
34177298Sobrien
342130561Sobrien	if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
343130561Sobrien	    RF_ALLOCATED)))
344130561Sobrien		return 0;
345130561Sobrien
346130561Sobrien	bus_release_resource (dev, type, rid, res);
34789857Sobrien
34833965Sjdp	return 1;
34933965Sjdp}
35033965Sjdp
35133965Sjdpstatic void ct_identify (driver_t *driver, device_t dev)
35233965Sjdp{
35333965Sjdp	u_long iobase, rescount;
35433965Sjdp	int devcount;
35533965Sjdp	device_t *devices;
35633965Sjdp	device_t child;
35733965Sjdp	devclass_t my_devclass;
35833965Sjdp	int i, k;
35933965Sjdp
36033965Sjdp	if ((my_devclass = devclass_find ("ct")) == NULL)
36133965Sjdp		return;
36233965Sjdp
36333965Sjdp	devclass_get_devices (my_devclass, &devices, &devcount);
36433965Sjdp
36533965Sjdp	if (devcount == 0) {
36633965Sjdp		/* We should find all devices by our self. We could alter other
36733965Sjdp		 * devices, but we don't have a choise
36889857Sobrien		 */
36977298Sobrien		for (i = 0; (iobase = porttab [i]) != 0; i++) {
37033965Sjdp			if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
37133965Sjdp			    iobase, iobase + NPORT, NPORT))
372218822Sdim				continue;
37377298Sobrien			if (ct_probe_board (iobase, -1, -1) == 0)
37433965Sjdp				continue;
37533965Sjdp
37633965Sjdp			devcount++;
37733965Sjdp			child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct",
37833965Sjdp			    -1);
37933965Sjdp
380218822Sdim			if (child == NULL)
38133965Sjdp				return;
38233965Sjdp
38333965Sjdp			device_set_desc_copy (child, "Cronyx Tau-ISA");
38433965Sjdp			device_set_driver (child, driver);
385130561Sobrien			bus_set_resource (child, SYS_RES_IOPORT, 0,
386130561Sobrien			    iobase, NPORT);
38777298Sobrien
38889857Sobrien			if (devcount >= NCTAU)
38989857Sobrien				break;
39089857Sobrien		}
39189857Sobrien	} else {
39289857Sobrien		static	short porttab [] = {
39389857Sobrien			0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
39489857Sobrien			0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
39589857Sobrien		};
39689857Sobrien		/* Lets check user choise.
39789857Sobrien		 */
39889857Sobrien		for (k = 0; k < devcount; k++) {
39989857Sobrien			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
40089857Sobrien			    &iobase, &rescount) != 0)
40189857Sobrien				continue;
40233965Sjdp
40377298Sobrien			for (i = 0; porttab [i] != 0; i++) {
40489857Sobrien				if (porttab [i] != iobase)
40589857Sobrien					continue;
40633965Sjdp
40733965Sjdp				if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
40833965Sjdp				    iobase, iobase + NPORT, NPORT))
40933965Sjdp					continue;
41033965Sjdp
41133965Sjdp				if (ct_probe_board (iobase, -1, -1) == 0)
41233965Sjdp					continue;
41333965Sjdp				porttab [i] = -1;
41433965Sjdp				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
41533965Sjdp				break;
41633965Sjdp			}
41733965Sjdp			if (porttab [i] == 0) {
41833965Sjdp				device_delete_child (
41933965Sjdp				    device_get_parent (devices[k]),
42033965Sjdp				    devices [k]);
42133965Sjdp				devices[k] = 0;
42233965Sjdp				continue;
42333965Sjdp			}
42433965Sjdp		}
42533965Sjdp		for (k = 0; k < devcount; k++) {
42633965Sjdp			if (devices[k] == 0)
42733965Sjdp				continue;
42889857Sobrien			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
42977298Sobrien			    &iobase, &rescount) == 0)
43033965Sjdp				continue;
43133965Sjdp			for (i = 0; (iobase = porttab [i]) != 0; i++) {
432218822Sdim				if (porttab [i] == -1)
43377298Sobrien					continue;
43433965Sjdp				if (!ct_is_free_res (devices[k], 0, SYS_RES_IOPORT,
43533965Sjdp				    iobase, iobase + NPORT, NPORT))
43633965Sjdp					continue;
43733965Sjdp				if (ct_probe_board (iobase, -1, -1) == 0)
43833965Sjdp					continue;
43933965Sjdp
440218822Sdim				bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
44133965Sjdp				    iobase, NPORT);
44233965Sjdp				porttab [i] = -1;
44333965Sjdp				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
44433965Sjdp				break;
44577298Sobrien			}
44689857Sobrien			if (porttab [i] == 0) {
44789857Sobrien				device_delete_child (
44833965Sjdp				    device_get_parent (devices[k]),
449130561Sobrien				    devices [k]);
450130561Sobrien			}
451130561Sobrien		}
452130561Sobrien		free (devices, M_TEMP);
45333965Sjdp	}
454130561Sobrien
455130561Sobrien	return;
456130561Sobrien}
457130561Sobrien
458130561Sobrienstatic int ct_probe (device_t dev)
459130561Sobrien{
460130561Sobrien	int unit = device_get_unit (dev);
461130561Sobrien	u_long iobase, rescount;
462130561Sobrien
463130561Sobrien	if (!device_get_desc (dev) ||
464130561Sobrien	    strcmp (device_get_desc (dev), "Cronyx Tau-ISA"))
465130561Sobrien		return ENXIO;
466130561Sobrien
467130561Sobrien/*	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/
468130561Sobrien	if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
469130561Sobrien		printf ("ct%d: Couldn't get IOPORT\n", unit);
470130561Sobrien		return ENXIO;
471130561Sobrien	}
472130561Sobrien
473130561Sobrien	if (!ct_is_free_res (dev, 0, SYS_RES_IOPORT,
474130561Sobrien	    iobase, iobase + NPORT, NPORT)) {
475130561Sobrien		printf ("ct%d: Resource IOPORT isn't free\n", unit);
476130561Sobrien		return ENXIO;
477130561Sobrien	}
478130561Sobrien
479130561Sobrien	if (!ct_probe_board (iobase, -1, -1)) {
480130561Sobrien		printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
481130561Sobrien		return ENXIO;
482130561Sobrien	}
483130561Sobrien
484130561Sobrien	return 0;
48533965Sjdp}
486218822Sdim
48777298Sobrienextern struct cdevsw ct_cdevsw;
48833965Sjdp
48933965Sjdpstatic void
49033965Sjdpct_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error)
49133965Sjdp{
49233965Sjdp	unsigned long *addr;
49333965Sjdp
494218822Sdim	if (error)
49533965Sjdp		return;
49633965Sjdp
49733965Sjdp	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
49833965Sjdp	addr = arg;
499130561Sobrien	*addr = segs->ds_addr;
500130561Sobrien}
50177298Sobrien
50289857Sobrienstatic int
50389857Sobrienct_bus_dma_mem_alloc (int bnum, int cnum, ct_dma_mem_t *dmem)
50433965Sjdp{
505130561Sobrien	int error;
506130561Sobrien
507130561Sobrien	error = bus_dma_tag_create (NULL, 16, 0, BUS_SPACE_MAXADDR_24BIT,
508130561Sobrien		BUS_SPACE_MAXADDR, NULL, NULL, dmem->size, 1,
509130561Sobrien		dmem->size, 0, NULL, NULL, &dmem->dmat);
510130561Sobrien	if (error) {
511130561Sobrien		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
512130561Sobrien		else		printf ("ct%d: ", bnum);
513130561Sobrien		printf ("couldn't allocate tag for dma memory\n");
514130561Sobrien 		return 0;
515130561Sobrien	}
516130561Sobrien	error = bus_dmamem_alloc (dmem->dmat, (void **)&dmem->virt,
517130561Sobrien		BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dmem->mapp);
518130561Sobrien	if (error) {
519130561Sobrien		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
520130561Sobrien		else		printf ("ct%d: ", bnum);
521130561Sobrien		printf ("couldn't allocate mem for dma memory\n");
522130561Sobrien		bus_dma_tag_destroy (dmem->dmat);
523130561Sobrien 		return 0;
524130561Sobrien	}
525130561Sobrien	error = bus_dmamap_load (dmem->dmat, dmem->mapp, dmem->virt,
526130561Sobrien		dmem->size, ct_bus_dmamap_addr, &dmem->phys, 0);
527130561Sobrien	if (error) {
528130561Sobrien		if (cnum >= 0)	printf ("ct%d-%d: ", bnum, cnum);
529130561Sobrien		else		printf ("ct%d: ", bnum);
530130561Sobrien		printf ("couldn't load mem map for dma memory\n");
531130561Sobrien		bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
532130561Sobrien		bus_dma_tag_destroy (dmem->dmat);
533130561Sobrien 		return 0;
53433965Sjdp	}
53533965Sjdp	return 1;
536218822Sdim}
53777298Sobrien
53833965Sjdpstatic void
53933965Sjdpct_bus_dma_mem_free (ct_dma_mem_t *dmem)
54033965Sjdp{
54133965Sjdp	bus_dmamap_unload (dmem->dmat, dmem->mapp);
54233965Sjdp	bus_dmamem_free (dmem->dmat, dmem->virt, dmem->mapp);
54333965Sjdp	bus_dma_tag_destroy (dmem->dmat);
544218822Sdim}
54533965Sjdp
54633965Sjdp/*
54733965Sjdp * The adapter is present, initialize the driver structures.
54833965Sjdp */
54977298Sobrienstatic int ct_attach (device_t dev)
550130561Sobrien{
551130561Sobrien	bdrv_t *bd = device_get_softc (dev);
552130561Sobrien	u_long iobase, drq, irq, rescount;
553130561Sobrien	int unit = device_get_unit (dev);
554130561Sobrien	char *ct_ln = CT_LOCK_NAME;
555130561Sobrien	ct_board_t *b;
556130561Sobrien	ct_chan_t *c;
557130561Sobrien	drv_t *d;
558130561Sobrien	int i;
559130561Sobrien	int s;
560130561Sobrien
561130561Sobrien	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));
562130561Sobrien
56333965Sjdp	bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
56433965Sjdp	bd->base_rid = 0;
56577298Sobrien	bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
566130561Sobrien		iobase, iobase + NPORT, NPORT, RF_ACTIVE);
56733965Sjdp	if (! bd->base_res) {
56877298Sobrien		printf ("ct%d: cannot alloc base address\n", unit);
569130561Sobrien		return ENXIO;
57033965Sjdp	}
57133965Sjdp
57233965Sjdp	if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
57333965Sjdp		for (i = 0; (drq = dmatab [i]) != 0; i++) {
57433965Sjdp			if (!ct_is_free_res (dev, 0, SYS_RES_DRQ,
575218822Sdim			    drq, drq + 1, 1))
57677298Sobrien				continue;
57733965Sjdp			bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
57833965Sjdp			break;
57933965Sjdp		}
58033965Sjdp
58133965Sjdp		if (dmatab[i] == 0) {
58233965Sjdp			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
583218822Sdim				bd->base_res);
58433965Sjdp			printf ("ct%d: Couldn't get DRQ\n", unit);
58533965Sjdp			return ENXIO;
58633965Sjdp		}
58733965Sjdp	}
588130561Sobrien
589130561Sobrien	bd->drq_rid = 0;
59077298Sobrien	bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
591130561Sobrien		drq, drq + 1, 1, RF_ACTIVE);
592130561Sobrien	if (! bd->drq_res) {
593130561Sobrien		printf ("ct%d: cannot allocate drq\n", unit);
594130561Sobrien		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
595130561Sobrien			bd->base_res);
596130561Sobrien		return ENXIO;
597130561Sobrien	}
59877298Sobrien
599130561Sobrien	if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
600130561Sobrien		for (i = 0; (irq = irqtab [i]) != 0; i++) {
60133965Sjdp			if (!ct_is_free_res (dev, 0, SYS_RES_IRQ,
602130561Sobrien			    irq, irq + 1, 1))
603130561Sobrien				continue;
604130561Sobrien			bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
605130561Sobrien			break;
606130561Sobrien		}
607130561Sobrien
608130561Sobrien		if (irqtab[i] == 0) {
60977298Sobrien			bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
610130561Sobrien				bd->drq_res);
611130561Sobrien			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
61233965Sjdp				bd->base_res);
613130561Sobrien			printf ("ct%d: Couldn't get IRQ\n", unit);
61433965Sjdp			return ENXIO;
61577298Sobrien		}
61689857Sobrien	}
61733965Sjdp
61877298Sobrien	bd->irq_rid = 0;
61989857Sobrien	bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
62033965Sjdp		irq, irq + 1, 1, RF_ACTIVE);
62133965Sjdp	if (! bd->irq_res) {
62233965Sjdp		printf ("ct%d: Couldn't allocate irq\n", unit);
62333965Sjdp		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
62433965Sjdp			bd->drq_res);
625218822Sdim		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
62677298Sobrien			bd->base_res);
62733965Sjdp		return ENXIO;
62833965Sjdp	}
62933965Sjdp
63033965Sjdp	b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
63133965Sjdp	if (!b) {
63233965Sjdp		printf ("ct:%d: Couldn't allocate memory\n", unit);
633218822Sdim		return (ENXIO);
63433965Sjdp	}
63533965Sjdp	adapter[unit] = b;
63633965Sjdp	bzero (b, sizeof(ct_board_t));
63789857Sobrien
63833965Sjdp	if (! ct_open_board (b, unit, iobase, irq, drq)) {
63933965Sjdp		printf ("ct%d: error loading firmware\n", unit);
640218822Sdim		free (b, M_DEVBUF);
64177298Sobrien		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
64233965Sjdp			bd->irq_res);
64333965Sjdp		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
64433965Sjdp			bd->drq_res);
64533965Sjdp		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
64633965Sjdp			bd->base_res);
64733965Sjdp 		return ENXIO;
648218822Sdim	}
64933965Sjdp
65033965Sjdp	bd->board = b;
65133965Sjdp
65289857Sobrien	ct_ln[2] = '0' + unit;
65333965Sjdp	mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
65433965Sjdp	if (! probe_irq (b, irq)) {
655218822Sdim		printf ("ct%d: irq %ld not functional\n", unit, irq);
65677298Sobrien		bd->board = 0;
65733965Sjdp		adapter [unit] = 0;
65833965Sjdp		free (b, M_DEVBUF);
65933965Sjdp		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
66033965Sjdp			bd->irq_res);
66133965Sjdp		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
66233965Sjdp			bd->drq_res);
663218822Sdim		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
66433965Sjdp			bd->base_res);
66533965Sjdp		mtx_destroy (&bd->ct_mtx);
66633965Sjdp 		return ENXIO;
66733965Sjdp	}
66833965Sjdp
66933965Sjdp	callout_init (&led_timo[unit], ct_mpsafenet ? CALLOUT_MPSAFE : 0);
67033965Sjdp	s = splimp ();
67133965Sjdp	if (bus_setup_intr (dev, bd->irq_res,
67233965Sjdp			   INTR_TYPE_NET|(ct_mpsafenet?INTR_MPSAFE:0),
67333965Sjdp			   ct_intr, bd, &bd->intrhand)) {
67433965Sjdp		printf ("ct%d: Can't setup irq %ld\n", unit, irq);
67533965Sjdp		bd->board = 0;
67633965Sjdp		adapter [unit] = 0;
67733965Sjdp		free (b, M_DEVBUF);
67833965Sjdp		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
67933965Sjdp			bd->irq_res);
68033965Sjdp		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
68133965Sjdp			bd->drq_res);
68233965Sjdp		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
68333965Sjdp			bd->base_res);
68433965Sjdp		mtx_destroy (&bd->ct_mtx);
68533965Sjdp		splx (s);
68633965Sjdp 		return ENXIO;
68733965Sjdp	}
68833965Sjdp
68933965Sjdp	CT_LOCK (bd);
69089857Sobrien	ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc);
69133965Sjdp	ct_setup_board (b, 0, 0, 0);
69233965Sjdp	CT_UNLOCK (bd);
693218822Sdim
69477298Sobrien	printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name,
69533965Sjdp		b->osc == 20000000 ? "20" : "16.384");
69633965Sjdp
69733965Sjdp	for (c = b->chan; c < b->chan + NCHAN; ++c) {
69833965Sjdp		d = &bd->channel[c->num];
69933965Sjdp		d->dmamem.size = sizeof(ct_buf_t);
70033965Sjdp		if (! ct_bus_dma_mem_alloc (unit, c->num, &d->dmamem))
701218822Sdim			continue;
70233965Sjdp		d->board = b;
70333965Sjdp		d->chan = c;
70433965Sjdp		d->bd = bd;
70533965Sjdp		c->sys = d;
706130561Sobrien		channel [b->num*NCHAN + c->num] = d;
707130561Sobrien		sprintf (d->name, "ct%d.%d", b->num, c->num);
70833965Sjdp
70933965Sjdp#ifdef NETGRAPH
71033965Sjdp		if (ng_make_node_common (&typestruct, &d->node) != 0) {
71133965Sjdp			printf ("%s: cannot make common node\n", d->name);
71233965Sjdp			channel [b->num*NCHAN + c->num] = 0;
71333965Sjdp			c->sys = 0;
71433965Sjdp			ct_bus_dma_mem_free (&d->dmamem);
71533965Sjdp			continue;
71633965Sjdp		}
71733965Sjdp		NG_NODE_SET_PRIVATE (d->node, d);
71833965Sjdp		sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE,
71933965Sjdp			 c->board->num*NCHAN + c->num);
72033965Sjdp		if (ng_name_node (d->node, d->nodename)) {
72133965Sjdp			printf ("%s: cannot name node\n", d->nodename);
72233965Sjdp			NG_NODE_UNREF (d->node);
72333965Sjdp			channel [b->num*NCHAN + c->num] = 0;
72433965Sjdp			c->sys = 0;
72533965Sjdp			ct_bus_dma_mem_free (&d->dmamem);
72633965Sjdp			continue;
72789857Sobrien		}
72833965Sjdp		d->queue.ifq_maxlen = IFQ_MAXLEN;
72933965Sjdp		d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
730218822Sdim		mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
73177298Sobrien		mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF);
73233965Sjdp		callout_init (&d->timeout_handle,
73333965Sjdp			     ct_mpsafenet ? CALLOUT_MPSAFE : 0);
73433965Sjdp#else /*NETGRAPH*/
73533965Sjdp		d->pp.pp_if.if_softc    = d;
73633965Sjdp		if_initname (&d->pp.pp_if, "ct", b->num * NCHAN + c->num);
73733965Sjdp		d->pp.pp_if.if_mtu	= PP_MTU;
738218822Sdim		d->pp.pp_if.if_flags	= IFF_POINTOPOINT | IFF_MULTICAST;
73933965Sjdp		if (!ct_mpsafenet)
74033965Sjdp			d->pp.pp_if.if_flags |= IFF_NEEDSGIANT;
74133965Sjdp		d->pp.pp_if.if_ioctl	= ct_sioctl;
74233965Sjdp		d->pp.pp_if.if_start	= ct_ifstart;
74333965Sjdp		d->pp.pp_if.if_watchdog	= ct_ifwatchdog;
74489857Sobrien		d->pp.pp_if.if_init	= ct_initialize;
74589857Sobrien		d->queue.ifq_maxlen	= NBUF;
74633965Sjdp		mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
74733965Sjdp		sppp_attach (&d->pp.pp_if);
748218822Sdim		if_attach (&d->pp.pp_if);
74977298Sobrien		d->pp.pp_tlf		= ct_tlf;
75033965Sjdp		d->pp.pp_tls		= ct_tls;
75133965Sjdp		/* If BPF is in the kernel, call the attach for it.
75233965Sjdp		 * Header size is 4 bytes. */
75333965Sjdp		bpfattach (&d->pp.pp_if, DLT_PPP, 4);
75433965Sjdp#endif /*NETGRAPH*/
75533965Sjdp		CT_LOCK (bd);
756218822Sdim		ct_start_chan (c, d->dmamem.virt, d->dmamem.phys);
75733965Sjdp		ct_register_receive (c, &ct_receive);
75833965Sjdp		ct_register_transmit (c, &ct_transmit);
75933965Sjdp		ct_register_error (c, &ct_error);
76033965Sjdp		CT_UNLOCK (bd);
761130561Sobrien		d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
762130561Sobrien				GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num);
76333965Sjdp	}
76489857Sobrien	splx (s);
76589857Sobrien
76633965Sjdp	return 0;
76733965Sjdp}
768218822Sdim
76977298Sobrienstatic int ct_detach (device_t dev)
77033965Sjdp{
77133965Sjdp	bdrv_t *bd = device_get_softc (dev);
772	ct_board_t *b = bd->board;
773	ct_chan_t *c;
774	int s;
775
776	KASSERT (mtx_initialized (&bd->ct_mtx), ("ct mutex not initialized"));
777
778	s = splimp ();
779	CT_LOCK (bd);
780	/* Check if the device is busy (open). */
781	for (c = b->chan; c < b->chan + NCHAN; ++c) {
782		drv_t *d = (drv_t*) c->sys;
783
784		if (!d || !d->chan->type)
785			continue;
786
787		if (d->running) {
788			CT_UNLOCK (bd);
789			splx (s);
790			return EBUSY;
791		}
792	}
793
794	/* Deactivate the timeout routine. */
795	callout_stop (&led_timo[b->num]);
796
797	CT_UNLOCK (bd);
798
799	bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
800	bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
801	bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
802
803	bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
804	bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
805
806	bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res);
807	bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
808
809	CT_LOCK (bd);
810	ct_close_board (b);
811	CT_UNLOCK (bd);
812
813	/* Detach the interfaces, free buffer memory. */
814	for (c = b->chan; c < b->chan + NCHAN; ++c) {
815		drv_t *d = (drv_t*) c->sys;
816
817		if (!d || !d->chan->type)
818			continue;
819
820#ifdef NETGRAPH
821		if (d->node) {
822			ng_rmnode_self (d->node);
823			NG_NODE_UNREF (d->node);
824			d->node = NULL;
825		}
826		mtx_destroy (&d->queue.ifq_mtx);
827		mtx_destroy (&d->hi_queue.ifq_mtx);
828#else
829		/* Detach from the packet filter list of interfaces. */
830		bpfdetach (&d->pp.pp_if);
831
832		/* Detach from the sync PPP list. */
833		sppp_detach (&d->pp.pp_if);
834
835		if_detach (&d->pp.pp_if);
836		IF_DRAIN (&d->queue);
837		mtx_destroy (&d->queue.ifq_mtx);
838#endif
839		destroy_dev (d->devt);
840	}
841
842	CT_LOCK (bd);
843	ct_led_off (b);
844	CT_UNLOCK (bd);
845	callout_drain (&led_timo[b->num]);
846	splx (s);
847
848	s = splimp ();
849	for (c = b->chan; c < b->chan + NCHAN; ++c) {
850		drv_t *d = (drv_t*) c->sys;
851
852		if (!d || !d->chan->type)
853			continue;
854
855		/* Deallocate buffers. */
856		ct_bus_dma_mem_free (&d->dmamem);
857	}
858	bd->board = 0;
859	adapter [b->num] = 0;
860	free (b, M_DEVBUF);
861	splx (s);
862
863	mtx_destroy (&bd->ct_mtx);
864
865	return 0;
866}
867
868#ifndef NETGRAPH
869static void ct_ifstart (struct ifnet *ifp)
870{
871	drv_t *d = ifp->if_softc;
872	bdrv_t *bd = d->bd;
873
874	CT_LOCK (bd);
875	ct_start (d);
876	CT_UNLOCK (bd);
877}
878
879static void ct_ifwatchdog (struct ifnet *ifp)
880{
881	drv_t *d = ifp->if_softc;
882
883	ct_watchdog (d);
884}
885
886static void ct_tlf (struct sppp *sp)
887{
888	drv_t *d = sp->pp_if.if_softc;
889
890	CT_DEBUG (d, ("ct_tlf\n"));
891/*	ct_set_dtr (d->chan, 0);*/
892/*	ct_set_rts (d->chan, 0);*/
893	if (!(d->pp.pp_flags & PP_FR) && !(d->pp.pp_if.if_flags & PP_CISCO))
894		sp->pp_down (sp);
895}
896
897static void ct_tls (struct sppp *sp)
898{
899	drv_t *d = sp->pp_if.if_softc;
900
901	CT_DEBUG (d, ("ct_tls\n"));
902	if (!(d->pp.pp_flags & PP_FR) && !(d->pp.pp_if.if_flags & PP_CISCO))
903		sp->pp_up (sp);
904}
905
906/*
907 * Initialization of interface.
908 * Ii seems to be never called by upper level.
909 */
910static void ct_initialize (void *softc)
911{
912	drv_t *d = softc;
913
914	CT_DEBUG (d, ("ct_initialize\n"));
915}
916
917/*
918 * Process an ioctl request.
919 */
920static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
921{
922	drv_t *d = ifp->if_softc;
923	bdrv_t *bd = d->bd;
924	int error, s, was_up, should_be_up;
925
926	was_up = (ifp->if_flags & IFF_RUNNING) != 0;
927	error = sppp_ioctl (ifp, cmd, data);
928	if (error)
929		return error;
930
931	if (! (ifp->if_flags & IFF_DEBUG))
932		d->chan->debug = 0;
933	else if (! d->chan->debug)
934		d->chan->debug = 1;
935
936	switch (cmd) {
937	default:	   CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
938	case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
939	case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
940	case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
941	case SIOCSIFADDR:  CT_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
942	}
943
944	/* We get here only in case of SIFFLAGS or SIFADDR. */
945	s = splimp ();
946	CT_LOCK (bd);
947	should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
948	if (! was_up && should_be_up) {
949		/* Interface goes up -- start it. */
950		ct_up (d);
951		ct_start (d);
952	} else if (was_up && ! should_be_up) {
953		/* Interface is going down -- stop it. */
954		/* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
955		ct_down (d);
956	}
957	CT_UNLOCK (bd);
958	splx (s);
959	return 0;
960}
961#endif /*NETGRAPH*/
962
963/*
964 * Stop the interface.  Called on splimp().
965 */
966static void ct_down (drv_t *d)
967{
968	int s = splimp ();
969	CT_DEBUG (d, ("ct_down\n"));
970	ct_set_dtr (d->chan, 0);
971	ct_set_rts (d->chan, 0);
972	d->running = 0;
973	splx (s);
974}
975
976/*
977 * Start the interface.  Called on splimp().
978 */
979static void ct_up (drv_t *d)
980{
981	int s = splimp ();
982	CT_DEBUG (d, ("ct_up\n"));
983	ct_set_dtr (d->chan, 1);
984	ct_set_rts (d->chan, 1);
985	d->running = 1;
986	splx (s);
987}
988
989/*
990 * Start output on the (slave) interface.  Get another datagram to send
991 * off of the interface queue, and copy it to the interface
992 * before starting the output.
993 */
994static void ct_send (drv_t *d)
995{
996	struct mbuf *m;
997	u_short len;
998
999	CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
1000
1001	/* No output if the interface is down. */
1002	if (! d->running)
1003		return;
1004
1005	/* No output if the modem is off. */
1006	if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
1007		return;
1008
1009	while (ct_buf_free (d->chan)) {
1010		/* Get the packet to send. */
1011#ifdef NETGRAPH
1012		IF_DEQUEUE (&d->hi_queue, m);
1013		if (! m)
1014			IF_DEQUEUE (&d->queue, m);
1015#else
1016		m = sppp_dequeue (&d->pp.pp_if);
1017#endif
1018		if (! m)
1019			return;
1020#ifndef NETGRAPH
1021		if (d->pp.pp_if.if_bpf)
1022			BPF_MTAP (&d->pp.pp_if, m);
1023#endif
1024		len = m->m_pkthdr.len;
1025		if (! m->m_next)
1026			ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
1027				len, 0);
1028		else {
1029			m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
1030			ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
1031				len, 0);
1032		}
1033		m_freem (m);
1034
1035		/* Set up transmit timeout, if the transmit ring is not empty.
1036		 * Transmit timeout is 10 seconds. */
1037#ifdef NETGRAPH
1038		d->timeout = 10;
1039#else
1040		d->pp.pp_if.if_timer = 10;
1041#endif
1042	}
1043#ifndef NETGRAPH
1044	d->pp.pp_if.if_flags |= IFF_OACTIVE;
1045#endif
1046}
1047
1048/*
1049 * Start output on the interface.
1050 * Always called on splimp().
1051 */
1052static void ct_start (drv_t *d)
1053{
1054	int s = splimp ();
1055
1056	if (d->running) {
1057		if (! d->chan->dtr)
1058			ct_set_dtr (d->chan, 1);
1059		if (! d->chan->rts)
1060			ct_set_rts (d->chan, 1);
1061		ct_send (d);
1062	}
1063
1064	splx (s);
1065}
1066
1067/*
1068 * Handle transmit timeouts.
1069 * Recover after lost transmit interrupts.
1070 * Always called on splimp().
1071 */
1072static void ct_watchdog (drv_t *d)
1073{
1074	bdrv_t *bd = d->bd;
1075	int s;
1076
1077	s = splimp ();
1078	CT_LOCK (bd);
1079	CT_DEBUG (d, ("device timeout\n"));
1080	if (d->running) {
1081		ct_setup_chan (d->chan);
1082		ct_start_chan (d->chan, 0, 0);
1083		ct_set_dtr (d->chan, 1);
1084		ct_set_rts (d->chan, 1);
1085		ct_start (d);
1086	}
1087	CT_UNLOCK (bd);
1088	splx (s);
1089}
1090
1091/*
1092 * Transmit callback function.
1093 */
1094static void ct_transmit (ct_chan_t *c, void *attachment, int len)
1095{
1096	drv_t *d = c->sys;
1097
1098	if (!d)
1099		return;
1100#ifdef NETGRAPH
1101	d->timeout = 0;
1102#else
1103	++d->pp.pp_if.if_opackets;
1104	d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1105	d->pp.pp_if.if_timer = 0;
1106#endif
1107	ct_start (d);
1108}
1109
1110/*
1111 * Process the received packet.
1112 */
1113static void ct_receive (ct_chan_t *c, char *data, int len)
1114{
1115	drv_t *d = c->sys;
1116	struct mbuf *m;
1117#ifdef NETGRAPH
1118	int error;
1119#endif
1120
1121	if (!d || !d->running)
1122		return;
1123
1124	m = makembuf (data, len);
1125	if (! m) {
1126		CT_DEBUG (d, ("no memory for packet\n"));
1127#ifndef NETGRAPH
1128		++d->pp.pp_if.if_iqdrops;
1129#endif
1130		return;
1131	}
1132	if (c->debug > 1)
1133		printmbuf (m);
1134#ifdef NETGRAPH
1135	m->m_pkthdr.rcvif = 0;
1136	NG_SEND_DATA_ONLY (error, d->hook, m);
1137#else
1138	++d->pp.pp_if.if_ipackets;
1139	m->m_pkthdr.rcvif = &d->pp.pp_if;
1140	/* Check if there's a BPF listener on this interface.
1141	 * If so, hand off the raw packet to bpf. */
1142	if (d->pp.pp_if.if_bpf)
1143		BPF_TAP (&d->pp.pp_if, data, len);
1144	IF_ENQUEUE (&d->queue, m);
1145#endif
1146}
1147
1148/*
1149 * Error callback function.
1150 */
1151static void ct_error (ct_chan_t *c, int data)
1152{
1153	drv_t *d = c->sys;
1154
1155	if (!d)
1156		return;
1157
1158	switch (data) {
1159	case CT_FRAME:
1160		CT_DEBUG (d, ("frame error\n"));
1161#ifndef NETGRAPH
1162		++d->pp.pp_if.if_ierrors;
1163#endif
1164		break;
1165	case CT_CRC:
1166		CT_DEBUG (d, ("crc error\n"));
1167#ifndef NETGRAPH
1168		++d->pp.pp_if.if_ierrors;
1169#endif
1170		break;
1171	case CT_OVERRUN:
1172		CT_DEBUG (d, ("overrun error\n"));
1173#ifndef NETGRAPH
1174		++d->pp.pp_if.if_collisions;
1175		++d->pp.pp_if.if_ierrors;
1176#endif
1177		break;
1178	case CT_OVERFLOW:
1179		CT_DEBUG (d, ("overflow error\n"));
1180#ifndef NETGRAPH
1181		++d->pp.pp_if.if_ierrors;
1182#endif
1183		break;
1184	case CT_UNDERRUN:
1185		CT_DEBUG (d, ("underrun error\n"));
1186#ifdef NETGRAPH
1187		d->timeout = 0;
1188#else
1189		++d->pp.pp_if.if_oerrors;
1190		d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1191		d->pp.pp_if.if_timer = 0;
1192#endif
1193		ct_start (d);
1194		break;
1195	default:
1196		CT_DEBUG (d, ("error #%d\n", data));
1197	}
1198}
1199
1200static int ct_open (struct cdev *dev, int oflags, int devtype, struct thread *td)
1201{
1202	drv_t *d;
1203
1204	if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)]))
1205		return ENXIO;
1206
1207	CT_DEBUG2 (d, ("ct_open\n"));
1208	return 0;
1209}
1210
1211static int ct_close (struct cdev *dev, int fflag, int devtype, struct thread *td)
1212{
1213	drv_t *d = channel [minor(dev)];
1214
1215	if (!d)
1216		return 0;
1217
1218	CT_DEBUG2 (d, ("ct_close\n"));
1219	return 0;
1220}
1221
1222static int ct_modem_status (ct_chan_t *c)
1223{
1224	drv_t *d = c->sys;
1225	bdrv_t *bd;
1226	int status, s;
1227
1228	if (!d)
1229		return 0;
1230
1231	bd = d->bd;
1232
1233	status = d->running ? TIOCM_LE : 0;
1234	s = splimp ();
1235	CT_LOCK (bd);
1236	if (ct_get_cd  (c)) status |= TIOCM_CD;
1237	if (ct_get_cts (c)) status |= TIOCM_CTS;
1238	if (ct_get_dsr (c)) status |= TIOCM_DSR;
1239	if (c->dtr)	    status |= TIOCM_DTR;
1240	if (c->rts)	    status |= TIOCM_RTS;
1241	CT_UNLOCK (bd);
1242	splx (s);
1243	return status;
1244}
1245
1246/*
1247 * Process an ioctl request on /dev/cronyx/ctauN.
1248 */
1249static int ct_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1250{
1251	drv_t *d = channel [minor (dev)];
1252	bdrv_t *bd;
1253	ct_chan_t *c;
1254	struct serial_statistics *st;
1255	struct e1_statistics *opte1;
1256	int error, s;
1257	char mask[16];
1258
1259	if (!d || !d->chan)
1260		return 0;
1261
1262	bd = d->bd;
1263	c = d->chan;
1264
1265	switch (cmd) {
1266	case SERIAL_GETREGISTERED:
1267		bzero (mask, sizeof(mask));
1268		for (s=0; s<NCTAU*NCHAN; ++s)
1269			if (channel [s])
1270				mask [s/8] |= 1 << (s & 7);
1271		bcopy (mask, data, sizeof (mask));
1272		return 0;
1273
1274#ifndef NETGRAPH
1275	case SERIAL_GETPROTO:
1276		strcpy ((char*)data, (d->pp.pp_flags & PP_FR) ? "fr" :
1277			(d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp");
1278		return 0;
1279
1280	case SERIAL_SETPROTO:
1281		/* Only for superuser! */
1282		error = suser (td);
1283		if (error)
1284			return error;
1285		if (d->pp.pp_if.if_flags & IFF_RUNNING)
1286			return EBUSY;
1287		if (! strcmp ("cisco", (char*)data)) {
1288			d->pp.pp_flags &= ~(PP_FR);
1289			d->pp.pp_flags |= PP_KEEPALIVE;
1290			d->pp.pp_if.if_flags |= PP_CISCO;
1291		} else if (! strcmp ("fr", (char*)data)) {
1292			d->pp.pp_if.if_flags &= ~(PP_CISCO);
1293			d->pp.pp_flags |= PP_FR | PP_KEEPALIVE;
1294		} else if (! strcmp ("ppp", (char*)data)) {
1295			d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1296			d->pp.pp_if.if_flags &= ~(PP_CISCO);
1297		} else
1298			return EINVAL;
1299		return 0;
1300
1301	case SERIAL_GETKEEPALIVE:
1302		if ((d->pp.pp_flags & PP_FR) ||
1303			(d->pp.pp_if.if_flags & PP_CISCO))
1304			return EINVAL;
1305		*(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0;
1306		return 0;
1307
1308	case SERIAL_SETKEEPALIVE:
1309		/* Only for superuser! */
1310		error = suser (td);
1311		if (error)
1312			return error;
1313		if ((d->pp.pp_flags & PP_FR) ||
1314			(d->pp.pp_if.if_flags & PP_CISCO))
1315			return EINVAL;
1316		if (*(int*)data)
1317			d->pp.pp_flags |= PP_KEEPALIVE;
1318		else
1319			d->pp.pp_flags &= ~PP_KEEPALIVE;
1320		return 0;
1321#endif /*NETGRAPH*/
1322
1323	case SERIAL_GETMODE:
1324		*(int*)data = SERIAL_HDLC;
1325		return 0;
1326
1327	case SERIAL_GETCFG:
1328		if (c->mode == M_HDLC)
1329			return EINVAL;
1330		switch (ct_get_config (c->board)) {
1331		default:    *(char*)data = 'a'; break;
1332		case CFG_B: *(char*)data = 'b'; break;
1333		case CFG_C: *(char*)data = 'c'; break;
1334		}
1335		return 0;
1336
1337	case SERIAL_SETCFG:
1338		/* Only for superuser! */
1339		error = suser (td);
1340		if (error)
1341			return error;
1342		if (c->mode == M_HDLC)
1343			return EINVAL;
1344		s = splimp ();
1345		CT_LOCK (bd);
1346		switch (*(char*)data) {
1347		case 'a': ct_set_config (c->board, CFG_A); break;
1348		case 'b': ct_set_config (c->board, CFG_B); break;
1349		case 'c': ct_set_config (c->board, CFG_C); break;
1350		}
1351		CT_UNLOCK (bd);
1352		splx (s);
1353		return 0;
1354
1355	case SERIAL_GETSTAT:
1356		st = (struct serial_statistics*) data;
1357		st->rintr  = c->rintr;
1358		st->tintr  = c->tintr;
1359		st->mintr  = c->mintr;
1360		st->ibytes = c->ibytes;
1361		st->ipkts  = c->ipkts;
1362		st->ierrs  = c->ierrs;
1363		st->obytes = c->obytes;
1364		st->opkts  = c->opkts;
1365		st->oerrs  = c->oerrs;
1366		return 0;
1367
1368	case SERIAL_GETESTAT:
1369		opte1 = (struct e1_statistics*)data;
1370		opte1->status	   = c->status;
1371		opte1->cursec	   = c->cursec;
1372		opte1->totsec	   = c->totsec + c->cursec;
1373
1374		opte1->currnt.bpv   = c->currnt.bpv;
1375		opte1->currnt.fse   = c->currnt.fse;
1376		opte1->currnt.crce  = c->currnt.crce;
1377		opte1->currnt.rcrce = c->currnt.rcrce;
1378		opte1->currnt.uas   = c->currnt.uas;
1379		opte1->currnt.les   = c->currnt.les;
1380		opte1->currnt.es    = c->currnt.es;
1381		opte1->currnt.bes   = c->currnt.bes;
1382		opte1->currnt.ses   = c->currnt.ses;
1383		opte1->currnt.oofs  = c->currnt.oofs;
1384		opte1->currnt.css   = c->currnt.css;
1385		opte1->currnt.dm    = c->currnt.dm;
1386
1387		opte1->total.bpv   = c->total.bpv   + c->currnt.bpv;
1388		opte1->total.fse   = c->total.fse   + c->currnt.fse;
1389		opte1->total.crce  = c->total.crce  + c->currnt.crce;
1390		opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1391		opte1->total.uas   = c->total.uas   + c->currnt.uas;
1392		opte1->total.les   = c->total.les   + c->currnt.les;
1393		opte1->total.es	   = c->total.es    + c->currnt.es;
1394		opte1->total.bes   = c->total.bes   + c->currnt.bes;
1395		opte1->total.ses   = c->total.ses   + c->currnt.ses;
1396		opte1->total.oofs  = c->total.oofs  + c->currnt.oofs;
1397		opte1->total.css   = c->total.css   + c->currnt.css;
1398		opte1->total.dm	   = c->total.dm    + c->currnt.dm;
1399		for (s=0; s<48; ++s) {
1400			opte1->interval[s].bpv   = c->interval[s].bpv;
1401			opte1->interval[s].fse   = c->interval[s].fse;
1402			opte1->interval[s].crce  = c->interval[s].crce;
1403			opte1->interval[s].rcrce = c->interval[s].rcrce;
1404			opte1->interval[s].uas   = c->interval[s].uas;
1405			opte1->interval[s].les   = c->interval[s].les;
1406			opte1->interval[s].es	 = c->interval[s].es;
1407			opte1->interval[s].bes   = c->interval[s].bes;
1408			opte1->interval[s].ses   = c->interval[s].ses;
1409			opte1->interval[s].oofs  = c->interval[s].oofs;
1410			opte1->interval[s].css   = c->interval[s].css;
1411			opte1->interval[s].dm	 = c->interval[s].dm;
1412		}
1413		return 0;
1414
1415	case SERIAL_CLRSTAT:
1416		/* Only for superuser! */
1417		error = suser (td);
1418		if (error)
1419			return error;
1420		c->rintr = 0;
1421		c->tintr = 0;
1422		c->mintr = 0;
1423		c->ibytes = 0;
1424		c->ipkts = 0;
1425		c->ierrs = 0;
1426		c->obytes = 0;
1427		c->opkts = 0;
1428		c->oerrs = 0;
1429		bzero (&c->currnt, sizeof (c->currnt));
1430		bzero (&c->total, sizeof (c->total));
1431		bzero (c->interval, sizeof (c->interval));
1432		return 0;
1433
1434	case SERIAL_GETBAUD:
1435		*(long*)data = ct_get_baud(c);
1436		return 0;
1437
1438	case SERIAL_SETBAUD:
1439		/* Only for superuser! */
1440		error = suser (td);
1441		if (error)
1442			return error;
1443		s = splimp ();
1444		CT_LOCK (bd);
1445		ct_set_baud (c, *(long*)data);
1446		CT_UNLOCK (bd);
1447		splx (s);
1448		return 0;
1449
1450	case SERIAL_GETLOOP:
1451		*(int*)data = ct_get_loop (c);
1452		return 0;
1453
1454	case SERIAL_SETLOOP:
1455		/* Only for superuser! */
1456		error = suser (td);
1457		if (error)
1458			return error;
1459		s = splimp ();
1460		CT_LOCK (bd);
1461		ct_set_loop (c, *(int*)data);
1462		CT_UNLOCK (bd);
1463		splx (s);
1464		return 0;
1465
1466	case SERIAL_GETDPLL:
1467		if (c->mode == M_E1 || c->mode == M_G703)
1468			return EINVAL;
1469		*(int*)data = ct_get_dpll (c);
1470		return 0;
1471
1472	case SERIAL_SETDPLL:
1473		/* Only for superuser! */
1474		error = suser (td);
1475		if (error)
1476			return error;
1477		if (c->mode == M_E1 || c->mode == M_G703)
1478			return EINVAL;
1479		s = splimp ();
1480		CT_LOCK (bd);
1481		ct_set_dpll (c, *(int*)data);
1482		CT_UNLOCK (bd);
1483		splx (s);
1484		return 0;
1485
1486	case SERIAL_GETNRZI:
1487		if (c->mode == M_E1 || c->mode == M_G703)
1488			return EINVAL;
1489		*(int*)data = ct_get_nrzi (c);
1490		return 0;
1491
1492	case SERIAL_SETNRZI:
1493		/* Only for superuser! */
1494		error = suser (td);
1495		if (error)
1496			return error;
1497		if (c->mode == M_E1 || c->mode == M_G703)
1498			return EINVAL;
1499		s = splimp ();
1500		CT_LOCK (bd);
1501		ct_set_nrzi (c, *(int*)data);
1502		CT_UNLOCK (bd);
1503		splx (s);
1504		return 0;
1505
1506	case SERIAL_GETDEBUG:
1507		*(int*)data = c->debug;
1508		return 0;
1509
1510	case SERIAL_SETDEBUG:
1511		/* Only for superuser! */
1512		error = suser (td);
1513		if (error)
1514			return error;
1515		c->debug = *(int*)data;
1516#ifndef	NETGRAPH
1517		if (d->chan->debug)
1518			d->pp.pp_if.if_flags |= IFF_DEBUG;
1519		else
1520			d->pp.pp_if.if_flags &= (~IFF_DEBUG);
1521#endif
1522		return 0;
1523
1524	case SERIAL_GETHIGAIN:
1525		if (c->mode != M_E1)
1526			return EINVAL;
1527		*(int*)data = ct_get_higain (c);
1528		return 0;
1529
1530	case SERIAL_SETHIGAIN:
1531		/* Only for superuser! */
1532		error = suser (td);
1533		if (error)
1534			return error;
1535		s = splimp ();
1536		CT_LOCK (bd);
1537		ct_set_higain (c, *(int*)data);
1538		CT_UNLOCK (bd);
1539		splx (s);
1540		return 0;
1541
1542	case SERIAL_GETPHONY:
1543		CT_DEBUG2 (d, ("ioctl: getphony\n"));
1544		if (c->mode != M_E1)
1545			return EINVAL;
1546		*(int*)data = c->gopt.phony;
1547		return 0;
1548
1549	case SERIAL_SETPHONY:
1550		CT_DEBUG2 (d, ("ioctl: setphony\n"));
1551		if (c->mode != M_E1)
1552			return EINVAL;
1553		/* Only for superuser! */
1554		error = suser (td);
1555		if (error)
1556			return error;
1557		s = splimp ();
1558		CT_LOCK (bd);
1559		ct_set_phony (c, *(int*)data);
1560		CT_UNLOCK (bd);
1561		splx (s);
1562		return 0;
1563
1564	case SERIAL_GETCLK:
1565		if (c->mode != M_E1 && c->mode != M_G703)
1566			return EINVAL;
1567		switch (ct_get_clk(c)) {
1568		default:	 *(int*)data = E1CLK_INTERNAL;		break;
1569		case GCLK_RCV:   *(int*)data = E1CLK_RECEIVE;		break;
1570		case GCLK_RCLKO: *(int*)data = c->num ?
1571			E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1;	break;
1572		}
1573		return 0;
1574
1575	case SERIAL_SETCLK:
1576		/* Only for superuser! */
1577		error = suser (td);
1578		if (error)
1579			return error;
1580		s = splimp ();
1581		CT_LOCK (bd);
1582		switch (*(int*)data) {
1583		default:		    ct_set_clk (c, GCLK_INT);   break;
1584		case E1CLK_RECEIVE:	    ct_set_clk (c, GCLK_RCV);   break;
1585		case E1CLK_RECEIVE_CHAN0:
1586		case E1CLK_RECEIVE_CHAN1:
1587					    ct_set_clk (c, GCLK_RCLKO); break;
1588		}
1589		CT_UNLOCK (bd);
1590		splx (s);
1591		return 0;
1592
1593	case SERIAL_GETTIMESLOTS:
1594		if (c->mode != M_E1)
1595			return EINVAL;
1596		*(long*)data = ct_get_ts (c);
1597		return 0;
1598
1599	case SERIAL_SETTIMESLOTS:
1600		/* Only for superuser! */
1601		error = suser (td);
1602		if (error)
1603			return error;
1604		s = splimp ();
1605		CT_LOCK (bd);
1606		ct_set_ts (c, *(long*)data);
1607		CT_UNLOCK (bd);
1608		splx (s);
1609		return 0;
1610
1611	case SERIAL_GETSUBCHAN:
1612		if (c->mode != M_E1)
1613			return EINVAL;
1614		*(long*)data = ct_get_subchan (c->board);
1615		return 0;
1616
1617	case SERIAL_SETSUBCHAN:
1618		/* Only for superuser! */
1619		error = suser (td);
1620		if (error)
1621			return error;
1622		s = splimp ();
1623		CT_LOCK (bd);
1624		ct_set_subchan (c->board, *(long*)data);
1625		CT_UNLOCK (bd);
1626		splx (s);
1627		return 0;
1628
1629	case SERIAL_GETINVCLK:
1630	case SERIAL_GETINVTCLK:
1631		if (c->mode == M_E1 || c->mode == M_G703)
1632			return EINVAL;
1633		*(int*)data = ct_get_invtxc (c);
1634		return 0;
1635
1636	case SERIAL_GETINVRCLK:
1637		if (c->mode == M_E1 || c->mode == M_G703)
1638			return EINVAL;
1639		*(int*)data = ct_get_invrxc (c);
1640		return 0;
1641
1642	case SERIAL_SETINVCLK:
1643	case SERIAL_SETINVTCLK:
1644		/* Only for superuser! */
1645		error = suser (td);
1646		if (error)
1647			return error;
1648		if (c->mode == M_E1 || c->mode == M_G703)
1649			return EINVAL;
1650		s = splimp ();
1651		CT_LOCK (bd);
1652		ct_set_invtxc (c, *(int*)data);
1653		CT_UNLOCK (bd);
1654		splx (s);
1655		return 0;
1656
1657	case SERIAL_SETINVRCLK:
1658		/* Only for superuser! */
1659		error = suser (td);
1660		if (error)
1661			return error;
1662		if (c->mode == M_E1 || c->mode == M_G703)
1663			return EINVAL;
1664		s = splimp ();
1665		CT_LOCK (bd);
1666		ct_set_invrxc (c, *(int*)data);
1667		CT_UNLOCK (bd);
1668		splx (s);
1669		return 0;
1670
1671	case SERIAL_GETLEVEL:
1672		if (c->mode != M_G703)
1673			return EINVAL;
1674		s = splimp ();
1675		CT_LOCK (bd);
1676		*(int*)data = ct_get_lq (c);
1677		CT_UNLOCK (bd);
1678		splx (s);
1679		return 0;
1680
1681	case TIOCSDTR:	/* Set DTR */
1682		s = splimp ();
1683		CT_LOCK (bd);
1684		ct_set_dtr (c, 1);
1685		CT_UNLOCK (bd);
1686		splx (s);
1687		return 0;
1688
1689	case TIOCCDTR:	/* Clear DTR */
1690		s = splimp ();
1691		CT_LOCK (bd);
1692		ct_set_dtr (c, 0);
1693		CT_UNLOCK (bd);
1694		splx (s);
1695		return 0;
1696
1697	case TIOCMSET:	/* Set DTR/RTS */
1698		s = splimp ();
1699		CT_LOCK (bd);
1700		ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1701		ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1702		CT_UNLOCK (bd);
1703		splx (s);
1704		return 0;
1705
1706	case TIOCMBIS:	/* Add DTR/RTS */
1707		s = splimp ();
1708		CT_LOCK (bd);
1709		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1);
1710		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1);
1711		CT_UNLOCK (bd);
1712		splx (s);
1713		return 0;
1714
1715	case TIOCMBIC:	/* Clear DTR/RTS */
1716		s = splimp ();
1717		CT_LOCK (bd);
1718		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0);
1719		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0);
1720		CT_UNLOCK (bd);
1721		splx (s);
1722		return 0;
1723
1724	case TIOCMGET:	/* Get modem status */
1725		*(int*)data = ct_modem_status (c);
1726		return 0;
1727	}
1728	return ENOTTY;
1729}
1730
1731static struct cdevsw ct_cdevsw = {
1732	.d_version  = D_VERSION,
1733	.d_open     = ct_open,
1734	.d_close    = ct_close,
1735	.d_ioctl    = ct_ioctl,
1736	.d_name     = "ct",
1737	.d_flags    = D_NEEDGIANT,
1738};
1739
1740#ifdef NETGRAPH
1741static int ng_ct_constructor (node_p node)
1742{
1743	drv_t *d = NG_NODE_PRIVATE (node);
1744	CT_DEBUG (d, ("Constructor\n"));
1745	return EINVAL;
1746}
1747
1748static int ng_ct_newhook (node_p node, hook_p hook, const char *name)
1749{
1750	int s;
1751	drv_t *d = NG_NODE_PRIVATE (node);
1752
1753	if (!d)
1754		return EINVAL;
1755
1756	bdrv_t *bd = d->bd;
1757
1758	/* Attach debug hook */
1759	if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) {
1760		NG_HOOK_SET_PRIVATE (hook, NULL);
1761		d->debug_hook = hook;
1762		return 0;
1763	}
1764
1765	/* Check for raw hook */
1766	if (strcmp (name, NG_CT_HOOK_RAW) != 0)
1767		return EINVAL;
1768
1769	NG_HOOK_SET_PRIVATE (hook, d);
1770	d->hook = hook;
1771	s = splimp ();
1772	CT_LOCK (bd);
1773	ct_up (d);
1774	CT_UNLOCK (bd);
1775	splx (s);
1776	return 0;
1777}
1778
1779static char *format_timeslots (u_long s)
1780{
1781	static char buf [100];
1782	char *p = buf;
1783	int i;
1784
1785	for (i=1; i<32; ++i)
1786		if ((s >> i) & 1) {
1787			int prev = (i > 1)  & (s >> (i-1));
1788			int next = (i < 31) & (s >> (i+1));
1789
1790			if (prev) {
1791				if (next)
1792					continue;
1793				*p++ = '-';
1794			} else if (p > buf)
1795				*p++ = ',';
1796
1797			if (i >= 10)
1798				*p++ = '0' + i / 10;
1799			*p++ = '0' + i % 10;
1800		}
1801	*p = 0;
1802	return buf;
1803}
1804
1805static int print_modems (char *s, ct_chan_t *c, int need_header)
1806{
1807	int status = ct_modem_status (c);
1808	int length = 0;
1809
1810	if (need_header)
1811		length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
1812	length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
1813		status & TIOCM_LE  ? "On" : "-",
1814		status & TIOCM_DTR ? "On" : "-",
1815		status & TIOCM_DSR ? "On" : "-",
1816		status & TIOCM_RTS ? "On" : "-",
1817		status & TIOCM_CTS ? "On" : "-",
1818		status & TIOCM_CD  ? "On" : "-");
1819	return length;
1820}
1821
1822static int print_stats (char *s, ct_chan_t *c, int need_header)
1823{
1824	struct serial_statistics st;
1825	int length = 0;
1826
1827	st.rintr  = c->rintr;
1828	st.tintr  = c->tintr;
1829	st.mintr  = c->mintr;
1830	st.ibytes = c->ibytes;
1831	st.ipkts  = c->ipkts;
1832	st.ierrs  = c->ierrs;
1833	st.obytes = c->obytes;
1834	st.opkts  = c->opkts;
1835	st.oerrs  = c->oerrs;
1836	if (need_header)
1837		length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
1838	length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
1839		st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts,
1840		st.ierrs, st.obytes, st.opkts, st.oerrs);
1841	return length;
1842}
1843
1844static char *format_e1_status (u_char status)
1845{
1846	static char buf [80];
1847
1848	if (status & E1_NOALARM)
1849		return "Ok";
1850	buf[0] = 0;
1851	if (status & E1_LOS)     strcat (buf, ",LOS");
1852	if (status & E1_AIS)     strcat (buf, ",AIS");
1853	if (status & E1_LOF)     strcat (buf, ",LOF");
1854	if (status & E1_LOMF)    strcat (buf, ",LOMF");
1855	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
1856	if (status & E1_AIS16)   strcat (buf, ",AIS16");
1857	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
1858	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
1859	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
1860	if (buf[0] == ',')
1861		return buf+1;
1862	return "Unknown";
1863}
1864
1865static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
1866{
1867	int n, length = 0;
1868
1869	if (numerator < 1 || divider < 1) {
1870		length += sprintf (s+length, leftalign ? "/-   " : "    -");
1871		return length;
1872	}
1873	n = (int) (0.5 + 1000.0 * numerator / divider);
1874	if (n < 1000) {
1875		length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
1876		return length;
1877	}
1878	*(s + length) = leftalign ? '/' : ' ';
1879	length ++;
1880
1881	if     (n >= 1000000) n = (n+500) / 1000 * 1000;
1882	else if (n >= 100000)  n = (n+50)  / 100 * 100;
1883	else if (n >= 10000)   n = (n+5)   / 10 * 10;
1884
1885	switch (n) {
1886	case 1000:    length += printf (s+length, ".999"); return length;
1887	case 10000:   n = 9990;   break;
1888	case 100000:  n = 99900;  break;
1889	case 1000000: n = 999000; break;
1890	}
1891	if (n < 10000)	      length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
1892	else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
1893	else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
1894	else		      length += sprintf (s+length, "%d", n/1000);
1895
1896	return length;
1897}
1898
1899static int print_e1_stats (char *s, ct_chan_t *c)
1900{
1901	struct e1_counters total;
1902	u_long totsec;
1903	int length = 0;
1904
1905	totsec		= c->totsec + c->cursec;
1906	total.bpv	= c->total.bpv   + c->currnt.bpv;
1907	total.fse	= c->total.fse   + c->currnt.fse;
1908	total.crce	= c->total.crce  + c->currnt.crce;
1909	total.rcrce	= c->total.rcrce + c->currnt.rcrce;
1910	total.uas	= c->total.uas   + c->currnt.uas;
1911	total.les	= c->total.les   + c->currnt.les;
1912	total.es	= c->total.es    + c->currnt.es;
1913	total.bes	= c->total.bes   + c->currnt.bes;
1914	total.ses	= c->total.ses   + c->currnt.ses;
1915	total.oofs	= c->total.oofs  + c->currnt.oofs;
1916	total.css	= c->total.css   + c->currnt.css;
1917	total.dm	= c->total.dm    + c->currnt.dm;
1918
1919	length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
1920
1921	/* Unavailable seconds, degraded minutes */
1922	length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
1923	length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
1924
1925	/* Bipolar violations, frame sync errors */
1926	length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
1927	length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
1928
1929	/* CRC errors, remote CRC errors (E-bit) */
1930	length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
1931	length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
1932
1933	/* Errored seconds, line errored seconds */
1934	length += print_frac (s + length, 0, c->currnt.es, c->cursec);
1935	length += print_frac (s + length, 1, c->currnt.les, c->cursec);
1936
1937	/* Severely errored seconds, burst errored seconds */
1938	length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
1939	length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
1940
1941	/* Out of frame seconds, controlled slip seconds */
1942	length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
1943	length += print_frac (s + length, 1, c->currnt.css, c->cursec);
1944
1945	length += sprintf (s + length, " %s\n", format_e1_status (c->status));
1946
1947	/* Print total statistics. */
1948	length += print_frac (s + length, 0, total.uas, totsec);
1949	length += print_frac (s + length, 1, 60 * total.dm, totsec);
1950
1951	length += print_frac (s + length, 0, total.bpv, totsec);
1952	length += print_frac (s + length, 1, total.fse, totsec);
1953
1954	length += print_frac (s + length, 0, total.crce, totsec);
1955	length += print_frac (s + length, 1, total.rcrce, totsec);
1956
1957	length += print_frac (s + length, 0, total.es, totsec);
1958	length += print_frac (s + length, 1, total.les, totsec);
1959
1960	length += print_frac (s + length, 0, total.ses, totsec);
1961	length += print_frac (s + length, 1, total.bes, totsec);
1962
1963	length += print_frac (s + length, 0, total.oofs, totsec);
1964	length += print_frac (s + length, 1, total.css, totsec);
1965
1966	length += sprintf (s + length, " -- Total\n");
1967	return length;
1968}
1969
1970static int print_chan (char *s, ct_chan_t *c)
1971{
1972	drv_t *d = c->sys;
1973	bdrv_t *bd = d->bd;
1974	int length = 0;
1975
1976	length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num);
1977	if (d->chan->debug)
1978		length += sprintf (s + length, " debug=%d", d->chan->debug);
1979
1980	switch (ct_get_config (c->board)) {
1981	case CFG_A:	length += sprintf (s + length, " cfg=A");	break;
1982	case CFG_B:	length += sprintf (s + length, " cfg=B");	break;
1983	case CFG_C:	length += sprintf (s + length, " cfg=C");	break;
1984	default:	length += sprintf (s + length, " cfg=unknown"); break;
1985	}
1986
1987	if (ct_get_baud (c))
1988		length += sprintf (s + length, " %ld", ct_get_baud (c));
1989	else
1990		length += sprintf (s + length, " extclock");
1991
1992	if (c->mode == M_E1 || c->mode == M_G703)
1993		switch (ct_get_clk(c)) {
1994		case GCLK_INT   : length += sprintf (s + length, " syn=int");     break;
1995		case GCLK_RCV   : length += sprintf (s + length, " syn=rcv");     break;
1996		case GCLK_RCLKO  : length += sprintf (s + length, " syn=xrcv");    break;
1997		}
1998	if (c->mode == M_HDLC) {
1999		length += sprintf (s + length, " dpll=%s",   ct_get_dpll (c)   ? "on" : "off");
2000		length += sprintf (s + length, " nrzi=%s",   ct_get_nrzi (c)   ? "on" : "off");
2001		length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off");
2002		length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off");
2003	}
2004	if (c->mode == M_E1)
2005		length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off");
2006
2007	length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off");
2008
2009	if (c->mode == M_E1)
2010		length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c)));
2011	if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A)
2012		length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board)));
2013	if (c->mode == M_G703) {
2014		int lq, x;
2015
2016		x = splimp ();
2017		CT_LOCK (bd);
2018		lq = ct_get_lq (c);
2019		CT_UNLOCK (bd);
2020		splx (x);
2021		length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2022	}
2023	length += sprintf (s + length, "\n");
2024	return length;
2025}
2026
2027static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook)
2028{
2029	drv_t *d = NG_NODE_PRIVATE (node);
2030	struct ng_mesg *msg;
2031	struct ng_mesg *resp = NULL;
2032	int error = 0;
2033
2034	if (!d)
2035		return EINVAL;
2036
2037	CT_DEBUG (d, ("Rcvmsg\n"));
2038	NGI_GET_MSG (item, msg);
2039	switch (msg->header.typecookie) {
2040	default:
2041		error = EINVAL;
2042		break;
2043
2044	case NGM_CT_COOKIE:
2045		printf ("Don't forget to implement\n");
2046		error = EINVAL;
2047		break;
2048
2049	case NGM_GENERIC_COOKIE:
2050		switch (msg->header.cmd) {
2051		default:
2052			error = EINVAL;
2053			break;
2054
2055		case NGM_TEXT_STATUS: {
2056			char *s;
2057			int l = 0;
2058			int dl = sizeof (struct ng_mesg) + 730;
2059
2060			NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2061			if (! resp) {
2062				error = ENOMEM;
2063				break;
2064			}
2065			s = (resp)->data;
2066			l += print_chan (s + l, d->chan);
2067			l += print_stats (s + l, d->chan, 1);
2068			l += print_modems (s + l, d->chan, 1);
2069			l += print_e1_stats (s + l, d->chan);
2070			strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2071			}
2072			break;
2073		}
2074		break;
2075	}
2076	NG_RESPOND_MSG (error, node, item, resp);
2077	NG_FREE_MSG (msg);
2078	return error;
2079}
2080
2081static int ng_ct_rcvdata (hook_p hook, item_p item)
2082{
2083	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2084	struct mbuf *m;
2085	struct ng_tag_prio *ptag;
2086	bdrv_t *bd;
2087	struct ifqueue *q;
2088	int s;
2089
2090	if (!d)
2091		return ENETDOWN;
2092
2093	bd = d->bd;
2094	NGI_GET_M (item, m);
2095	NG_FREE_ITEM (item);
2096	if (! NG_HOOK_PRIVATE (hook) || ! d) {
2097		NG_FREE_M (m);
2098		return ENETDOWN;
2099	}
2100
2101	/* Check for high priority data */
2102	if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE,
2103	    NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) )
2104		q = &d->hi_queue;
2105	else
2106		q = &d->queue;
2107
2108	s = splimp ();
2109	CT_LOCK (bd);
2110	IF_LOCK (q);
2111	if (_IF_QFULL (q)) {
2112		_IF_DROP (q);
2113		IF_UNLOCK (q);
2114		CT_UNLOCK (bd);
2115		splx (s);
2116		NG_FREE_M (m);
2117		return ENOBUFS;
2118	}
2119	_IF_ENQUEUE (q, m);
2120	IF_UNLOCK (q);
2121	ct_start (d);
2122	CT_UNLOCK (bd);
2123	splx (s);
2124	return 0;
2125}
2126
2127static int ng_ct_rmnode (node_p node)
2128{
2129	drv_t *d = NG_NODE_PRIVATE (node);
2130	bdrv_t *bd;
2131
2132	CT_DEBUG (d, ("Rmnode\n"));
2133	if (d && d->running) {
2134		bd = d->bd;
2135		int s = splimp ();
2136		CT_LOCK (bd);
2137		ct_down (d);
2138		CT_UNLOCK (bd);
2139		splx (s);
2140	}
2141#ifdef	KLD_MODULE
2142	if (node->nd_flags & NGF_REALLY_DIE) {
2143		NG_NODE_SET_PRIVATE (node, NULL);
2144		NG_NODE_UNREF (node);
2145	}
2146	NG_NODE_REVIVE(node);		/* Persistant node */
2147#endif
2148	return 0;
2149}
2150
2151static void ng_ct_watchdog (void *arg)
2152{
2153	drv_t *d = arg;
2154
2155	if (!d)
2156		return;
2157
2158	if (d->timeout == 1)
2159		ct_watchdog (d);
2160	if (d->timeout)
2161		d->timeout--;
2162	callout_reset (&d->timeout_handle, hz, ng_ct_watchdog, d);
2163}
2164
2165static int ng_ct_connect (hook_p hook)
2166{
2167	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2168
2169	if (!d)
2170		return 0;
2171
2172	callout_reset (&d->timeout_handle, hz, ng_ct_watchdog, d);
2173	return 0;
2174}
2175
2176static int ng_ct_disconnect (hook_p hook)
2177{
2178	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2179	bdrv_t *bd;
2180
2181	if (!d)
2182		return 0;
2183
2184	bd = d->bd;
2185
2186	CT_LOCK (bd);
2187	if (NG_HOOK_PRIVATE (hook))
2188		ct_down (d);
2189	CT_UNLOCK (bd);
2190	/* If we were wait it than it reasserted now, just stop it. */
2191	if (!callout_drain (&d->timeout_handle))
2192		callout_stop (&d->timeout_handle);
2193	return 0;
2194}
2195#endif
2196
2197static int ct_modevent (module_t mod, int type, void *unused)
2198{
2199	static int load_count = 0;
2200
2201	if (!debug_mpsafenet && ct_mpsafenet) {
2202		printf ("WORNING! Network stack is not MPSAFE. "
2203			"Turning off debug.ct.mpsafenet.\n");
2204		ct_mpsafenet = 0;
2205	}
2206	if (ct_mpsafenet)
2207		ct_cdevsw.d_flags &= ~D_NEEDGIANT;
2208
2209	switch (type) {
2210	case MOD_LOAD:
2211#ifdef NETGRAPH
2212		if (ng_newtype (&typestruct))
2213			printf ("Failed to register ng_ct\n");
2214#endif
2215		++load_count;
2216		callout_init (&timeout_handle, ct_mpsafenet?CALLOUT_MPSAFE:0);
2217		callout_reset (&timeout_handle, hz*5, ct_timeout, 0);
2218		break;
2219	case MOD_UNLOAD:
2220		if (load_count == 1) {
2221			printf ("Removing device entry for Tau-ISA\n");
2222#ifdef NETGRAPH
2223			ng_rmtype (&typestruct);
2224#endif
2225		}
2226		/* If we were wait it than it reasserted now, just stop it. */
2227		if (!callout_drain (&timeout_handle))
2228			callout_stop (&timeout_handle);
2229		--load_count;
2230		break;
2231	case MOD_SHUTDOWN:
2232		break;
2233	}
2234	return 0;
2235}
2236
2237#ifdef NETGRAPH
2238static struct ng_type typestruct = {
2239	.version	= NG_ABI_VERSION,
2240	.name		= NG_CT_NODE_TYPE,
2241	.constructor	= ng_ct_constructor,
2242	.rcvmsg		= ng_ct_rcvmsg,
2243	.shutdown	= ng_ct_rmnode,
2244	.newhook	= ng_ct_newhook,
2245	.connect	= ng_ct_connect,
2246	.rcvdata	= ng_ct_rcvdata,
2247	.disconnect	= ng_ct_disconnect,
2248};
2249#endif /*NETGRAPH*/
2250
2251#ifdef NETGRAPH
2252MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2253#else
2254MODULE_DEPEND (ct, sppp, 1, 1, 1);
2255#endif
2256DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2257MODULE_VERSION (ct, 1);
2258