if_ct.c revision 129879
1243730Srwatson/*
2243730Srwatson * Cronyx-Tau adapter driver for FreeBSD.
3243730Srwatson * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
4243730Srwatson * and asyncronous channels with full modem control.
5243730Srwatson * Keepalive protocol implemented in both Cisco and PPP modes.
6243730Srwatson *
7243730Srwatson * Copyright (C) 1994-2002 Cronyx Engineering.
8243730Srwatson * Author: Serge Vakulenko, <vak@cronyx.ru>
9243730Srwatson *
10243730Srwatson * Copyright (C) 1999-2004 Cronyx Engineering.
11243730Srwatson * Author: Roman Kurakin, <rik@cronyx.ru>
12243730Srwatson *
13243730Srwatson * This software is distributed with NO WARRANTIES, not even the implied
14243730Srwatson * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15243730Srwatson *
16243730Srwatson * Authors grant any other persons or organisations a permission to use,
17243730Srwatson * modify and redistribute this software in source and binary forms,
18243730Srwatson * as long as this message is kept with the software, all derivative
19243730Srwatson * works or modified versions.
20243730Srwatson *
21243730Srwatson * Cronyx Id: if_ct.c,v 1.1.2.22 2004/02/26 19:06:51 rik Exp $
22243730Srwatson */
23243730Srwatson#include <sys/cdefs.h>
24243730Srwatson__FBSDID("$FreeBSD: head/sys/dev/ctau/if_ct.c 129879 2004-05-30 20:08:47Z phk $");
25243730Srwatson
26243730Srwatson#include <sys/param.h>
27243730Srwatson
28243730Srwatson#if __FreeBSD_version >= 500000
29243730Srwatson#   define NCTAU 1
30243734Srwatson#else
31243730Srwatson#   include "ctau.h"
32243730Srwatson#endif
33243730Srwatson
34243730Srwatson#if NCTAU > 0
35243730Srwatson#include <sys/proc.h>
36243730Srwatson#include <sys/systm.h>
37243730Srwatson#include <sys/kernel.h>
38243730Srwatson#include <sys/module.h>
39243730Srwatson#include <sys/mbuf.h>
40243730Srwatson#include <sys/sockio.h>
41243730Srwatson#include <sys/malloc.h>
42243730Srwatson#include <sys/socket.h>
43243730Srwatson#include <sys/conf.h>
44243730Srwatson#include <sys/errno.h>
45243730Srwatson#include <sys/tty.h>
46243730Srwatson#if __FreeBSD_version >= 400000
47243730Srwatson#   include <sys/bus.h>
48243730Srwatson#   include <machine/bus.h>
49243730Srwatson#   include <sys/rman.h>
50243730Srwatson#   include <isa/isavar.h>
51243730Srwatson#endif
52243730Srwatson#include <sys/interrupt.h>
53243730Srwatson#include <vm/vm.h>
54243730Srwatson#include <vm/pmap.h>
55243730Srwatson#include <net/if.h>
56243730Srwatson#include <machine/cpufunc.h>
57243730Srwatson#include <machine/cserial.h>
58243730Srwatson#include <machine/clock.h>
59243730Srwatson#if __FreeBSD_version < 500000
60243730Srwatson#include <i386/isa/isa_device.h>
61243730Srwatson#endif
62243730Srwatson#if __FreeBSD_version >= 400000
63243730Srwatson#include <machine/resource.h>
64243730Srwatson#   if __FreeBSD_version <= 501000
65243730Srwatson#   include <i386/isa/intr_machdep.h>
66243730Srwatson#   endif
67243730Srwatson#endif
68243730Srwatson#if __FreeBSD_version >= 400000
69243730Srwatson#include <dev/cx/machdep.h>
70243730Srwatson#include <dev/ctau/ctddk.h>
71243730Srwatson#include <dev/cx/cronyxfw.h>
72243730Srwatson#else
73243730Srwatson#include <i386/isa/cronyx/machdep.h>
74243734Srwatson#include <i386/isa/cronyx/ctddk.h>
75243730Srwatson#include <i386/isa/cronyx/cronyxfw.h>
76243730Srwatson#endif
77243730Srwatson#include "opt_ng_cronyx.h"
78243730Srwatson#ifdef NETGRAPH_CRONYX
79243730Srwatson#   include "opt_netgraph.h"
80243730Srwatson#   include <netgraph/ng_message.h>
81243730Srwatson#   include <netgraph/netgraph.h>
82243730Srwatson#if __FreeBSD_version >= 400000
83243730Srwatson#   include <dev/ctau/ng_ct.h>
84243730Srwatson#else
85243730Srwatson#   include <netgraph/ng_ct.h>
86243730Srwatson#endif
87243730Srwatson#else
88243730Srwatson#   include <net/if_types.h>
89243730Srwatson#   if __FreeBSD_version < 500000
90243730Srwatson#   include "sppp.h"
91243730Srwatson#   if NSPPP <= 0
92243730Srwatson#	error The device ctau requires sppp or netgraph.
93243730Srwatson#   endif
94243730Srwatson#   endif
95243730Srwatson#   include <net/if_sppp.h>
96243730Srwatson#   define PP_CISCO IFF_LINK2
97243730Srwatson#if __FreeBSD_version < 400000
98243730Srwatson#   include <bpfilter.h>
99243730Srwatson#   if NBPFILTER > 0
100243730Srwatson#      include <net/bpf.h>
101243730Srwatson#   endif
102243730Srwatson#else
103243730Srwatson#   if __FreeBSD_version < 500000
104243730Srwatson#       include <bpf.h>
105243730Srwatson#   endif
106243730Srwatson#   include <net/bpf.h>
107243730Srwatson#   define NBPFILTER NBPF
108243730Srwatson#endif
109243730Srwatson#endif
110243730Srwatson
111243730Srwatson/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */
112243730Srwatson#ifndef PP_FR
113243730Srwatson#define PP_FR 0
114243730Srwatson#endif
115243730Srwatson
116243730Srwatson#define CT_DEBUG(d,s)	({if (d->chan->debug) {\
117243730Srwatson				printf ("%s: ", d->name); printf s;}})
118243730Srwatson#define CT_DEBUG2(d,s)	({if (d->chan->debug>1) {\
119243730Srwatson				printf ("%s: ", d->name); printf s;}})
120243730Srwatson#define CDEV_MAJOR	99
121243730Srwatson
122243730Srwatson#if __FreeBSD_version >= 400000
123243730Srwatsonstatic void ct_identify		__P((driver_t *, device_t));
124243730Srwatsonstatic int ct_probe		__P((device_t));
125243730Srwatsonstatic int ct_attach		__P((device_t));
126243730Srwatsonstatic int ct_detach		__P((device_t));
127243730Srwatson
128243730Srwatsonstatic device_method_t ct_isa_methods [] = {
129243730Srwatson	DEVMETHOD(device_identify,	ct_identify),
130243730Srwatson	DEVMETHOD(device_probe,		ct_probe),
131243730Srwatson	DEVMETHOD(device_attach,	ct_attach),
132243730Srwatson	DEVMETHOD(device_detach,	ct_detach),
133243730Srwatson	{0, 0}
134243730Srwatson};
135243730Srwatson
136243730Srwatsontypedef struct _bdrv_t {
137243730Srwatson	ct_board_t	*board;
138243730Srwatson	struct resource	*base_res;
139243730Srwatson	struct resource	*drq_res;
140243730Srwatson	struct resource	*irq_res;
141243730Srwatson	int		base_rid;
142243730Srwatson	int		drq_rid;
143243730Srwatson	int		irq_rid;
144243730Srwatson	void		*intrhand;
145243730Srwatson} bdrv_t;
146243730Srwatson
147243730Srwatsonstatic driver_t ct_isa_driver = {
148243730Srwatson	"ct",
149243730Srwatson	ct_isa_methods,
150243730Srwatson	sizeof (bdrv_t),
151243730Srwatson};
152243730Srwatson
153243730Srwatsonstatic devclass_t ct_devclass;
154243730Srwatson#endif
155243730Srwatson
156243730Srwatsontypedef struct _drv_t {
157243730Srwatson	char name [8];
158243730Srwatson	ct_chan_t *chan;
159243730Srwatson	ct_board_t *board;
160243730Srwatson	ct_buf_t buf;
161243730Srwatson	int running;
162243730Srwatson#ifdef NETGRAPH
163243730Srwatson	char	nodename [NG_NODELEN+1];
164243730Srwatson	hook_p	hook;
165243730Srwatson	hook_p	debug_hook;
166243730Srwatson	node_p	node;
167243730Srwatson	struct	ifqueue queue;
168243730Srwatson	struct	ifqueue hi_queue;
169243730Srwatson	short	timeout;
170243730Srwatson	struct	callout_handle timeout_handle;
171243730Srwatson#else
172243730Srwatson	struct sppp pp;
173243730Srwatson#endif
174243730Srwatson#if __FreeBSD_version >= 400000
175243730Srwatson	dev_t devt;
176243730Srwatson#endif
177243730Srwatson} drv_t;
178243730Srwatson
179243730Srwatsonstatic void ct_receive (ct_chan_t *c, char *data, int len);
180243730Srwatsonstatic void ct_transmit (ct_chan_t *c, void *attachment, int len);
181243730Srwatsonstatic void ct_error (ct_chan_t *c, int data);
182243730Srwatsonstatic void ct_up (drv_t *d);
183243730Srwatsonstatic void ct_start (drv_t *d);
184243730Srwatsonstatic void ct_down (drv_t *d);
185243730Srwatsonstatic void ct_watchdog (drv_t *d);
186243730Srwatson#ifdef NETGRAPH
187243730Srwatsonextern struct ng_type typestruct;
188243730Srwatson#else
189243730Srwatsonstatic void ct_ifstart (struct ifnet *ifp);
190243730Srwatsonstatic void ct_tlf (struct sppp *sp);
191243730Srwatsonstatic void ct_tls (struct sppp *sp);
192243730Srwatsonstatic void ct_ifwatchdog (struct ifnet *ifp);
193243730Srwatsonstatic int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
194243730Srwatsonstatic void ct_initialize (void *softc);
195243730Srwatson#endif
196243730Srwatson
197243730Srwatsonstatic ct_board_t *adapter [NCTAU];
198243730Srwatsonstatic drv_t *channel [NCTAU*NCHAN];
199243730Srwatsonstatic struct callout_handle led_timo [NCTAU];
200243730Srwatsonstatic struct callout_handle timeout_handle;
201243730Srwatson
202243730Srwatson/*
203243730Srwatson * Print the mbuf chain, for debug purposes only.
204243730Srwatson */
205243730Srwatsonstatic void printmbuf (struct mbuf *m)
206243730Srwatson{
207243730Srwatson	printf ("mbuf:");
208243730Srwatson	for (; m; m=m->m_next) {
209243730Srwatson		if (m->m_flags & M_PKTHDR)
210243730Srwatson			printf (" HDR %d:", m->m_pkthdr.len);
211243730Srwatson		if (m->m_flags & M_EXT)
212243730Srwatson			printf (" EXT:");
213243730Srwatson		printf (" %d", m->m_len);
214243730Srwatson	}
215243730Srwatson	printf ("\n");
216243730Srwatson}
217243730Srwatson
218243730Srwatson/*
219243730Srwatson * Make an mbuf from data.
220243730Srwatson */
221243730Srwatsonstatic struct mbuf *makembuf (void *buf, u_int len)
222243730Srwatson{
223243730Srwatson	struct mbuf *m;
224243730Srwatson
225243730Srwatson	MGETHDR (m, M_DONTWAIT, MT_DATA);
226243730Srwatson	if (! m)
227243730Srwatson		return 0;
228243730Srwatson	MCLGET (m, M_DONTWAIT);
229243730Srwatson	if (! (m->m_flags & M_EXT)) {
230243730Srwatson		m_freem (m);
231243730Srwatson		return 0;
232243730Srwatson	}
233243730Srwatson	m->m_pkthdr.len = m->m_len = len;
234243730Srwatson	bcopy (buf, mtod (m, caddr_t), len);
235243730Srwatson	return m;
236243730Srwatson}
237243730Srwatson
238243730Srwatsonstatic void ct_timeout (void *arg)
239243730Srwatson{
240243730Srwatson	drv_t *d;
241243730Srwatson	int s, i;
242243730Srwatson
243243730Srwatson	for (i=0; i<NCTAU*NCHAN; ++i) {
244243730Srwatson		d = channel[i];
245243730Srwatson		if (! d)
246243730Srwatson			continue;
247243730Srwatson		if (d->chan->mode != M_G703)
248243730Srwatson			continue;
249243730Srwatson		s = splimp ();
250243730Srwatson		ct_g703_timer (d->chan);
251243730Srwatson		splx (s);
252243730Srwatson	}
253243730Srwatson	timeout_handle = timeout (ct_timeout, 0, hz);
254243730Srwatson}
255243730Srwatson
256243730Srwatsonstatic void ct_led_off (void *arg)
257243730Srwatson{
258243730Srwatson	ct_board_t *b = arg;
259243730Srwatson	int s = splimp ();
260243730Srwatson
261243730Srwatson	ct_led (b, 0);
262243730Srwatson	led_timo[b->num].callout = 0;
263243730Srwatson	splx (s);
264243730Srwatson}
265243730Srwatson
266243730Srwatson/*
267243730Srwatson * Activate interupt handler from DDK.
268243730Srwatson */
269243730Srwatson#if __FreeBSD_version >= 400000
270243730Srwatsonstatic void ct_intr (void *arg)
271243730Srwatson{
272243730Srwatson	bdrv_t *bd = arg;
273243730Srwatson	ct_board_t *b = bd->board;
274243730Srwatson#else
275243730Srwatsonstatic void ct_intr (int bnum)
276243730Srwatson{
277243730Srwatson	ct_board_t *b = adapter [bnum];
278243730Srwatson#endif
279243730Srwatson	int s = splimp ();
280243730Srwatson
281243730Srwatson	/* Turn LED on. */
282243730Srwatson	ct_led (b, 1);
283243730Srwatson
284243730Srwatson	ct_int_handler (b);
285243730Srwatson
286243730Srwatson	/* Turn LED off 50 msec later. */
287243730Srwatson	if (! led_timo[b->num].callout)
288243730Srwatson		led_timo[b->num] = timeout (ct_led_off, b, hz/20);
289243730Srwatson	splx (s);
290243730Srwatson}
291243730Srwatson
292243730Srwatsonstatic int probe_irq (ct_board_t *b, int irq)
293243730Srwatson{
294243730Srwatson	int mask, busy, cnt;
295243730Srwatson
296243730Srwatson	/* Clear pending irq, if any. */
297243730Srwatson	ct_probe_irq (b, -irq);
298243730Srwatson	DELAY (100);
299243730Srwatson	for (cnt=0; cnt<5; ++cnt) {
300243730Srwatson		/* Get the mask of pending irqs, assuming they are busy.
301243730Srwatson		 * Activate the adapter on given irq. */
302243730Srwatson		busy = ct_probe_irq (b, irq);
303243730Srwatson		DELAY (1000);
304243730Srwatson
305243730Srwatson		/* Get the mask of active irqs.
306243730Srwatson		 * Deactivate our irq. */
307243730Srwatson		mask = ct_probe_irq (b, -irq);
308243730Srwatson		DELAY (100);
309243730Srwatson		if ((mask & ~busy) == 1 << irq) {
310243730Srwatson			ct_probe_irq (b, 0);
311243730Srwatson			/* printf ("ct%d: irq %d ok, mask=0x%04x, busy=0x%04x\n",
312243730Srwatson				b->num, irq, mask, busy); */
313243730Srwatson			return 1;
314243730Srwatson		}
315243730Srwatson	}
316243730Srwatson	/* printf ("ct%d: irq %d not functional, mask=0x%04x, busy=0x%04x\n",
317243730Srwatson		b->num, irq, mask, busy); */
318243730Srwatson	ct_probe_irq (b, 0);
319243730Srwatson	return 0;
320243730Srwatson}
321243730Srwatson
322243730Srwatsonstatic	short porttab [] = {
323243730Srwatson		0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
324243730Srwatson		0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
325243730Srwatson	};
326243730Srwatsonstatic	char dmatab [] = { 7, 6, 5, 0 };
327243730Srwatsonstatic	char irqtab [] = { 5, 10, 11, 7, 3, 15, 12, 0 };
328243730Srwatson
329243730Srwatson#if __FreeBSD_version >= 400000
330243730Srwatsonstatic int ct_is_free_res (device_t dev, int rid, int type, u_long start,
331243730Srwatson	u_long end, u_long count)
332243730Srwatson{
333243730Srwatson	struct resource *res;
334243730Srwatson
335243730Srwatson	if (!(res = bus_alloc_resource (dev, type, &rid, start, end, count,
336243730Srwatson	    RF_ALLOCATED)))
337243730Srwatson		return 0;
338243730Srwatson
339243730Srwatson	bus_release_resource (dev, type, rid, res);
340243730Srwatson
341243730Srwatson	return 1;
342243730Srwatson}
343243730Srwatson
344243730Srwatsonstatic void ct_identify (driver_t *driver, device_t dev)
345243730Srwatson{
346243730Srwatson	u_long iobase, rescount;
347243730Srwatson	int devcount;
348243730Srwatson	device_t *devices;
349243730Srwatson	device_t child;
350243730Srwatson	devclass_t my_devclass;
351243730Srwatson	int i, k;
352243730Srwatson
353243730Srwatson	if ((my_devclass = devclass_find ("ct")) == NULL)
354243730Srwatson		return;
355243730Srwatson
356243730Srwatson	devclass_get_devices (my_devclass, &devices, &devcount);
357243730Srwatson
358243730Srwatson	if (devcount == 0) {
359243730Srwatson		/* We should find all devices by our self. We could alter other
360243730Srwatson		 * devices, but we don't have a choise
361243730Srwatson		 */
362243730Srwatson		for (i = 0; (iobase = porttab [i]) != 0; i++) {
363243730Srwatson			if (!ct_is_free_res (dev, 1, SYS_RES_IOPORT,
364243730Srwatson			    iobase, iobase + NPORT, NPORT))
365243730Srwatson				continue;
366243730Srwatson			if (ct_probe_board (iobase, -1, -1) == 0)
367243730Srwatson				continue;
368243730Srwatson
369243730Srwatson			devcount++;
370243730Srwatson			child = BUS_ADD_CHILD (dev, ISA_ORDER_SPECULATIVE, "ct",
371243730Srwatson			    -1);
372243730Srwatson
373243730Srwatson			if (child == NULL)
374243730Srwatson				return;
375243730Srwatson
376243730Srwatson			device_set_desc_copy (child, "Cronyx Tau-ISA");
377243730Srwatson			device_set_driver (child, driver);
378243730Srwatson			bus_set_resource (child, SYS_RES_IOPORT, 0,
379243730Srwatson			    iobase, NPORT);
380243730Srwatson
381243730Srwatson			if (devcount >= NCTAU)
382243730Srwatson				break;
383243730Srwatson		}
384243730Srwatson	} else {
385243730Srwatson		static	short porttab [] = {
386243730Srwatson			0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
387243730Srwatson			0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
388243730Srwatson		};
389243730Srwatson		/* Lets check user choise.
390243730Srwatson		 */
391243730Srwatson		for (k = 0; k < devcount; k++) {
392243730Srwatson			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
393243730Srwatson			    &iobase, &rescount) != 0)
394243730Srwatson				continue;
395247442Spjd
396243730Srwatson			for (i = 0; porttab [i] != 0; i++) {
397243730Srwatson				if (porttab [i] != iobase)
398243730Srwatson					continue;
399243730Srwatson
400243730Srwatson				if (!ct_is_free_res (devices[k], 1, SYS_RES_IOPORT,
401243730Srwatson				    iobase, iobase + NPORT, NPORT))
402243730Srwatson					continue;
403243730Srwatson
404243730Srwatson				if (ct_probe_board (iobase, -1, -1) == 0)
405243730Srwatson					continue;
406243730Srwatson				porttab [i] = -1;
407243730Srwatson				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
408243730Srwatson				break;
409243730Srwatson			}
410247442Spjd			if (porttab [i] == 0) {
411247442Spjd				device_delete_child (
412247442Spjd				    device_get_parent (devices[k]),
413247442Spjd				    devices [k]);
414247442Spjd				devices[k] = 0;
415247442Spjd				continue;
416247442Spjd			}
417247442Spjd		}
418243730Srwatson		for (k = 0; k < devcount; k++) {
419243730Srwatson			if (devices[k] == 0)
420243730Srwatson				continue;
421243730Srwatson			if (bus_get_resource (devices[k], SYS_RES_IOPORT, 0,
422243730Srwatson			    &iobase, &rescount) == 0)
423243730Srwatson				continue;
424243730Srwatson			for (i = 0; (iobase = porttab [i]) != 0; i++) {
425243730Srwatson				if (porttab [i] == -1)
426243730Srwatson					continue;
427243730Srwatson				if (!ct_is_free_res (devices[k], 1, SYS_RES_IOPORT,
428243730Srwatson				    iobase, iobase + NPORT, NPORT))
429243730Srwatson					continue;
430243730Srwatson				if (ct_probe_board (iobase, -1, -1) == 0)
431243730Srwatson					continue;
432243730Srwatson
433243730Srwatson				bus_set_resource (devices[k], SYS_RES_IOPORT, 0,
434243730Srwatson				    iobase, NPORT);
435243730Srwatson				porttab [i] = -1;
436243730Srwatson				device_set_desc_copy (devices[k], "Cronyx Tau-ISA");
437243730Srwatson				break;
438243730Srwatson			}
439243730Srwatson			if (porttab [i] == 0) {
440243730Srwatson				device_delete_child (
441243730Srwatson				    device_get_parent (devices[k]),
442243730Srwatson				    devices [k]);
443243730Srwatson			}
444243730Srwatson		}
445243730Srwatson		free (devices, M_TEMP);
446243730Srwatson	}
447243730Srwatson
448243730Srwatson	return;
449243730Srwatson}
450243730Srwatson
451243730Srwatsonstatic int ct_probe (device_t dev)
452243730Srwatson{
453243730Srwatson	int unit = device_get_unit (dev);
454243730Srwatson	u_long iobase, rescount;
455243730Srwatson
456243730Srwatson	if (!device_get_desc (dev) ||
457243730Srwatson	    strcmp (device_get_desc (dev), "Cronyx Tau-ISA"))
458243730Srwatson		return ENXIO;
459243730Srwatson
460243730Srwatson/*	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));*/
461243730Srwatson	if (bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount) != 0) {
462243730Srwatson		printf ("ct%d: Couldn't get IOPORT\n", unit);
463243730Srwatson		return ENXIO;
464243730Srwatson	}
465243730Srwatson
466243730Srwatson	if (!ct_is_free_res (dev, 1, SYS_RES_IOPORT,
467243730Srwatson	    iobase, iobase + NPORT, NPORT)) {
468243730Srwatson		printf ("ct%d: Resource IOPORT isn't free\n", unit);
469243730Srwatson		return ENXIO;
470243730Srwatson	}
471243730Srwatson
472243730Srwatson	if (!ct_probe_board (iobase, -1, -1)) {
473243730Srwatson		printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
474243730Srwatson		return ENXIO;
475243730Srwatson	}
476243730Srwatson
477243730Srwatson	return 0;
478243730Srwatson}
479243730Srwatson#else /* __FreeBSD_version < 400000 */
480243730Srwatsonstatic int ct_probe (struct isa_device *id)
481243730Srwatson{
482243730Srwatson	int unit = id->id_unit;
483243730Srwatson	int iobase;
484243730Srwatson	ct_board_t *b;
485243730Srwatson	int i;
486243730Srwatson
487243730Srwatson	iobase = id->id_iobase;
488243730Srwatson	if (iobase < 0) {
489243730Srwatson		/* Autodetect the adapter. */
490243730Srwatson
491243730Srwatson		for (i=0; ; i++) {
492243730Srwatson			if (! porttab[i]) {
493243730Srwatson				iobase = -1;
494243730Srwatson				return 0;
495243730Srwatson			}
496243730Srwatson			iobase = porttab[i];
497243730Srwatson			if (unit > 0 && adapter[0] && adapter[0]->port == iobase)
498243730Srwatson				continue;
499243730Srwatson			if (unit > 1 && adapter[1] && adapter[1]->port == iobase)
500243730Srwatson				continue;
501243730Srwatson			if (! haveseen_isadev (id, CC_IOADDR | CC_QUIET) &&
502243730Srwatson			    ct_probe_board (iobase, -1, -1))
503243730Srwatson				break;
504243730Srwatson		}
505243730Srwatson	} else if (! ct_probe_board (iobase, -1, -1))
506243730Srwatson		return 0;
507243730Srwatson
508243730Srwatson	if (id->id_drq < 0) {
509243730Srwatson		/* Find available 16-bit DRQ. */
510243730Srwatson
511243730Srwatson		for (i=0; ; ++i) {
512243730Srwatson			if (! dmatab[i]) {
513243730Srwatson				printf ("ct%d: no available drq found\n",
514243730Srwatson					unit);
515243730Srwatson				id->id_drq = -1;
516243730Srwatson				return 0;
517243730Srwatson			}
518243730Srwatson			id->id_drq = dmatab[i];
519243730Srwatson			if (! haveseen_isadev (id, CC_DRQ | CC_QUIET)
520243730Srwatson			    && !isa_dma_acquire (id->id_drq))
521243730Srwatson				break;
522243730Srwatson		}
523243730Srwatson	}
524243730Srwatson
525243730Srwatson	b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
526243730Srwatson	if (!b) {
527243730Srwatson		printf ("ct:%d: Couldn't allocate memory\n", unit);
528243730Srwatson		return (ENXIO);
529243730Srwatson	}
530243730Srwatson	adapter[unit] = b;
531243730Srwatson	bzero (b, sizeof(ct_board_t));
532243730Srwatson
533243730Srwatson	if (! ct_open_board (b, unit, iobase,
534243730Srwatson	    id->id_irq ? ffs (id->id_irq) - 1 : -1, id->id_drq)) {
535243730Srwatson		printf ("ct%d: error loading firmware\n", unit);
536243730Srwatson		adapter [unit] = 0;
537243730Srwatson		free (b, M_DEVBUF);
538243730Srwatson		isa_dma_release (id->id_drq);
539243730Srwatson 		return 0;
540243730Srwatson	}
541243730Srwatson
542243730Srwatson	if (id->id_irq) {
543243730Srwatson		if (! probe_irq (b, ffs (id->id_irq) - 1))
544243730Srwatson			printf ("ct%d: irq %d not functional\n",
545243730Srwatson				unit, ffs (id->id_irq) - 1);
546243730Srwatson	} else {
547243730Srwatson		/* Find available IRQ. */
548243730Srwatson
549243730Srwatson		for (i=0; ; ++i) {
550243730Srwatson			if (! irqtab[i]) {
551243730Srwatson				printf ("ct%d: no available irq found\n",
552243730Srwatson					unit);
553243730Srwatson				id->id_irq = -1;
554243730Srwatson				isa_dma_release (id->id_drq);
555243730Srwatson				adapter [unit] = 0;
556243730Srwatson				free (b, M_DEVBUF);
557243730Srwatson				return 0;
558243730Srwatson			}
559243730Srwatson			id->id_irq = 1 << irqtab[i];
560243730Srwatson			if (haveseen_isadev (id, CC_IRQ | CC_QUIET))
561243730Srwatson				continue;
562243730Srwatson#ifdef KLD_MODULE
563243730Srwatson			if (register_intr (irqtab[i], 0, 0, (inthand2_t*)
564243730Srwatson			    ct_intr, &net_imask, unit) != 0)
565243730Srwatson				continue;
566243730Srwatson			unregister_intr (irqtab[i], (inthand2_t*) ct_intr);
567243730Srwatson#endif
568243730Srwatson			if (probe_irq (b, irqtab[i]))
569243730Srwatson				break;
570243730Srwatson		}
571243730Srwatson	}
572243730Srwatson	ct_init_board (b, b->num, b->port, ffs (id->id_irq) - 1, b->dma,
573243730Srwatson		b->type, b->osc);
574243730Srwatson	ct_setup_board (b, 0, 0, 0);
575243730Srwatson
576243730Srwatson	return 1;
577243730Srwatson}
578243730Srwatson#endif /* __FreeBSD_version < 400000 */
579243730Srwatson
580243730Srwatsonextern struct cdevsw ct_cdevsw;
581243730Srwatson/*
582243730Srwatson * The adapter is present, initialize the driver structures.
583243730Srwatson */
584243730Srwatson#if __FreeBSD_version < 400000
585243730Srwatsonstatic int ct_attach (struct isa_device *id)
586243730Srwatson{
587243730Srwatson#else
588243730Srwatsonstatic int ct_attach (device_t dev)
589243730Srwatson{
590243730Srwatson	bdrv_t *bd = device_get_softc (dev);
591243730Srwatson	u_long iobase, drq, irq, rescount;
592243730Srwatson	int unit = device_get_unit (dev);
593243730Srwatson	int i;
594243730Srwatson	int s;
595243730Srwatson#endif
596243730Srwatson	ct_board_t *b;
597243730Srwatson	ct_chan_t *c;
598243730Srwatson	drv_t *d;
599243730Srwatson
600243730Srwatson#if __FreeBSD_version >= 400000
601243730Srwatson	KASSERT ((bd != NULL), ("ct%d: NULL device softc\n", unit));
602243730Srwatson
603243730Srwatson	bus_get_resource (dev, SYS_RES_IOPORT, 0, &iobase, &rescount);
604243730Srwatson	bd->base_rid = 0;
605243730Srwatson	bd->base_res = bus_alloc_resource (dev, SYS_RES_IOPORT, &bd->base_rid,
606243730Srwatson		iobase, iobase + NPORT, NPORT, RF_ACTIVE);
607243730Srwatson	if (! bd->base_res) {
608243730Srwatson		printf ("ct%d: cannot alloc base address\n", unit);
609243730Srwatson		return ENXIO;
610243730Srwatson	}
611243730Srwatson
612243730Srwatson	if (bus_get_resource (dev, SYS_RES_DRQ, 0, &drq, &rescount) != 0) {
613243730Srwatson		for (i = 0; (drq = dmatab [i]) != 0; i++) {
614243730Srwatson			if (!ct_is_free_res (dev, 1, SYS_RES_DRQ,
615243730Srwatson			    drq, drq + 1, 1))
616243730Srwatson				continue;
617243730Srwatson			bus_set_resource (dev, SYS_RES_DRQ, 0, drq, 1);
618243730Srwatson			break;
619243730Srwatson		}
620243730Srwatson
621243730Srwatson		if (dmatab[i] == 0) {
622243730Srwatson			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
623243730Srwatson				bd->base_res);
624243730Srwatson			printf ("ct%d: Couldn't get DRQ\n", unit);
625243730Srwatson			return ENXIO;
626243730Srwatson		}
627243730Srwatson	}
628243730Srwatson
629243730Srwatson	bd->drq_rid = 0;
630243730Srwatson	bd->drq_res = bus_alloc_resource (dev, SYS_RES_DRQ, &bd->drq_rid,
631243730Srwatson		drq, drq + 1, 1, RF_ACTIVE);
632243730Srwatson	if (! bd->drq_res) {
633243730Srwatson		printf ("ct%d: cannot allocate drq\n", unit);
634243730Srwatson		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
635243730Srwatson			bd->base_res);
636243730Srwatson		return ENXIO;
637243730Srwatson	}
638243730Srwatson
639243730Srwatson	if (bus_get_resource (dev, SYS_RES_IRQ, 0, &irq, &rescount) != 0) {
640243730Srwatson		for (i = 0; (irq = irqtab [i]) != 0; i++) {
641243730Srwatson			if (!ct_is_free_res (dev, 1, SYS_RES_IRQ,
642243730Srwatson			    irq, irq + 1, 1))
643243730Srwatson				continue;
644243730Srwatson			bus_set_resource (dev, SYS_RES_IRQ, 0, irq, 1);
645243730Srwatson			break;
646243730Srwatson		}
647243730Srwatson
648243730Srwatson		if (irqtab[i] == 0) {
649243730Srwatson			bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
650243730Srwatson				bd->drq_res);
651243730Srwatson			bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
652243730Srwatson				bd->base_res);
653243730Srwatson			printf ("ct%d: Couldn't get IRQ\n", unit);
654243730Srwatson			return ENXIO;
655243730Srwatson		}
656243730Srwatson	}
657243730Srwatson
658243730Srwatson	bd->irq_rid = 0;
659243730Srwatson	bd->irq_res = bus_alloc_resource (dev, SYS_RES_IRQ, &bd->irq_rid,
660243730Srwatson		irq, irq + 1, 1, RF_ACTIVE);
661243730Srwatson	if (! bd->irq_res) {
662243730Srwatson		printf ("ct%d: Couldn't allocate irq\n", unit);
663243730Srwatson		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
664243730Srwatson			bd->drq_res);
665243730Srwatson		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
666243730Srwatson			bd->base_res);
667243730Srwatson		return ENXIO;
668243730Srwatson	}
669243730Srwatson
670243730Srwatson	b = malloc (sizeof (ct_board_t), M_DEVBUF, M_WAITOK);
671243730Srwatson	if (!b) {
672243730Srwatson		printf ("ct:%d: Couldn't allocate memory\n", unit);
673243730Srwatson		return (ENXIO);
674243730Srwatson	}
675243730Srwatson	adapter[unit] = b;
676243730Srwatson	bzero (b, sizeof(ct_board_t));
677243730Srwatson
678243730Srwatson	if (! ct_open_board (b, unit, iobase, irq, drq)) {
679243730Srwatson		printf ("ct%d: error loading firmware\n", unit);
680243730Srwatson		free (b, M_DEVBUF);
681243730Srwatson		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
682243730Srwatson			bd->irq_res);
683243730Srwatson		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
684243730Srwatson			bd->drq_res);
685243730Srwatson		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
686243730Srwatson			bd->base_res);
687243730Srwatson 		return ENXIO;
688243730Srwatson	}
689243730Srwatson
690243730Srwatson	bd->board = b;
691243730Srwatson
692243730Srwatson	if (! probe_irq (b, irq)) {
693243730Srwatson		printf ("ct%d: irq %ld not functional\n", unit, irq);
694243730Srwatson		bd->board = 0;
695243730Srwatson		adapter [unit] = 0;
696243730Srwatson		free (b, M_DEVBUF);
697243730Srwatson		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
698243730Srwatson			bd->irq_res);
699243730Srwatson		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
700243730Srwatson			bd->drq_res);
701243730Srwatson		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
702243730Srwatson			bd->base_res);
703243730Srwatson 		return ENXIO;
704243730Srwatson	}
705243730Srwatson
706243730Srwatson	s = splimp ();
707243730Srwatson	if (bus_setup_intr (dev, bd->irq_res, INTR_TYPE_NET, ct_intr, bd,
708243730Srwatson	    &bd->intrhand)) {
709243730Srwatson		printf ("ct%d: Can't setup irq %ld\n", unit, irq);
710243730Srwatson		bd->board = 0;
711243730Srwatson		adapter [unit] = 0;
712243730Srwatson		free (b, M_DEVBUF);
713243730Srwatson		bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid,
714243730Srwatson			bd->irq_res);
715243730Srwatson		bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid,
716243730Srwatson			bd->drq_res);
717243730Srwatson		bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid,
718243730Srwatson			bd->base_res);
719243730Srwatson		splx (s);
720243730Srwatson 		return ENXIO;
721243730Srwatson	}
722243730Srwatson
723243730Srwatson	ct_init_board (b, b->num, b->port, irq, drq, b->type, b->osc);
724243730Srwatson	ct_setup_board (b, 0, 0, 0);
725243730Srwatson#else
726243730Srwatson	b = adapter [id->id_unit];
727243730Srwatson#endif
728243730Srwatson
729243730Srwatson	printf ("ct%d: <Cronyx-%s>, clock %s MHz\n", b->num, b->name,
730243730Srwatson		b->osc == 20000000 ? "20" : "16.384");
731243730Srwatson#if __FreeBSD_version < 400000
732243730Srwatson	id->id_ointr = ct_intr;
733243730Srwatson#endif
734243730Srwatson
735243730Srwatson	for (c=b->chan; c<b->chan+NCHAN; ++c) {
736243730Srwatson		d = contigmalloc (sizeof(drv_t), M_DEVBUF, M_WAITOK,
737243730Srwatson			0x100000, 0x1000000, 16, 0);
738243730Srwatson		channel [b->num*NCHAN + c->num] = d;
739243730Srwatson		bzero (d, sizeof(drv_t));
740243730Srwatson		sprintf (d->name, "ct%d.%d", b->num, c->num);
741243730Srwatson		d->board = b;
742243730Srwatson		d->chan = c;
743243730Srwatson		c->sys = d;
744243730Srwatson
745243730Srwatson#ifdef NETGRAPH
746243730Srwatson		if (ng_make_node_common (&typestruct, &d->node) != 0) {
747243730Srwatson			printf ("%s: cannot make common node\n", d->name);
748243730Srwatson			channel [b->num*NCHAN + c->num] = 0;
749243730Srwatson			c->sys = 0;
750243730Srwatson#if __FreeBSD_version < 400000
751243730Srwatson			free (d, M_DEVBUF);
752243730Srwatson#else
753243730Srwatson			contigfree (d, sizeof (*d), M_DEVBUF);
754243730Srwatson#endif
755243730Srwatson			continue;
756243730Srwatson		}
757243730Srwatson#if __FreeBSD_version >= 500000
758243730Srwatson		NG_NODE_SET_PRIVATE (d->node, d);
759243730Srwatson#else
760243730Srwatson		d->node->private = d;
761243730Srwatson#endif
762243730Srwatson		sprintf (d->nodename, "%s%d", NG_CT_NODE_TYPE,
763243730Srwatson			 c->board->num*NCHAN + c->num);
764243730Srwatson		if (ng_name_node (d->node, d->nodename)) {
765243730Srwatson			printf ("%s: cannot name node\n", d->nodename);
766243730Srwatson#if __FreeBSD_version >= 500000
767243730Srwatson			NG_NODE_UNREF (d->node);
768243730Srwatson#else
769243730Srwatson			ng_rmnode (d->node);
770243730Srwatson			ng_unref (d->node);
771243730Srwatson#endif
772243730Srwatson			channel [b->num*NCHAN + c->num] = 0;
773243730Srwatson			c->sys = 0;
774243730Srwatson#if __FreeBSD_version < 400000
775243730Srwatson			free (d, M_DEVBUF);
776243730Srwatson#else
777243730Srwatson			contigfree (d, sizeof (*d), M_DEVBUF);
778243730Srwatson#endif
779243730Srwatson			continue;
780243730Srwatson		}
781243730Srwatson		d->queue.ifq_maxlen = IFQ_MAXLEN;
782243730Srwatson		d->hi_queue.ifq_maxlen = IFQ_MAXLEN;
783243730Srwatson#if __FreeBSD_version >= 500000
784243730Srwatson		mtx_init (&d->queue.ifq_mtx, "ct_queue", NULL, MTX_DEF);
785243730Srwatson		mtx_init (&d->hi_queue.ifq_mtx, "ct_queue_hi", NULL, MTX_DEF);
786243730Srwatson#endif
787243730Srwatson#else /*NETGRAPH*/
788243730Srwatson		d->pp.pp_if.if_softc    = d;
789243730Srwatson#if __FreeBSD_version > 501000
790243730Srwatson		if_initname (&d->pp.pp_if, "ct", b->num * NCHAN + c->num);
791243730Srwatson#else
792243730Srwatson		d->pp.pp_if.if_unit     = b->num * NCHAN + c->num;
793243730Srwatson		d->pp.pp_if.if_name     = "ct";
794243730Srwatson#endif
795243730Srwatson		d->pp.pp_if.if_mtu      = PP_MTU;
796243730Srwatson		d->pp.pp_if.if_flags    = IFF_POINTOPOINT | IFF_MULTICAST;
797243730Srwatson		d->pp.pp_if.if_ioctl    = ct_sioctl;
798243730Srwatson		d->pp.pp_if.if_start    = ct_ifstart;
799243730Srwatson		d->pp.pp_if.if_watchdog = ct_ifwatchdog;
800243730Srwatson		d->pp.pp_if.if_init     = ct_initialize;
801243730Srwatson		sppp_attach (&d->pp.pp_if);
802243730Srwatson		if_attach (&d->pp.pp_if);
803243730Srwatson		d->pp.pp_tlf            = ct_tlf;
804243730Srwatson		d->pp.pp_tls            = ct_tls;
805243730Srwatson#if __FreeBSD_version >= 400000 || NBPFILTER > 0
806243730Srwatson		/* If BPF is in the kernel, call the attach for it.
807243730Srwatson		 * Header size is 4 bytes. */
808243730Srwatson		bpfattach (&d->pp.pp_if, DLT_PPP, 4);
809243730Srwatson#endif
810243730Srwatson#endif /*NETGRAPH*/
811243730Srwatson		ct_start_chan (c, &d->buf, vtophys (&d->buf));
812243730Srwatson		ct_register_receive (c, &ct_receive);
813243730Srwatson		ct_register_transmit (c, &ct_transmit);
814243730Srwatson		ct_register_error (c, &ct_error);
815243730Srwatson#if __FreeBSD_version >= 400000
816243730Srwatson		d->devt = make_dev (&ct_cdevsw, b->num*NCHAN+c->num, UID_ROOT,
817243730Srwatson				GID_WHEEL, 0600, "ct%d", b->num*NCHAN+c->num);
818243730Srwatson	}
819243730Srwatson	splx (s);
820243730Srwatson
821243730Srwatson	return 0;
822243730Srwatson#else /* __FreeBSD_version < 400000 */
823243730Srwatson	}
824243730Srwatson	return 1;
825243730Srwatson#endif /*__FreeBSD_version */
826243730Srwatson}
827243730Srwatson
828243730Srwatson#if __FreeBSD_version >= 400000
829243730Srwatsonstatic int ct_detach (device_t dev)
830243730Srwatson{
831243730Srwatson	bdrv_t *bd = device_get_softc (dev);
832243730Srwatson	ct_board_t *b = bd->board;
833243730Srwatson	ct_chan_t *c;
834243730Srwatson	int s = splimp ();
835243730Srwatson
836243730Srwatson	/* Check if the device is busy (open). */
837243730Srwatson	for (c = b->chan; c < b->chan + NCHAN; ++c) {
838243730Srwatson		drv_t *d = (drv_t*) c->sys;
839243730Srwatson
840243730Srwatson		if (!d || !d->chan->type)
841243730Srwatson			continue;
842243730Srwatson
843243730Srwatson		if (d->running) {
844243730Srwatson			splx (s);
845243730Srwatson			return EBUSY;
846		}
847	}
848
849	/* Deactivate the timeout routine. */
850	if (led_timo[b->num].callout)
851		untimeout (ct_led_off, b, led_timo[b->num]);
852
853	bus_teardown_intr (dev, bd->irq_res, bd->intrhand);
854	bus_deactivate_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
855	bus_release_resource (dev, SYS_RES_IRQ, bd->irq_rid, bd->irq_res);
856
857	bus_deactivate_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
858	bus_release_resource (dev, SYS_RES_DRQ, bd->drq_rid, bd->drq_res);
859
860	bus_deactivate_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->irq_res);
861	bus_release_resource (dev, SYS_RES_IOPORT, bd->base_rid, bd->base_res);
862
863	ct_close_board (b);
864
865	/* Detach the interfaces, free buffer memory. */
866	for (c = b->chan; c < b->chan + NCHAN; ++c) {
867		drv_t *d = (drv_t*) c->sys;
868
869		if (!d || !d->chan->type)
870			continue;
871
872#ifdef NETGRAPH
873#if __FreeBSD_version >= 500000
874		if (d->node) {
875			ng_rmnode_self (d->node);
876			NG_NODE_UNREF (d->node);
877			d->node = NULL;
878		}
879		mtx_destroy (&d->queue.ifq_mtx);
880		mtx_destroy (&d->hi_queue.ifq_mtx);
881#else
882		ng_rmnode (d->node);
883		d->node = 0;
884#endif
885#else
886#if __FreeBSD_version >= 410000 && NBPFILTER > 0
887		/* Detach from the packet filter list of interfaces. */
888		bpfdetach (&d->pp.pp_if);
889#endif
890		/* Detach from the sync PPP list. */
891		sppp_detach (&d->pp.pp_if);
892
893		if_detach (&d->pp.pp_if);
894#endif
895		destroy_dev (d->devt);
896	}
897
898	ct_led_off (b);
899	if (led_timo[b->num].callout)
900		untimeout (ct_led_off, b, led_timo[b->num]);
901	splx (s);
902
903	s = splimp ();
904	for (c = b->chan; c < b->chan + NCHAN; ++c) {
905		drv_t *d = (drv_t*) c->sys;
906
907		if (!d || !d->chan->type)
908			continue;
909
910		/* Deallocate buffers. */
911#if __FreeBSD_version < 400000
912		free (d, M_DEVBUF);
913#else
914		contigfree (d, sizeof (*d), M_DEVBUF);
915#endif
916	}
917	bd->board = 0;
918	adapter [b->num] = 0;
919	free (b, M_DEVBUF);
920	splx (s);
921
922	return 0;
923}
924#endif
925
926#ifndef NETGRAPH
927static void ct_ifstart (struct ifnet *ifp)
928{
929        drv_t *d = ifp->if_softc;
930
931	ct_start (d);
932}
933
934static void ct_ifwatchdog (struct ifnet *ifp)
935{
936        drv_t *d = ifp->if_softc;
937
938	ct_watchdog (d);
939}
940
941static void ct_tlf (struct sppp *sp)
942{
943	drv_t *d = sp->pp_if.if_softc;
944
945	CT_DEBUG (d, ("ct_tlf\n"));
946/*	ct_set_dtr (d->chan, 0);*/
947/*	ct_set_rts (d->chan, 0);*/
948	sp->pp_down (sp);
949}
950
951static void ct_tls (struct sppp *sp)
952{
953	drv_t *d = sp->pp_if.if_softc;
954
955	CT_DEBUG (d, ("ct_tls\n"));
956	sp->pp_up (sp);
957}
958
959/*
960 * Initialization of interface.
961 * Ii seems to be never called by upper level.
962 */
963static void ct_initialize (void *softc)
964{
965	drv_t *d = softc;
966
967	CT_DEBUG (d, ("ct_initialize\n"));
968}
969
970/*
971 * Process an ioctl request.
972 */
973static int ct_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
974{
975	drv_t *d = ifp->if_softc;
976	int error, s, was_up, should_be_up;
977
978	was_up = (ifp->if_flags & IFF_RUNNING) != 0;
979	error = sppp_ioctl (ifp, cmd, data);
980	if (error)
981		return error;
982
983	if (! (ifp->if_flags & IFF_DEBUG))
984		d->chan->debug = 0;
985	else if (! d->chan->debug)
986		d->chan->debug = 1;
987
988	switch (cmd) {
989	default:           CT_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0;
990	case SIOCADDMULTI: CT_DEBUG2 (d, ("SIOCADDMULTI\n"));     return 0;
991	case SIOCDELMULTI: CT_DEBUG2 (d, ("SIOCDELMULTI\n"));     return 0;
992	case SIOCSIFFLAGS: CT_DEBUG2 (d, ("SIOCSIFFLAGS\n"));     break;
993	case SIOCSIFADDR:  CT_DEBUG2 (d, ("SIOCSIFADDR\n"));      break;
994	}
995
996	/* We get here only in case of SIFFLAGS or SIFADDR. */
997	s = splimp ();
998	should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
999	if (! was_up && should_be_up) {
1000		/* Interface goes up -- start it. */
1001		ct_up (d);
1002		ct_start (d);
1003	} else if (was_up && ! should_be_up) {
1004		/* Interface is going down -- stop it. */
1005		/* if ((d->pp.pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/
1006		ct_down (d);
1007	}
1008	splx (s);
1009	return 0;
1010}
1011#endif /*NETGRAPH*/
1012
1013/*
1014 * Stop the interface.  Called on splimp().
1015 */
1016static void ct_down (drv_t *d)
1017{
1018	int s = splimp ();
1019	CT_DEBUG (d, ("ct_down\n"));
1020	ct_set_dtr (d->chan, 0);
1021	ct_set_rts (d->chan, 0);
1022	d->running = 0;
1023	splx (s);
1024}
1025
1026/*
1027 * Start the interface.  Called on splimp().
1028 */
1029static void ct_up (drv_t *d)
1030{
1031	int s = splimp ();
1032	CT_DEBUG (d, ("ct_up\n"));
1033	ct_set_dtr (d->chan, 1);
1034	ct_set_rts (d->chan, 1);
1035	d->running = 1;
1036	splx (s);
1037}
1038
1039/*
1040 * Start output on the (slave) interface.  Get another datagram to send
1041 * off of the interface queue, and copy it to the interface
1042 * before starting the output.
1043 */
1044static void ct_send (drv_t *d)
1045{
1046	struct mbuf *m;
1047	u_short len;
1048
1049	CT_DEBUG2 (d, ("ct_send, tn=%d\n", d->chan->tn));
1050
1051	/* No output if the interface is down. */
1052	if (! d->running)
1053		return;
1054
1055	/* No output if the modem is off. */
1056	if (! ct_get_dsr (d->chan) && !ct_get_loop (d->chan))
1057		return;
1058
1059	while (ct_buf_free (d->chan)) {
1060		/* Get the packet to send. */
1061#ifdef NETGRAPH
1062		IF_DEQUEUE (&d->hi_queue, m);
1063		if (! m)
1064			IF_DEQUEUE (&d->queue, m);
1065#else
1066		m = sppp_dequeue (&d->pp.pp_if);
1067#endif
1068		if (! m)
1069			return;
1070#if (__FreeBSD_version >= 400000 || NBPFILTER > 0) && !defined (NETGRAPH)
1071		if (d->pp.pp_if.if_bpf)
1072#if __FreeBSD_version >= 500000
1073			BPF_MTAP (&d->pp.pp_if, m);
1074#else
1075			bpf_mtap (&d->pp.pp_if, m);
1076#endif
1077#endif
1078		len = m->m_pkthdr.len;
1079		if (! m->m_next)
1080			ct_send_packet (d->chan, (u_char*)mtod (m, caddr_t),
1081				len, 0);
1082		else {
1083			m_copydata (m, 0, len, d->chan->tbuf[d->chan->te]);
1084			ct_send_packet (d->chan, d->chan->tbuf[d->chan->te],
1085				len, 0);
1086		}
1087		m_freem (m);
1088
1089		/* Set up transmit timeout, if the transmit ring is not empty.
1090		 * Transmit timeout is 10 seconds. */
1091#ifdef NETGRAPH
1092		d->timeout = 10;
1093#else
1094		d->pp.pp_if.if_timer = 10;
1095#endif
1096	}
1097#ifndef NETGRAPH
1098	d->pp.pp_if.if_flags |= IFF_OACTIVE;
1099#endif
1100}
1101
1102/*
1103 * Start output on the interface.
1104 * Always called on splimp().
1105 */
1106static void ct_start (drv_t *d)
1107{
1108	int s = splimp ();
1109
1110	if (d->running) {
1111		if (! d->chan->dtr)
1112			ct_set_dtr (d->chan, 1);
1113		if (! d->chan->rts)
1114			ct_set_rts (d->chan, 1);
1115		ct_send (d);
1116	}
1117
1118	splx (s);
1119}
1120
1121/*
1122 * Handle transmit timeouts.
1123 * Recover after lost transmit interrupts.
1124 * Always called on splimp().
1125 */
1126static void ct_watchdog (drv_t *d)
1127{
1128	int s = splimp ();
1129
1130	CT_DEBUG (d, ("device timeout\n"));
1131	if (d->running) {
1132		ct_setup_chan (d->chan);
1133		ct_start_chan (d->chan, 0, 0);
1134		ct_set_dtr (d->chan, 1);
1135		ct_set_rts (d->chan, 1);
1136		ct_start (d);
1137	}
1138
1139	splx (s);
1140}
1141
1142/*
1143 * Transmit callback function.
1144 */
1145static void ct_transmit (ct_chan_t *c, void *attachment, int len)
1146{
1147	drv_t *d = c->sys;
1148
1149	if (!d)
1150		return;
1151#ifdef NETGRAPH
1152	d->timeout = 0;
1153#else
1154	++d->pp.pp_if.if_opackets;
1155	d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1156	d->pp.pp_if.if_timer = 0;
1157#endif
1158	ct_start (d);
1159}
1160
1161/*
1162 * Process the received packet.
1163 */
1164static void ct_receive (ct_chan_t *c, char *data, int len)
1165{
1166	drv_t *d = c->sys;
1167	struct mbuf *m;
1168#if __FreeBSD_version >= 500000 && defined NETGRAPH
1169	int error;
1170#endif
1171
1172	if (!d || !d->running)
1173		return;
1174
1175	m = makembuf (data, len);
1176	if (! m) {
1177		CT_DEBUG (d, ("no memory for packet\n"));
1178#ifndef NETGRAPH
1179		++d->pp.pp_if.if_iqdrops;
1180#endif
1181		return;
1182	}
1183	if (c->debug > 1)
1184		printmbuf (m);
1185#ifdef NETGRAPH
1186	m->m_pkthdr.rcvif = 0;
1187#if __FreeBSD_version >= 500000
1188	NG_SEND_DATA_ONLY (error, d->hook, m);
1189#else
1190	ng_queue_data (d->hook, m, 0);
1191#endif
1192#else
1193	++d->pp.pp_if.if_ipackets;
1194	m->m_pkthdr.rcvif = &d->pp.pp_if;
1195#if __FreeBSD_version >= 400000 || NBPFILTER > 0
1196	/* Check if there's a BPF listener on this interface.
1197	 * If so, hand off the raw packet to bpf. */
1198	if (d->pp.pp_if.if_bpf)
1199#if __FreeBSD_version >= 500000
1200		BPF_TAP (&d->pp.pp_if, data, len);
1201#else
1202		bpf_tap (&d->pp.pp_if, data, len);
1203#endif
1204#endif
1205	sppp_input (&d->pp.pp_if, m);
1206#endif
1207}
1208
1209/*
1210 * Error callback function.
1211 */
1212static void ct_error (ct_chan_t *c, int data)
1213{
1214	drv_t *d = c->sys;
1215
1216	if (!d)
1217		return;
1218
1219	switch (data) {
1220	case CT_FRAME:
1221		CT_DEBUG (d, ("frame error\n"));
1222#ifndef NETGRAPH
1223		++d->pp.pp_if.if_ierrors;
1224#endif
1225		break;
1226	case CT_CRC:
1227		CT_DEBUG (d, ("crc error\n"));
1228#ifndef NETGRAPH
1229		++d->pp.pp_if.if_ierrors;
1230#endif
1231		break;
1232	case CT_OVERRUN:
1233		CT_DEBUG (d, ("overrun error\n"));
1234#ifndef NETGRAPH
1235		++d->pp.pp_if.if_collisions;
1236		++d->pp.pp_if.if_ierrors;
1237#endif
1238		break;
1239	case CT_OVERFLOW:
1240		CT_DEBUG (d, ("overflow error\n"));
1241#ifndef NETGRAPH
1242		++d->pp.pp_if.if_ierrors;
1243#endif
1244		break;
1245	case CT_UNDERRUN:
1246		CT_DEBUG (d, ("underrun error\n"));
1247#ifdef NETGRAPH
1248		d->timeout = 0;
1249#else
1250		++d->pp.pp_if.if_oerrors;
1251		d->pp.pp_if.if_flags &= ~IFF_OACTIVE;
1252		d->pp.pp_if.if_timer = 0;
1253#endif
1254		ct_start (d);
1255		break;
1256	default:
1257		CT_DEBUG (d, ("error #%d\n", data));
1258	}
1259}
1260
1261#if __FreeBSD_version < 500000
1262static int ct_open (dev_t dev, int oflags, int devtype, struct proc *p)
1263#else
1264static int ct_open (dev_t dev, int oflags, int devtype, struct thread *td)
1265#endif
1266{
1267	drv_t *d;
1268
1269	if (minor(dev) >= NCTAU*NCHAN || ! (d = channel[minor(dev)]))
1270		return ENXIO;
1271
1272	CT_DEBUG2 (d, ("ct_open\n"));
1273	return 0;
1274}
1275
1276#if __FreeBSD_version < 500000
1277static int ct_close (dev_t dev, int fflag, int devtype, struct proc *p)
1278#else
1279static int ct_close (dev_t dev, int fflag, int devtype, struct thread *td)
1280#endif
1281{
1282	drv_t *d = channel [minor(dev)];
1283
1284	if (!d)
1285		return 0;
1286
1287	CT_DEBUG2 (d, ("ct_close\n"));
1288	return 0;
1289}
1290
1291static int ct_modem_status (ct_chan_t *c)
1292{
1293	drv_t *d = c->sys;
1294	int status, s;
1295
1296	if (!d)
1297		return 0;
1298
1299	status = d->running ? TIOCM_LE : 0;
1300	s = splimp ();
1301	if (ct_get_cd  (c)) status |= TIOCM_CD;
1302	if (ct_get_cts (c)) status |= TIOCM_CTS;
1303	if (ct_get_dsr (c)) status |= TIOCM_DSR;
1304	if (c->dtr)	    status |= TIOCM_DTR;
1305	if (c->rts)	    status |= TIOCM_RTS;
1306	splx (s);
1307	return status;
1308}
1309
1310/*
1311 * Process an ioctl request on /dev/cronyx/ctauN.
1312 */
1313#if __FreeBSD_version < 500000
1314static int ct_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1315#else
1316static int ct_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1317#endif
1318{
1319	drv_t *d = channel [minor (dev)];
1320	ct_chan_t *c;
1321	struct serial_statistics *st;
1322	struct e1_statistics *opte1;
1323	int error, s;
1324	char mask[16];
1325
1326	if (!d || !d->chan)
1327		return 0;
1328
1329	c = d->chan;
1330
1331	switch (cmd) {
1332	case SERIAL_GETREGISTERED:
1333		bzero (mask, sizeof(mask));
1334		for (s=0; s<NCTAU*NCHAN; ++s)
1335			if (channel [s])
1336				mask [s/8] |= 1 << (s & 7);
1337	        bcopy (mask, data, sizeof (mask));
1338		return 0;
1339
1340#ifndef NETGRAPH
1341	case SERIAL_GETPROTO:
1342	        strcpy ((char*)data, (d->pp.pp_flags & PP_FR) ? "fr" :
1343	                (d->pp.pp_if.if_flags & PP_CISCO) ? "cisco" : "ppp");
1344	        return 0;
1345
1346	case SERIAL_SETPROTO:
1347	        /* Only for superuser! */
1348#if __FreeBSD_version < 400000
1349	        error = suser (p->p_ucred, &p->p_acflag);
1350#elif __FreeBSD_version < 500000
1351	        error = suser (p);
1352#else /* __FreeBSD_version >= 500000 */
1353	        error = suser (td);
1354#endif /* __FreeBSD_version >= 500000 */
1355	        if (error)
1356	                return error;
1357		if (d->pp.pp_if.if_flags & IFF_RUNNING)
1358			return EBUSY;
1359	        if (! strcmp ("cisco", (char*)data)) {
1360	                d->pp.pp_flags &= ~(PP_FR);
1361	                d->pp.pp_flags |= PP_KEEPALIVE;
1362	                d->pp.pp_if.if_flags |= PP_CISCO;
1363	        } else if (! strcmp ("fr", (char*)data)) {
1364	                d->pp.pp_if.if_flags &= ~(PP_CISCO);
1365	                d->pp.pp_flags |= PP_FR | PP_KEEPALIVE;
1366	        } else if (! strcmp ("ppp", (char*)data)) {
1367	                d->pp.pp_flags &= ~(PP_FR | PP_KEEPALIVE);
1368	                d->pp.pp_if.if_flags &= ~(PP_CISCO);
1369	        } else
1370			return EINVAL;
1371	        return 0;
1372
1373	case SERIAL_GETKEEPALIVE:
1374		if ((d->pp.pp_flags & PP_FR) ||
1375			(d->pp.pp_if.if_flags & PP_CISCO))
1376			return EINVAL;
1377	        *(int*)data = (d->pp.pp_flags & PP_KEEPALIVE) ? 1 : 0;
1378	        return 0;
1379
1380	case SERIAL_SETKEEPALIVE:
1381	        /* Only for superuser! */
1382#if __FreeBSD_version < 400000
1383	        error = suser (p->p_ucred, &p->p_acflag);
1384#elif __FreeBSD_version < 500000
1385	        error = suser (p);
1386#else /* __FreeBSD_version >= 500000 */
1387	        error = suser (td);
1388#endif /* __FreeBSD_version >= 500000 */
1389	        if (error)
1390	                return error;
1391		if ((d->pp.pp_flags & PP_FR) ||
1392			(d->pp.pp_if.if_flags & PP_CISCO))
1393			return EINVAL;
1394	        if (*(int*)data)
1395	                d->pp.pp_flags |= PP_KEEPALIVE;
1396		else
1397	                d->pp.pp_flags &= ~PP_KEEPALIVE;
1398	        return 0;
1399#endif /*NETGRAPH*/
1400
1401	case SERIAL_GETMODE:
1402		*(int*)data = SERIAL_HDLC;
1403	        return 0;
1404
1405	case SERIAL_GETCFG:
1406		if (c->mode == M_HDLC)
1407			return EINVAL;
1408		switch (ct_get_config (c->board)) {
1409		default:    *(char*)data = 'a'; break;
1410		case CFG_B: *(char*)data = 'b'; break;
1411		case CFG_C: *(char*)data = 'c'; break;
1412		}
1413	        return 0;
1414
1415	case SERIAL_SETCFG:
1416	        /* Only for superuser! */
1417#if __FreeBSD_version < 400000
1418	        error = suser (p->p_ucred, &p->p_acflag);
1419#elif __FreeBSD_version < 500000
1420	        error = suser (p);
1421#else /* __FreeBSD_version >= 500000 */
1422	        error = suser (td);
1423#endif /* __FreeBSD_version >= 500000 */
1424	        if (error)
1425	                return error;
1426		if (c->mode == M_HDLC)
1427			return EINVAL;
1428	        s = splimp ();
1429		switch (*(char*)data) {
1430		case 'a': ct_set_config (c->board, CFG_A); break;
1431		case 'b': ct_set_config (c->board, CFG_B); break;
1432		case 'c': ct_set_config (c->board, CFG_C); break;
1433		}
1434	        splx (s);
1435                return 0;
1436
1437	case SERIAL_GETSTAT:
1438	        st = (struct serial_statistics*) data;
1439	        st->rintr  = c->rintr;
1440	        st->tintr  = c->tintr;
1441	        st->mintr  = c->mintr;
1442	        st->ibytes = c->ibytes;
1443	        st->ipkts  = c->ipkts;
1444	        st->ierrs  = c->ierrs;
1445	        st->obytes = c->obytes;
1446	        st->opkts  = c->opkts;
1447	        st->oerrs  = c->oerrs;
1448	        return 0;
1449
1450	case SERIAL_GETESTAT:
1451		opte1 = (struct e1_statistics*)data;
1452		opte1->status	   = c->status;
1453		opte1->cursec	   = c->cursec;
1454		opte1->totsec	   = c->totsec + c->cursec;
1455
1456		opte1->currnt.bpv   = c->currnt.bpv;
1457		opte1->currnt.fse   = c->currnt.fse;
1458		opte1->currnt.crce  = c->currnt.crce;
1459		opte1->currnt.rcrce = c->currnt.rcrce;
1460		opte1->currnt.uas   = c->currnt.uas;
1461		opte1->currnt.les   = c->currnt.les;
1462		opte1->currnt.es    = c->currnt.es;
1463		opte1->currnt.bes   = c->currnt.bes;
1464		opte1->currnt.ses   = c->currnt.ses;
1465		opte1->currnt.oofs  = c->currnt.oofs;
1466		opte1->currnt.css   = c->currnt.css;
1467		opte1->currnt.dm    = c->currnt.dm;
1468
1469		opte1->total.bpv   = c->total.bpv   + c->currnt.bpv;
1470		opte1->total.fse   = c->total.fse   + c->currnt.fse;
1471		opte1->total.crce  = c->total.crce  + c->currnt.crce;
1472		opte1->total.rcrce = c->total.rcrce + c->currnt.rcrce;
1473		opte1->total.uas   = c->total.uas   + c->currnt.uas;
1474		opte1->total.les   = c->total.les   + c->currnt.les;
1475		opte1->total.es	   = c->total.es    + c->currnt.es;
1476		opte1->total.bes   = c->total.bes   + c->currnt.bes;
1477		opte1->total.ses   = c->total.ses   + c->currnt.ses;
1478		opte1->total.oofs  = c->total.oofs  + c->currnt.oofs;
1479		opte1->total.css   = c->total.css   + c->currnt.css;
1480		opte1->total.dm	   = c->total.dm    + c->currnt.dm;
1481		for (s=0; s<48; ++s) {
1482			opte1->interval[s].bpv   = c->interval[s].bpv;
1483			opte1->interval[s].fse   = c->interval[s].fse;
1484			opte1->interval[s].crce  = c->interval[s].crce;
1485			opte1->interval[s].rcrce = c->interval[s].rcrce;
1486			opte1->interval[s].uas   = c->interval[s].uas;
1487			opte1->interval[s].les   = c->interval[s].les;
1488			opte1->interval[s].es	 = c->interval[s].es;
1489			opte1->interval[s].bes   = c->interval[s].bes;
1490			opte1->interval[s].ses   = c->interval[s].ses;
1491			opte1->interval[s].oofs  = c->interval[s].oofs;
1492			opte1->interval[s].css   = c->interval[s].css;
1493			opte1->interval[s].dm	 = c->interval[s].dm;
1494		}
1495		return 0;
1496
1497	case SERIAL_CLRSTAT:
1498	        /* Only for superuser! */
1499#if __FreeBSD_version < 400000
1500	        error = suser (p->p_ucred, &p->p_acflag);
1501#elif __FreeBSD_version < 500000
1502	        error = suser (p);
1503#else /* __FreeBSD_version >= 500000 */
1504	        error = suser (td);
1505#endif /* __FreeBSD_version >= 500000 */
1506	        if (error)
1507	                return error;
1508	        c->rintr = 0;
1509	        c->tintr = 0;
1510	        c->mintr = 0;
1511	        c->ibytes = 0;
1512	        c->ipkts = 0;
1513	        c->ierrs = 0;
1514	        c->obytes = 0;
1515	        c->opkts = 0;
1516	        c->oerrs = 0;
1517		bzero (&c->currnt, sizeof (c->currnt));
1518		bzero (&c->total, sizeof (c->total));
1519		bzero (c->interval, sizeof (c->interval));
1520	        return 0;
1521
1522	case SERIAL_GETBAUD:
1523	        *(long*)data = ct_get_baud(c);
1524	        return 0;
1525
1526	case SERIAL_SETBAUD:
1527	        /* Only for superuser! */
1528#if __FreeBSD_version < 400000
1529	        error = suser (p->p_ucred, &p->p_acflag);
1530#elif __FreeBSD_version < 500000
1531	        error = suser (p);
1532#else /* __FreeBSD_version >= 500000 */
1533	        error = suser (td);
1534#endif /* __FreeBSD_version >= 500000 */
1535	        if (error)
1536	                return error;
1537	        s = splimp ();
1538	        ct_set_baud (c, *(long*)data);
1539	        splx (s);
1540	        return 0;
1541
1542	case SERIAL_GETLOOP:
1543	        *(int*)data = ct_get_loop (c);
1544	        return 0;
1545
1546	case SERIAL_SETLOOP:
1547	        /* Only for superuser! */
1548#if __FreeBSD_version < 400000
1549	        error = suser (p->p_ucred, &p->p_acflag);
1550#elif __FreeBSD_version < 500000
1551	        error = suser (p);
1552#else /* __FreeBSD_version >= 500000 */
1553	        error = suser (td);
1554#endif /* __FreeBSD_version >= 500000 */
1555	        if (error)
1556	                return error;
1557	        s = splimp ();
1558		ct_set_loop (c, *(int*)data);
1559	        splx (s);
1560	        return 0;
1561
1562	case SERIAL_GETDPLL:
1563	        if (c->mode == M_E1 || c->mode == M_G703)
1564	                return EINVAL;
1565		*(int*)data = ct_get_dpll (c);
1566	        return 0;
1567
1568	case SERIAL_SETDPLL:
1569	        /* Only for superuser! */
1570#if __FreeBSD_version < 400000
1571	        error = suser (p->p_ucred, &p->p_acflag);
1572#elif __FreeBSD_version < 500000
1573	        error = suser (p);
1574#else /* __FreeBSD_version >= 500000 */
1575	        error = suser (td);
1576#endif /* __FreeBSD_version >= 500000 */
1577	        if (error)
1578	                return error;
1579	        if (c->mode == M_E1 || c->mode == M_G703)
1580	                return EINVAL;
1581	        s = splimp ();
1582	        ct_set_dpll (c, *(int*)data);
1583	        splx (s);
1584	        return 0;
1585
1586	case SERIAL_GETNRZI:
1587	        if (c->mode == M_E1 || c->mode == M_G703)
1588	                return EINVAL;
1589	        *(int*)data = ct_get_nrzi (c);
1590	        return 0;
1591
1592	case SERIAL_SETNRZI:
1593	        /* Only for superuser! */
1594#if __FreeBSD_version < 400000
1595	        error = suser (p->p_ucred, &p->p_acflag);
1596#elif __FreeBSD_version < 500000
1597	        error = suser (p);
1598#else /* __FreeBSD_version >= 500000 */
1599	        error = suser (td);
1600#endif /* __FreeBSD_version >= 500000 */
1601	        if (error)
1602	                return error;
1603	        if (c->mode == M_E1 || c->mode == M_G703)
1604	                return EINVAL;
1605	        s = splimp ();
1606	        ct_set_nrzi (c, *(int*)data);
1607	        splx (s);
1608	        return 0;
1609
1610	case SERIAL_GETDEBUG:
1611	        *(int*)data = c->debug;
1612	        return 0;
1613
1614	case SERIAL_SETDEBUG:
1615	        /* Only for superuser! */
1616#if __FreeBSD_version < 400000
1617	        error = suser (p->p_ucred, &p->p_acflag);
1618#elif __FreeBSD_version < 500000
1619	        error = suser (p);
1620#else /* __FreeBSD_version >= 500000 */
1621	        error = suser (td);
1622#endif /* __FreeBSD_version >= 500000 */
1623	        if (error)
1624	                return error;
1625	        c->debug = *(int*)data;
1626#ifndef	NETGRAPH
1627		if (d->chan->debug)
1628			d->pp.pp_if.if_flags |= IFF_DEBUG;
1629		else
1630			d->pp.pp_if.if_flags &= (~IFF_DEBUG);
1631#endif
1632	        return 0;
1633
1634	case SERIAL_GETHIGAIN:
1635	        if (c->mode != M_E1)
1636	                return EINVAL;
1637	        *(int*)data = ct_get_higain (c);
1638		return 0;
1639
1640	case SERIAL_SETHIGAIN:
1641	        /* Only for superuser! */
1642#if __FreeBSD_version < 400000
1643	        error = suser (p->p_ucred, &p->p_acflag);
1644#elif __FreeBSD_version < 500000
1645	        error = suser (p);
1646#else /* __FreeBSD_version >= 500000 */
1647	        error = suser (td);
1648#endif /* __FreeBSD_version >= 500000 */
1649	        if (error)
1650	                return error;
1651		s = splimp ();
1652		ct_set_higain (c, *(int*)data);
1653		splx (s);
1654		return 0;
1655
1656	case SERIAL_GETPHONY:
1657		CT_DEBUG2 (d, ("ioctl: getphony\n"));
1658	        if (c->mode != M_E1)
1659	                return EINVAL;
1660	        *(int*)data = c->gopt.phony;
1661		return 0;
1662
1663	case SERIAL_SETPHONY:
1664		CT_DEBUG2 (d, ("ioctl: setphony\n"));
1665	        if (c->mode != M_E1)
1666	                return EINVAL;
1667	        /* Only for superuser! */
1668#if __FreeBSD_version < 400000
1669	        error = suser (p->p_ucred, &p->p_acflag);
1670#elif __FreeBSD_version < 500000
1671	        error = suser (p);
1672#else /* __FreeBSD_version >= 500000 */
1673	        error = suser (td);
1674#endif /* __FreeBSD_version >= 500000 */
1675	        if (error)
1676	                return error;
1677		s = splimp ();
1678		ct_set_phony (c, *(int*)data);
1679		splx (s);
1680		return 0;
1681
1682	case SERIAL_GETCLK:
1683	        if (c->mode != M_E1 && c->mode != M_G703)
1684	                return EINVAL;
1685		switch (ct_get_clk(c)) {
1686		default:         *(int*)data = E1CLK_INTERNAL;          break;
1687		case GCLK_RCV:   *(int*)data = E1CLK_RECEIVE;	        break;
1688		case GCLK_RCLKO: *(int*)data = c->num ?
1689			E1CLK_RECEIVE_CHAN0 : E1CLK_RECEIVE_CHAN1;	break;
1690		}
1691		return 0;
1692
1693	case SERIAL_SETCLK:
1694	        /* Only for superuser! */
1695#if __FreeBSD_version < 400000
1696	        error = suser (p->p_ucred, &p->p_acflag);
1697#elif __FreeBSD_version < 500000
1698	        error = suser (p);
1699#else /* __FreeBSD_version >= 500000 */
1700	        error = suser (td);
1701#endif /* __FreeBSD_version >= 500000 */
1702	        if (error)
1703	                return error;
1704		s = splimp ();
1705		switch (*(int*)data) {
1706		default:                    ct_set_clk (c, GCLK_INT);   break;
1707		case E1CLK_RECEIVE:	    ct_set_clk (c, GCLK_RCV);   break;
1708		case E1CLK_RECEIVE_CHAN0:
1709		case E1CLK_RECEIVE_CHAN1:
1710					    ct_set_clk (c, GCLK_RCLKO); break;
1711		}
1712		splx (s);
1713		return 0;
1714
1715	case SERIAL_GETTIMESLOTS:
1716	        if (c->mode != M_E1)
1717	                return EINVAL;
1718	        *(long*)data = ct_get_ts (c);
1719		return 0;
1720
1721	case SERIAL_SETTIMESLOTS:
1722	        /* Only for superuser! */
1723#if __FreeBSD_version < 400000
1724	        error = suser (p->p_ucred, &p->p_acflag);
1725#elif __FreeBSD_version < 500000
1726	        error = suser (p);
1727#else /* __FreeBSD_version >= 500000 */
1728	        error = suser (td);
1729#endif /* __FreeBSD_version >= 500000 */
1730	        if (error)
1731	                return error;
1732		s = splimp ();
1733		ct_set_ts (c, *(long*)data);
1734		splx (s);
1735		return 0;
1736
1737	case SERIAL_GETSUBCHAN:
1738	        if (c->mode != M_E1)
1739	                return EINVAL;
1740	        *(long*)data = ct_get_subchan (c->board);
1741		return 0;
1742
1743	case SERIAL_SETSUBCHAN:
1744	        /* Only for superuser! */
1745#if __FreeBSD_version < 400000
1746	        error = suser (p->p_ucred, &p->p_acflag);
1747#elif __FreeBSD_version < 500000
1748	        error = suser (p);
1749#else /* __FreeBSD_version >= 500000 */
1750	        error = suser (td);
1751#endif /* __FreeBSD_version >= 500000 */
1752	        if (error)
1753	                return error;
1754		s = splimp ();
1755		ct_set_subchan (c->board, *(long*)data);
1756		splx (s);
1757		return 0;
1758
1759	case SERIAL_GETINVCLK:
1760	case SERIAL_GETINVTCLK:
1761	        if (c->mode == M_E1 || c->mode == M_G703)
1762	                return EINVAL;
1763	        *(int*)data = ct_get_invtxc (c);
1764		return 0;
1765
1766	case SERIAL_GETINVRCLK:
1767	        if (c->mode == M_E1 || c->mode == M_G703)
1768	                return EINVAL;
1769	        *(int*)data = ct_get_invrxc (c);
1770		return 0;
1771
1772	case SERIAL_SETINVCLK:
1773	case SERIAL_SETINVTCLK:
1774	        /* Only for superuser! */
1775#if __FreeBSD_version < 400000
1776	        error = suser (p->p_ucred, &p->p_acflag);
1777#elif __FreeBSD_version < 500000
1778	        error = suser (p);
1779#else /* __FreeBSD_version >= 500000 */
1780	        error = suser (td);
1781#endif /* __FreeBSD_version >= 500000 */
1782	        if (error)
1783	                return error;
1784	        if (c->mode == M_E1 || c->mode == M_G703)
1785	                return EINVAL;
1786		s = splimp ();
1787		ct_set_invtxc (c, *(int*)data);
1788		splx (s);
1789		return 0;
1790
1791	case SERIAL_SETINVRCLK:
1792	        /* Only for superuser! */
1793#if __FreeBSD_version < 400000
1794	        error = suser (p->p_ucred, &p->p_acflag);
1795#elif __FreeBSD_version < 500000
1796	        error = suser (p);
1797#else /* __FreeBSD_version >= 500000 */
1798	        error = suser (td);
1799#endif /* __FreeBSD_version >= 500000 */
1800	        if (error)
1801	                return error;
1802	        if (c->mode == M_E1 || c->mode == M_G703)
1803	                return EINVAL;
1804		s = splimp ();
1805		ct_set_invrxc (c, *(int*)data);
1806		splx (s);
1807		return 0;
1808
1809	case SERIAL_GETLEVEL:
1810	        if (c->mode != M_G703)
1811	                return EINVAL;
1812		s = splimp ();
1813		*(int*)data = ct_get_lq (c);
1814		splx (s);
1815		return 0;
1816
1817	case TIOCSDTR:          /* Set DTR */
1818		s = splimp ();
1819		ct_set_dtr (c, 1);
1820		splx (s);
1821		return 0;
1822
1823	case TIOCCDTR:          /* Clear DTR */
1824		s = splimp ();
1825		ct_set_dtr (c, 0);
1826		splx (s);
1827		return 0;
1828
1829	case TIOCMSET:          /* Set DTR/RTS */
1830		s = splimp ();
1831		ct_set_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
1832		ct_set_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
1833		splx (s);
1834		return 0;
1835
1836	case TIOCMBIS:          /* Add DTR/RTS */
1837		s = splimp ();
1838		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 1);
1839		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 1);
1840		splx (s);
1841		return 0;
1842
1843	case TIOCMBIC:          /* Clear DTR/RTS */
1844		s = splimp ();
1845		if (*(int*)data & TIOCM_DTR) ct_set_dtr (c, 0);
1846		if (*(int*)data & TIOCM_RTS) ct_set_rts (c, 0);
1847		splx (s);
1848		return 0;
1849
1850	case TIOCMGET:          /* Get modem status */
1851		*(int*)data = ct_modem_status (c);
1852		return 0;
1853	}
1854	return ENOTTY;
1855}
1856
1857#if __FreeBSD_version < 400000
1858struct isa_driver ctdriver = { ct_probe, ct_attach, "ct" };
1859static struct cdevsw ct_cdevsw = {
1860	ct_open,	ct_close,	noread,		nowrite,
1861	ct_ioctl,	nostop,		noreset,	nodevtotty,
1862	seltrue,	nommap,		NULL,		"ct",
1863	NULL,		-1,
1864};
1865#elif __FreeBSD_version < 500000
1866static struct cdevsw ct_cdevsw = {
1867	ct_open,	ct_close,	noread,		nowrite,
1868	ct_ioctl,	nopoll,		nommap,		nostrategy,
1869	"ct",		CDEV_MAJOR,	nodump,		nopsize,
1870	D_NAGGED,	-1
1871};
1872#elif __FreeBSD_version == 500000
1873static struct cdevsw ct_cdevsw = {
1874	ct_open,	ct_close,	noread,		nowrite,
1875	ct_ioctl,	nopoll,		nommap,		nostrategy,
1876	"ct",		CDEV_MAJOR,	nodump,		nopsize,
1877	D_NAGGED,
1878	};
1879#elif __FreeBSD_version <= 501000
1880static struct cdevsw ct_cdevsw = {
1881	.d_open     = ct_open,
1882	.d_close    = ct_close,
1883	.d_read     = noread,
1884	.d_write    = nowrite,
1885	.d_ioctl    = ct_ioctl,
1886	.d_poll     = nopoll,
1887	.d_mmap	    = nommap,
1888	.d_strategy = nostrategy,
1889	.d_name     = "ct",
1890	.d_maj      = CDEV_MAJOR,
1891	.d_dump     = nodump,
1892	.d_flags    = D_NAGGED,
1893};
1894#elif __FreeBSD_version < 502103
1895static struct cdevsw ct_cdevsw = {
1896	.d_open     = ct_open,
1897	.d_close    = ct_close,
1898	.d_ioctl    = ct_ioctl,
1899	.d_name     = "ct",
1900	.d_maj      = CDEV_MAJOR,
1901	.d_flags    = D_NAGGED,
1902};
1903#else /* __FreeBSD_version >= 502103 */
1904static struct cdevsw ct_cdevsw = {
1905	.d_version  = D_VERSION,
1906	.d_open     = ct_open,
1907	.d_close    = ct_close,
1908	.d_ioctl    = ct_ioctl,
1909	.d_name     = "ct",
1910	.d_maj      = CDEV_MAJOR,
1911	.d_flags    = D_NEEDGIANT,
1912};
1913#endif /* __FreeBSD_version > 501000 */
1914
1915#ifdef NETGRAPH
1916#if __FreeBSD_version >= 500000
1917static int ng_ct_constructor (node_p node)
1918{
1919	drv_t *d = NG_NODE_PRIVATE (node);
1920#else
1921static int ng_ct_constructor (node_p *node)
1922{
1923	drv_t *d = (*node)->private;
1924#endif
1925	CT_DEBUG (d, ("Constructor\n"));
1926	return EINVAL;
1927}
1928
1929static int ng_ct_newhook (node_p node, hook_p hook, const char *name)
1930{
1931	int s;
1932#if __FreeBSD_version >= 500000
1933	drv_t *d = NG_NODE_PRIVATE (node);
1934#else
1935	drv_t *d = node->private;
1936#endif
1937
1938	if (!d)
1939		return EINVAL;
1940
1941	/* Attach debug hook */
1942	if (strcmp (name, NG_CT_HOOK_DEBUG) == 0) {
1943#if __FreeBSD_version >= 500000
1944		NG_HOOK_SET_PRIVATE (hook, NULL);
1945#else
1946		hook->private = 0;
1947#endif
1948		d->debug_hook = hook;
1949		return 0;
1950	}
1951
1952	/* Check for raw hook */
1953	if (strcmp (name, NG_CT_HOOK_RAW) != 0)
1954		return EINVAL;
1955
1956#if __FreeBSD_version >= 500000
1957	NG_HOOK_SET_PRIVATE (hook, d);
1958#else
1959	hook->private = d;
1960#endif
1961	d->hook = hook;
1962	s = splimp ();
1963	ct_up (d);
1964	splx (s);
1965	return 0;
1966}
1967
1968static char *format_timeslots (u_long s)
1969{
1970	static char buf [100];
1971	char *p = buf;
1972	int i;
1973
1974	for (i=1; i<32; ++i)
1975		if ((s >> i) & 1) {
1976			int prev = (i > 1)  & (s >> (i-1));
1977			int next = (i < 31) & (s >> (i+1));
1978
1979			if (prev) {
1980				if (next)
1981					continue;
1982				*p++ = '-';
1983			} else if (p > buf)
1984				*p++ = ',';
1985
1986			if (i >= 10)
1987				*p++ = '0' + i / 10;
1988			*p++ = '0' + i % 10;
1989		}
1990	*p = 0;
1991	return buf;
1992}
1993
1994static int print_modems (char *s, ct_chan_t *c, int need_header)
1995{
1996	int status = ct_modem_status (c);
1997	int length = 0;
1998
1999	if (need_header)
2000		length += sprintf (s + length, "  LE   DTR  DSR  RTS  CTS  CD\n");
2001	length += sprintf (s + length, "%4s %4s %4s %4s %4s %4s\n",
2002		status & TIOCM_LE  ? "On" : "-",
2003		status & TIOCM_DTR ? "On" : "-",
2004		status & TIOCM_DSR ? "On" : "-",
2005		status & TIOCM_RTS ? "On" : "-",
2006		status & TIOCM_CTS ? "On" : "-",
2007		status & TIOCM_CD  ? "On" : "-");
2008	return length;
2009}
2010
2011static int print_stats (char *s, ct_chan_t *c, int need_header)
2012{
2013	struct serial_statistics st;
2014	int length = 0;
2015
2016        st.rintr  = c->rintr;
2017        st.tintr  = c->tintr;
2018        st.mintr  = c->mintr;
2019        st.ibytes = c->ibytes;
2020        st.ipkts  = c->ipkts;
2021        st.ierrs  = c->ierrs;
2022        st.obytes = c->obytes;
2023        st.opkts  = c->opkts;
2024        st.oerrs  = c->oerrs;
2025	if (need_header)
2026		length += sprintf (s + length, "  Rintr   Tintr   Mintr   Ibytes   Ipkts   Ierrs   Obytes   Opkts   Oerrs\n");
2027	length += sprintf (s + length, "%7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n",
2028		st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts,
2029		st.ierrs, st.obytes, st.opkts, st.oerrs);
2030	return length;
2031}
2032
2033static char *format_e1_status (u_char status)
2034{
2035	static char buf [80];
2036
2037	if (status & E1_NOALARM)
2038		return "Ok";
2039	buf[0] = 0;
2040	if (status & E1_LOS)     strcat (buf, ",LOS");
2041	if (status & E1_AIS)     strcat (buf, ",AIS");
2042	if (status & E1_LOF)     strcat (buf, ",LOF");
2043	if (status & E1_LOMF)    strcat (buf, ",LOMF");
2044	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
2045	if (status & E1_AIS16)   strcat (buf, ",AIS16");
2046	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
2047	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");
2048	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");
2049	if (buf[0] == ',')
2050		return buf+1;
2051	return "Unknown";
2052}
2053
2054static int print_frac (char *s, int leftalign, u_long numerator, u_long divider)
2055{
2056	int n, length = 0;
2057
2058	if (numerator < 1 || divider < 1) {
2059		length += sprintf (s+length, leftalign ? "/-   " : "    -");
2060		return length;
2061	}
2062	n = (int) (0.5 + 1000.0 * numerator / divider);
2063	if (n < 1000) {
2064		length += sprintf (s+length, leftalign ? "/.%-3d" : " .%03d", n);
2065		return length;
2066	}
2067	*(s + length) = leftalign ? '/' : ' ';
2068	length ++;
2069
2070	if      (n >= 1000000) n = (n+500) / 1000 * 1000;
2071	else if (n >= 100000)  n = (n+50)  / 100 * 100;
2072	else if (n >= 10000)   n = (n+5)   / 10 * 10;
2073
2074	switch (n) {
2075	case 1000:    length += printf (s+length, ".999"); return length;
2076	case 10000:   n = 9990;   break;
2077	case 100000:  n = 99900;  break;
2078	case 1000000: n = 999000; break;
2079	}
2080	if (n < 10000)        length += sprintf (s+length, "%d.%d", n/1000, n/10%100);
2081	else if (n < 100000)  length += sprintf (s+length, "%d.%d", n/1000, n/100%10);
2082	else if (n < 1000000) length += sprintf (s+length, "%d.", n/1000);
2083	else                  length += sprintf (s+length, "%d", n/1000);
2084
2085	return length;
2086}
2087
2088static int print_e1_stats (char *s, ct_chan_t *c)
2089{
2090	struct e1_counters total;
2091	u_long totsec;
2092	int length = 0;
2093
2094	totsec		= c->totsec + c->cursec;
2095	total.bpv	= c->total.bpv   + c->currnt.bpv;
2096	total.fse	= c->total.fse   + c->currnt.fse;
2097	total.crce	= c->total.crce  + c->currnt.crce;
2098	total.rcrce	= c->total.rcrce + c->currnt.rcrce;
2099	total.uas	= c->total.uas   + c->currnt.uas;
2100	total.les	= c->total.les   + c->currnt.les;
2101	total.es	= c->total.es    + c->currnt.es;
2102	total.bes	= c->total.bes   + c->currnt.bes;
2103	total.ses	= c->total.ses   + c->currnt.ses;
2104	total.oofs	= c->total.oofs  + c->currnt.oofs;
2105	total.css	= c->total.css   + c->currnt.css;
2106	total.dm	= c->total.dm    + c->currnt.dm;
2107
2108	length += sprintf (s + length, " Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
2109
2110	/* Unavailable seconds, degraded minutes */
2111	length += print_frac (s + length, 0, c->currnt.uas, c->cursec);
2112	length += print_frac (s + length, 1, 60 * c->currnt.dm, c->cursec);
2113
2114	/* Bipolar violations, frame sync errors */
2115	length += print_frac (s + length, 0, c->currnt.bpv, c->cursec);
2116	length += print_frac (s + length, 1, c->currnt.fse, c->cursec);
2117
2118	/* CRC errors, remote CRC errors (E-bit) */
2119	length += print_frac (s + length, 0, c->currnt.crce, c->cursec);
2120	length += print_frac (s + length, 1, c->currnt.rcrce, c->cursec);
2121
2122	/* Errored seconds, line errored seconds */
2123	length += print_frac (s + length, 0, c->currnt.es, c->cursec);
2124	length += print_frac (s + length, 1, c->currnt.les, c->cursec);
2125
2126	/* Severely errored seconds, burst errored seconds */
2127	length += print_frac (s + length, 0, c->currnt.ses, c->cursec);
2128	length += print_frac (s + length, 1, c->currnt.bes, c->cursec);
2129
2130	/* Out of frame seconds, controlled slip seconds */
2131	length += print_frac (s + length, 0, c->currnt.oofs, c->cursec);
2132	length += print_frac (s + length, 1, c->currnt.css, c->cursec);
2133
2134	length += sprintf (s + length, " %s\n", format_e1_status (c->status));
2135
2136	/* Print total statistics. */
2137	length += print_frac (s + length, 0, total.uas, totsec);
2138	length += print_frac (s + length, 1, 60 * total.dm, totsec);
2139
2140	length += print_frac (s + length, 0, total.bpv, totsec);
2141	length += print_frac (s + length, 1, total.fse, totsec);
2142
2143	length += print_frac (s + length, 0, total.crce, totsec);
2144	length += print_frac (s + length, 1, total.rcrce, totsec);
2145
2146	length += print_frac (s + length, 0, total.es, totsec);
2147	length += print_frac (s + length, 1, total.les, totsec);
2148
2149	length += print_frac (s + length, 0, total.ses, totsec);
2150	length += print_frac (s + length, 1, total.bes, totsec);
2151
2152	length += print_frac (s + length, 0, total.oofs, totsec);
2153	length += print_frac (s + length, 1, total.css, totsec);
2154
2155	length += sprintf (s + length, " -- Total\n");
2156	return length;
2157}
2158
2159static int print_chan (char *s, ct_chan_t *c)
2160{
2161	drv_t *d = c->sys;
2162	int length = 0;
2163
2164	length += sprintf (s + length, "ct%d", c->board->num * NCHAN + c->num);
2165	if (d->chan->debug)
2166		length += sprintf (s + length, " debug=%d", d->chan->debug);
2167
2168	switch (ct_get_config (c->board)) {
2169	case CFG_A:	length += sprintf (s + length, " cfg=A");	break;
2170	case CFG_B:	length += sprintf (s + length, " cfg=B");	break;
2171	case CFG_C:	length += sprintf (s + length, " cfg=C");	break;
2172	default:	length += sprintf (s + length, " cfg=unknown"); break;
2173	}
2174
2175	if (ct_get_baud (c))
2176		length += sprintf (s + length, " %ld", ct_get_baud (c));
2177	else
2178		length += sprintf (s + length, " extclock");
2179
2180	if (c->mode == M_E1 || c->mode == M_G703)
2181		switch (ct_get_clk(c)) {
2182		case GCLK_INT   : length += sprintf (s + length, " syn=int");     break;
2183		case GCLK_RCV   : length += sprintf (s + length, " syn=rcv");     break;
2184		case GCLK_RCLKO  : length += sprintf (s + length, " syn=xrcv");    break;
2185		}
2186	if (c->mode == M_HDLC) {
2187		length += sprintf (s + length, " dpll=%s",   ct_get_dpll (c)   ? "on" : "off");
2188		length += sprintf (s + length, " nrzi=%s",   ct_get_nrzi (c)   ? "on" : "off");
2189		length += sprintf (s + length, " invtclk=%s", ct_get_invtxc (c) ? "on" : "off");
2190		length += sprintf (s + length, " invrclk=%s", ct_get_invrxc (c) ? "on" : "off");
2191	}
2192	if (c->mode == M_E1)
2193		length += sprintf (s + length, " higain=%s", ct_get_higain (c)? "on" : "off");
2194
2195	length += sprintf (s + length, " loop=%s", ct_get_loop (c) ? "on" : "off");
2196
2197	if (c->mode == M_E1)
2198		length += sprintf (s + length, " ts=%s", format_timeslots (ct_get_ts(c)));
2199	if (c->mode == M_E1 && ct_get_config (c->board) != CFG_A)
2200		length += sprintf (s + length, " pass=%s", format_timeslots (ct_get_subchan(c->board)));
2201	if (c->mode == M_G703) {
2202		int lq, x;
2203
2204		x = splimp ();
2205		lq = ct_get_lq (c);
2206		splx (x);
2207		length += sprintf (s + length, " (level=-%.1fdB)", lq / 10.0);
2208	}
2209	length += sprintf (s + length, "\n");
2210	return length;
2211}
2212
2213#if __FreeBSD_version >= 500000
2214static int ng_ct_rcvmsg (node_p node, item_p item, hook_p lasthook)
2215{
2216	drv_t *d = NG_NODE_PRIVATE (node);
2217	struct ng_mesg *msg;
2218#else
2219static int ng_ct_rcvmsg (node_p node, struct ng_mesg *msg,
2220	const char *retaddr, struct ng_mesg **rptr)
2221{
2222	drv_t *d = node->private;
2223#endif
2224	struct ng_mesg *resp = NULL;
2225	int error = 0;
2226
2227	if (!d)
2228		return EINVAL;
2229
2230	CT_DEBUG (d, ("Rcvmsg\n"));
2231#if __FreeBSD_version >= 500000
2232	NGI_GET_MSG (item, msg);
2233#endif
2234	switch (msg->header.typecookie) {
2235	default:
2236		error = EINVAL;
2237		break;
2238
2239	case NGM_CT_COOKIE:
2240		printf ("Don't forget to implement\n");
2241		error = EINVAL;
2242		break;
2243
2244	case NGM_GENERIC_COOKIE:
2245		switch (msg->header.cmd) {
2246		default:
2247			error = EINVAL;
2248			break;
2249
2250		case NGM_TEXT_STATUS: {
2251			char *s;
2252			int l = 0;
2253			int dl = sizeof (struct ng_mesg) + 730;
2254
2255#if __FreeBSD_version >= 500000
2256			NG_MKRESPONSE (resp, msg, dl, M_NOWAIT);
2257			if (! resp) {
2258				error = ENOMEM;
2259				break;
2260			}
2261#else
2262			MALLOC (resp, struct ng_mesg *, dl,
2263				M_NETGRAPH, M_NOWAIT);
2264			if (! resp) {
2265				error = ENOMEM;
2266				break;
2267			}
2268			bzero (resp, dl);
2269#endif
2270			s = (resp)->data;
2271			l += print_chan (s + l, d->chan);
2272			l += print_stats (s + l, d->chan, 1);
2273			l += print_modems (s + l, d->chan, 1);
2274			l += print_e1_stats (s + l, d->chan);
2275#if __FreeBSD_version < 500000
2276			(resp)->header.version = NG_VERSION;
2277			(resp)->header.arglen = strlen (s) + 1;
2278			(resp)->header.token = msg->header.token;
2279			(resp)->header.typecookie = NGM_CT_COOKIE;
2280			(resp)->header.cmd = msg->header.cmd;
2281#endif
2282			strncpy ((resp)->header.cmdstr, "status", NG_CMDSTRLEN);
2283			}
2284			break;
2285		}
2286		break;
2287	}
2288#if __FreeBSD_version >= 500000
2289	NG_RESPOND_MSG (error, node, item, resp);
2290	NG_FREE_MSG (msg);
2291#else
2292	*rptr = resp;
2293	FREE (msg, M_NETGRAPH);
2294#endif
2295	return error;
2296}
2297
2298#if __FreeBSD_version >= 500000
2299static int ng_ct_rcvdata (hook_p hook, item_p item)
2300{
2301	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE(hook));
2302	struct mbuf *m;
2303	meta_p meta;
2304#else
2305static int ng_ct_rcvdata (hook_p hook, struct mbuf *m, meta_p meta)
2306{
2307	drv_t *d = hook->node->private;
2308#endif
2309	struct ifqueue *q;
2310	int s;
2311
2312	if (!d)
2313		return ENETDOWN;
2314
2315#if __FreeBSD_version >= 500000
2316	NGI_GET_M (item, m);
2317	NGI_GET_META (item, meta);
2318	NG_FREE_ITEM (item);
2319	if (! NG_HOOK_PRIVATE (hook) || ! d) {
2320		NG_FREE_M (m);
2321		NG_FREE_META (meta);
2322#else
2323	if (! hook->private || ! d) {
2324		NG_FREE_DATA (m,meta);
2325#endif
2326		return ENETDOWN;
2327	}
2328	q = (meta && meta->priority > 0) ? &d->hi_queue : &d->queue;
2329	s = splimp ();
2330#if __FreeBSD_version >= 500000
2331	IF_LOCK (q);
2332	if (_IF_QFULL (q)) {
2333		_IF_DROP (q);
2334		IF_UNLOCK (q);
2335		splx (s);
2336		NG_FREE_M (m);
2337		NG_FREE_META (meta);
2338		return ENOBUFS;
2339	}
2340	_IF_ENQUEUE (q, m);
2341	IF_UNLOCK (q);
2342#else
2343	if (IF_QFULL (q)) {
2344		IF_DROP (q);
2345		splx (s);
2346		NG_FREE_DATA (m, meta);
2347		return ENOBUFS;
2348	}
2349	IF_ENQUEUE (q, m);
2350#endif
2351	ct_start (d);
2352	splx (s);
2353	return 0;
2354}
2355
2356static int ng_ct_rmnode (node_p node)
2357{
2358#if __FreeBSD_version >= 500000
2359	drv_t *d = NG_NODE_PRIVATE (node);
2360
2361	CT_DEBUG (d, ("Rmnode\n"));
2362	if (d && d->running) {
2363		int s = splimp ();
2364		ct_down (d);
2365		splx (s);
2366	}
2367#ifdef	KLD_MODULE
2368	if (node->nd_flags & NG_REALLY_DIE) {
2369		NG_NODE_SET_PRIVATE (node, NULL);
2370		NG_NODE_UNREF (node);
2371	}
2372	node->nd_flags &= ~NG_INVALID;
2373#endif
2374#else /* __FreeBSD_version < 500000 */
2375	drv_t *d = node->private;
2376	int s;
2377
2378	if (!d)
2379		return 0;
2380
2381	s = splimp ();
2382	ct_down (d);
2383	splx (s);
2384	node->flags |= NG_INVALID;
2385	ng_cutlinks (node);
2386#ifdef	KLD_MODULE
2387	ng_unname (node);
2388	ng_unref (node);
2389#else
2390	node->flags &= ~NG_INVALID;
2391#endif
2392#endif
2393	return 0;
2394}
2395
2396static void ng_ct_watchdog (void *arg)
2397{
2398	drv_t *d = arg;
2399
2400	if (!d)
2401		return;
2402
2403	if (d->timeout == 1)
2404		ct_watchdog (d);
2405	if (d->timeout)
2406		d->timeout--;
2407	d->timeout_handle = timeout (ng_ct_watchdog, d, hz);
2408}
2409
2410static int ng_ct_connect (hook_p hook)
2411{
2412#if __FreeBSD_version >= 500000
2413	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2414#else
2415	drv_t *d = hook->node->private;
2416#endif
2417
2418	if (!d)
2419		return 0;
2420
2421	d->timeout_handle = timeout (ng_ct_watchdog, d, hz);
2422	return 0;
2423}
2424
2425static int ng_ct_disconnect (hook_p hook)
2426{
2427#if __FreeBSD_version >= 500000
2428	drv_t *d = NG_NODE_PRIVATE (NG_HOOK_NODE (hook));
2429#else
2430	drv_t *d = hook->node->private;
2431#endif
2432
2433	if (!d)
2434		return 0;
2435
2436#if __FreeBSD_version >= 500000
2437	if (NG_HOOK_PRIVATE (hook))
2438#else
2439	if (hook->private)
2440#endif
2441		ct_down (d);
2442	untimeout (ng_ct_watchdog, d, d->timeout_handle);
2443	return 0;
2444}
2445#endif
2446
2447#ifdef KLD_MODULE
2448#if __FreeBSD_version < 400000
2449/*
2450 * Function called when loading the driver.
2451 */
2452static int ct_load (void)
2453{
2454	int i;
2455
2456	for (i=0;i<NCTAU; ++i) {
2457		struct isa_device id = {-1, &ctdriver, -1, 0, -1, 0, 0, (inthand2_t *)ct_intr, i, 0, 0, 0, 0 ,0 ,1 ,0 ,0};
2458		disable_intr();
2459		if (!ct_probe (&id)) {
2460			enable_intr();
2461			break;
2462		}
2463		ct_attach (&id);
2464		register_intr ((adapter [i])->irq, 0, 0, (inthand2_t*) ct_intr,
2465				&net_imask, id.id_unit);
2466		enable_intr();
2467	}
2468	if (!i) {
2469		/* Deactivate the timeout routine. */
2470		untimeout (ct_timeout, 0, timeout_handle);
2471
2472		return ENXIO;
2473	}
2474	return 0;
2475}
2476
2477/*
2478 * Function called when unloading the driver.
2479 */
2480static int ct_unload (void)
2481{
2482	int i, s;
2483
2484	/* Check if the device is busy (open). */
2485	for (i=0; i<NCTAU*NCHAN; ++i) {
2486		drv_t *d = channel[i];
2487
2488		if (!d)
2489			continue;
2490		if (d->running)
2491				return EBUSY;
2492	}
2493
2494	/* OK to unload the driver, unregister the interrupt first. */
2495	s = splimp ();
2496
2497	/* Deactivate the timeout routine. */
2498	for (i=0; i<NCTAU; ++i) {
2499		if (!adapter [i])
2500			continue;
2501		untimeout (ct_timeout, 0, timeout_handle);
2502		break;
2503	}
2504
2505	for (i=0; i<NCTAU; ++i) {
2506		ct_board_t *b = adapter [i];
2507
2508		if (!b || ! b->port)
2509			continue;
2510
2511		ct_close_board (b);
2512	}
2513
2514	for (i=0; i<NCTAU; ++i) {
2515		ct_board_t *b = adapter [i];
2516
2517		if (!b || ! b->port)
2518			continue;
2519
2520		if (led_timo[i].callout)
2521			untimeout (ct_led_off, b, led_timo[i]);
2522	}
2523
2524	for (i=0; i<NCTAU; ++i) {
2525		ct_board_t *b = adapter [i];
2526
2527		if (!b || ! b->port)
2528			continue;
2529
2530		/* Disable the interrupt request. */
2531		disable_intr();
2532		unregister_intr (b->irq, (inthand2_t *)ct_intr);
2533		isa_dma_release (b->dma);
2534		enable_intr();
2535	}
2536
2537	/* Detach the interfaces, free buffer memory. */
2538	for (i=0; i<NCTAU*NCHAN; ++i) {
2539		drv_t *d = channel[i];
2540
2541		if (!d)
2542			continue;
2543
2544#ifndef NETGRAPH
2545#if NBPFILTER > 0
2546		/* Detach from the packet filter list of interfaces. */
2547		{
2548			struct bpf_if *q, **b = &bpf_iflist;
2549
2550			while ((q = *b)) {
2551				if (q->bif_ifp == d->pp.pp_if) {
2552					*b = q->bif_next;
2553					free (q, M_DEVBUF);
2554				}
2555				b = &(q->bif_next);
2556			}
2557		}
2558#endif /* NBPFILTER > 0 */
2559		/* Detach from the sync PPP list. */
2560		sppp_detach (&d->pp.pp_if);
2561
2562		/* Detach from the system list of interfaces. */
2563		{
2564			struct ifaddr *ifa;
2565			TAILQ_FOREACH (ifa, &d->pp.pp_if.if_addrhead, ifa_link) {
2566				TAILQ_REMOVE (&d->pp.pp_if.if_addrhead, ifa, ifa_link);
2567				free (ifa, M_IFADDR);
2568			}
2569			TAILQ_REMOVE (&ifnet, &d->pp.pp_if, if_link);
2570		}
2571#endif /* !NETGRAPH */
2572		/* Deallocate buffers. */
2573/*		free (d, M_DEVBUF);*/
2574	}
2575	for (i=0; i<NCTAU; ++i) {
2576		ct_board_t *b = adapter [i];
2577		if (!b)
2578			continue;
2579		adapter [i] = 0;
2580		free (b, M_DEVBUF);
2581	}
2582	splx(s);
2583
2584	return 0;
2585}
2586
2587#define devsw(a)	cdevsw[major((a))]
2588#endif /* __FreeBSD_version < 400000 */
2589#endif /* KLD_MODULE */
2590
2591#if __FreeBSD_version < 400000
2592#ifdef KLD_MODULE
2593static int ct_modevent (module_t mod, int type, void *unused)
2594{
2595        dev_t dev;
2596	int result;
2597	static int load_count = 0;
2598
2599	dev = makedev (CDEV_MAJOR, 0);
2600	switch (type) {
2601	case MOD_LOAD:
2602		if (devsw(dev))
2603			return (ENXIO);
2604		load_count ++;
2605		cdevsw_add (&dev, &ct_cdevsw, NULL);
2606		timeout_handle = timeout (ct_timeout, 0, hz*5);
2607		result = ct_load ();
2608 		return result;
2609	case MOD_UNLOAD:
2610		result = ct_unload ();
2611		if (result)
2612			return result;
2613		if (devsw(dev)&&!(load_count-1)) {
2614			cdevsw_add (&dev, NULL, NULL);
2615		}
2616		load_count --;
2617		return result;
2618	case MOD_SHUTDOWN:
2619		break;
2620	}
2621	return 0;
2622}
2623#endif /* KLD_MODULE */
2624#else /* __FreeBSD_version >= 400000 */
2625static int ct_modevent (module_t mod, int type, void *unused)
2626{
2627        dev_t dev;
2628	static int load_count = 0;
2629	struct cdevsw *cdsw;
2630
2631#if __FreeBSD_version >= 502103
2632	dev = udev2dev (makeudev(CDEV_MAJOR, 0));
2633#else
2634	dev = makedev (CDEV_MAJOR, 0);
2635#endif
2636	switch (type) {
2637	case MOD_LOAD:
2638		if (dev != NODEV &&
2639		    (cdsw = devsw (dev)) &&
2640		    cdsw->d_maj == CDEV_MAJOR) {
2641			printf ("Tau-ISA driver is already in system\n");
2642			return (ENXIO);
2643		}
2644#if __FreeBSD_version >= 500000 && defined NETGRAPH
2645		if (ng_newtype (&typestruct))
2646			printf ("Failed to register ng_ct\n");
2647#endif
2648		++load_count;
2649#if __FreeBSD_version <= 500000
2650		cdevsw_add (&ct_cdevsw);
2651#endif
2652		timeout_handle = timeout (ct_timeout, 0, hz*5);
2653		break;
2654	case MOD_UNLOAD:
2655		if (load_count == 1) {
2656			printf ("Removing device entry for Tau-ISA\n");
2657#if __FreeBSD_version <= 500000
2658			cdevsw_remove (&ct_cdevsw);
2659#endif
2660#if __FreeBSD_version >= 500000 && defined NETGRAPH
2661			ng_rmtype (&typestruct);
2662#endif
2663		}
2664		if (timeout_handle.callout)
2665			untimeout (ct_timeout, 0, timeout_handle);
2666		--load_count;
2667		break;
2668	case MOD_SHUTDOWN:
2669		break;
2670	}
2671	return 0;
2672}
2673#endif /* __FreeBSD_version >= 400000 */
2674
2675#ifdef NETGRAPH
2676static struct ng_type typestruct = {
2677	.version	= NG_ABI_VERSION,
2678	.name		= NG_CT_NODE_TYPE,
2679	.constructor	= ng_ct_constructor,
2680	.rcvmsg		= ng_ct_rcvmsg,
2681	.shutdown	= ng_ct_rmnode,
2682	.newhook	= ng_ct_newhook,
2683	.connect	= ng_ct_connect,
2684	.rcvdata	= ng_ct_rcvdata,
2685	.disconnect	= ng_ct_disconnect
2686};
2687
2688#if __FreeBSD_version < 400000
2689NETGRAPH_INIT_ORDERED (ct, &typestruct, SI_SUB_DRIVERS,\
2690	SI_ORDER_MIDDLE + CDEV_MAJOR);
2691#endif
2692#endif /*NETGRAPH*/
2693
2694#if __FreeBSD_version >= 500000
2695#ifdef NETGRAPH
2696MODULE_DEPEND (ng_ct, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
2697#else
2698MODULE_DEPEND (ct, sppp, 1, 1, 1);
2699#endif
2700#ifdef KLD_MODULE
2701DRIVER_MODULE (ctmod, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2702#else
2703DRIVER_MODULE (ct, isa, ct_isa_driver, ct_devclass, ct_modevent, NULL);
2704#endif
2705#elif __FreeBSD_version >= 400000
2706#ifdef NETGRAPH
2707DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, ng_mod_event, &typestruct);
2708#else
2709DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, ct_modevent, 0);
2710#endif
2711#else /* __FreeBSD_version < 400000 */
2712#ifdef KLD_MODULE
2713#ifndef NETGRAPH
2714static moduledata_t ctmod = { "ct", ct_modevent, };
2715DECLARE_MODULE (ct, ctmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR);
2716#endif /* !NETGRAPH */
2717#else /* KLD_MODULE */
2718
2719/*
2720 * Now for some driver initialisation.
2721 * Occurs ONCE during boot (very early).
2722 * This is if we are NOT a loadable module.
2723 */
2724static void ct_drvinit (void *unused)
2725{
2726        dev_t dev;
2727
2728	dev = makedev (CDEV_MAJOR, 0);
2729	cdevsw_add (&dev, &ct_cdevsw, NULL);
2730
2731	/* Activate the timeout routine. */
2732	timeout_handle = timeout (ct_timeout, 0, hz);
2733#ifdef NETGRAPH
2734#if 0
2735	/* Register our node type in netgraph */
2736	if (ng_newtype (&typestruct))
2737		printf ("Failed to register ng_ct\n");
2738#endif
2739#endif
2740}
2741
2742SYSINIT (ctdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, ct_drvinit, 0)
2743#endif /* KLD_MODULE */
2744#endif /* __FreeBSD_version < 400000 */
2745#endif /* NCTAU */
2746