xref: /freebsd/sys/dev/snp/snp.c (revision 77f77631e75f6858d00b61473e49b7c8906c5aa8)
1dde8a05bSUgen J.S. Antsilevich /*
2dde8a05bSUgen J.S. Antsilevich  * Copyright (c) 1995 Ugen J.S.Antsilevich
3dde8a05bSUgen J.S. Antsilevich  *
4dde8a05bSUgen J.S. Antsilevich  * Redistribution and use in source forms, with and without modification,
5dde8a05bSUgen J.S. Antsilevich  * are permitted provided that this entire comment appears intact.
6dde8a05bSUgen J.S. Antsilevich  *
7dde8a05bSUgen J.S. Antsilevich  * Redistribution in binary form may occur without any restrictions.
8dde8a05bSUgen J.S. Antsilevich  * Obviously, it would be nice if you gave credit where credit is due
9dde8a05bSUgen J.S. Antsilevich  * but requiring it would be too onerous.
10dde8a05bSUgen J.S. Antsilevich  *
11dde8a05bSUgen J.S. Antsilevich  * This software is provided ``AS IS'' without any warranties of any kind.
12dde8a05bSUgen J.S. Antsilevich  *
13dde8a05bSUgen J.S. Antsilevich  * Snoop stuff.
14dde8a05bSUgen J.S. Antsilevich  */
15dde8a05bSUgen J.S. Antsilevich 
16dde8a05bSUgen J.S. Antsilevich #include "snp.h"
17dde8a05bSUgen J.S. Antsilevich 
18019b4d63SUgen J.S. Antsilevich #if NSNP > 0
19dde8a05bSUgen J.S. Antsilevich 
20dde8a05bSUgen J.S. Antsilevich #include <sys/param.h>
21dde8a05bSUgen J.S. Antsilevich #include <sys/systm.h>
22dde8a05bSUgen J.S. Antsilevich #include <sys/ioctl.h>
23dde8a05bSUgen J.S. Antsilevich #include <sys/ioctl_compat.h>	/* Oooh..We need O/NTTYDISC	 */
24dde8a05bSUgen J.S. Antsilevich #include <sys/proc.h>
25dde8a05bSUgen J.S. Antsilevich #define TTYDEFCHARS
26dde8a05bSUgen J.S. Antsilevich #include <sys/tty.h>
27dde8a05bSUgen J.S. Antsilevich #undef  TTYDEFCHARS
28dde8a05bSUgen J.S. Antsilevich #include <sys/file.h>
29dde8a05bSUgen J.S. Antsilevich #include <sys/conf.h>
30dde8a05bSUgen J.S. Antsilevich #include <sys/uio.h>
31dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h>
32dde8a05bSUgen J.S. Antsilevich #include <sys/malloc.h>
33dde8a05bSUgen J.S. Antsilevich 
34dde8a05bSUgen J.S. Antsilevich #include <sys/snoop.h>
35dde8a05bSUgen J.S. Antsilevich 
36dde8a05bSUgen J.S. Antsilevich #ifndef MIN
37dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b))
38dde8a05bSUgen J.S. Antsilevich #endif
39dde8a05bSUgen J.S. Antsilevich 
40dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP];
41dde8a05bSUgen J.S. Antsilevich 
4277f77631SPaul Traina static struct tty *
4377f77631SPaul Traina devtotty (dev)
4477f77631SPaul Traina 	dev_t		dev;
4577f77631SPaul Traina {
4677f77631SPaul Traina 	if (major(dev) > nchrdev)
4777f77631SPaul Traina 		return (NULL);		/* no such device available */
4877f77631SPaul Traina 
4977f77631SPaul Traina 	return (*cdevsw[major(dev)].d_devtotty)(dev);
5077f77631SPaul Traina }
5177f77631SPaul Traina 
52dde8a05bSUgen J.S. Antsilevich int
53dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag)
54dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
55dde8a05bSUgen J.S. Antsilevich 	struct uio     *uio;
56dde8a05bSUgen J.S. Antsilevich 	int             flag;
57dde8a05bSUgen J.S. Antsilevich {
58dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
59dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
60dde8a05bSUgen J.S. Antsilevich 	int             len, n, nblen, error = 0;
61dde8a05bSUgen J.S. Antsilevich 	caddr_t         from;
62dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
63dde8a05bSUgen J.S. Antsilevich 
64dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
65dde8a05bSUgen J.S. Antsilevich 	if ((snp->snp_len + snp->snp_base) > snp->snp_blen)
66dde8a05bSUgen J.S. Antsilevich 		panic("snoop buffer error");
67dde8a05bSUgen J.S. Antsilevich #endif
6877f77631SPaul Traina 
6977f77631SPaul Traina 	if (snp->snp_target == -1)
70dde8a05bSUgen J.S. Antsilevich 		return (EIO);
71dde8a05bSUgen J.S. Antsilevich 
72dde8a05bSUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_RWAIT;
73dde8a05bSUgen J.S. Antsilevich 
74dde8a05bSUgen J.S. Antsilevich 	do {
75dde8a05bSUgen J.S. Antsilevich 		if (snp->snp_len == 0) {
76dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_NBIO) {
77dde8a05bSUgen J.S. Antsilevich 				return EWOULDBLOCK;
78dde8a05bSUgen J.S. Antsilevich 			}
79dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_RWAIT;
80dde8a05bSUgen J.S. Antsilevich 			tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
81dde8a05bSUgen J.S. Antsilevich 		}
82dde8a05bSUgen J.S. Antsilevich 	} while (snp->snp_len == 0);
83dde8a05bSUgen J.S. Antsilevich 
84019b4d63SUgen J.S. Antsilevich 	n = snp->snp_len;
85dde8a05bSUgen J.S. Antsilevich 
86dde8a05bSUgen J.S. Antsilevich 	while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
87dde8a05bSUgen J.S. Antsilevich 		len = MIN(uio->uio_resid, snp->snp_len);
88dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
89dde8a05bSUgen J.S. Antsilevich 		if (len == 0)
90dde8a05bSUgen J.S. Antsilevich 			break;
91dde8a05bSUgen J.S. Antsilevich 
92dde8a05bSUgen J.S. Antsilevich 		error = uiomove(from, len, uio);
93dde8a05bSUgen J.S. Antsilevich 		snp->snp_base += len;
94dde8a05bSUgen J.S. Antsilevich 		snp->snp_len -= len;
95dde8a05bSUgen J.S. Antsilevich 	}
96019b4d63SUgen J.S. Antsilevich 	if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
97dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
98019b4d63SUgen J.S. Antsilevich 	}
99dde8a05bSUgen J.S. Antsilevich 	s = spltty();
100dde8a05bSUgen J.S. Antsilevich 	nblen = snp->snp_blen;
101dde8a05bSUgen J.S. Antsilevich 	if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
102dde8a05bSUgen J.S. Antsilevich 		while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN))
103dde8a05bSUgen J.S. Antsilevich 			nblen = nblen / 2;
104dde8a05bSUgen J.S. Antsilevich 		if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) {
105dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
106dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
107dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
108dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
109dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
110dde8a05bSUgen J.S. Antsilevich 		}
111dde8a05bSUgen J.S. Antsilevich 	}
112dde8a05bSUgen J.S. Antsilevich 	splx(s);
113dde8a05bSUgen J.S. Antsilevich 
114dde8a05bSUgen J.S. Antsilevich 	return error;
115dde8a05bSUgen J.S. Antsilevich }
116dde8a05bSUgen J.S. Antsilevich 
117dde8a05bSUgen J.S. Antsilevich 
118dde8a05bSUgen J.S. Antsilevich int
119dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n)
120dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
121dde8a05bSUgen J.S. Antsilevich 	char           *buf;
122dde8a05bSUgen J.S. Antsilevich 	int             n;
123dde8a05bSUgen J.S. Antsilevich {
124dde8a05bSUgen J.S. Antsilevich 	int             s_free, s_tail;
125dde8a05bSUgen J.S. Antsilevich 	int             s, len, nblen;
126dde8a05bSUgen J.S. Antsilevich 	caddr_t         from, to;
127dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
128dde8a05bSUgen J.S. Antsilevich 	struct tty     *tp;
129dde8a05bSUgen J.S. Antsilevich 
130dde8a05bSUgen J.S. Antsilevich 
131dde8a05bSUgen J.S. Antsilevich 	if (n == 0)
132dde8a05bSUgen J.S. Antsilevich 		return 0;
133dde8a05bSUgen J.S. Antsilevich 
134dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
135dde8a05bSUgen J.S. Antsilevich 	if (n < 0)
136dde8a05bSUgen J.S. Antsilevich 		panic("bad snoop char count");
137dde8a05bSUgen J.S. Antsilevich 
138019b4d63SUgen J.S. Antsilevich 	if (!(snp->snp_flags & SNOOP_OPEN)) {
139019b4d63SUgen J.S. Antsilevich 		printf("Snoop: data coming to closed device.\n");
140019b4d63SUgen J.S. Antsilevich 		return 0;
141dde8a05bSUgen J.S. Antsilevich 	}
142019b4d63SUgen J.S. Antsilevich #endif
143019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_DOWN) {
144019b4d63SUgen J.S. Antsilevich 		printf("Snoop: more data to down interface.\n");
145019b4d63SUgen J.S. Antsilevich 		return 0;
146019b4d63SUgen J.S. Antsilevich 	}
147964587caSUgen J.S. Antsilevich 
148019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OFLOW) {
149019b4d63SUgen J.S. Antsilevich 		printf("Snoop: buffer overflow.\n");
150019b4d63SUgen J.S. Antsilevich 		/*
151019b4d63SUgen J.S. Antsilevich 		 * On overflow we just repeat the standart close
152019b4d63SUgen J.S. Antsilevich 		 * procedure...yes , this is waste of space but.. Then next
153019b4d63SUgen J.S. Antsilevich 		 * read from device will fail if one would recall he is
154019b4d63SUgen J.S. Antsilevich 		 * snooping and retry...
155019b4d63SUgen J.S. Antsilevich 		 */
156dde8a05bSUgen J.S. Antsilevich 
157964587caSUgen J.S. Antsilevich 		return (snpdown(snp));
158019b4d63SUgen J.S. Antsilevich 	}
159019b4d63SUgen J.S. Antsilevich 	s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
160019b4d63SUgen J.S. Antsilevich 	s_free = snp->snp_blen - snp->snp_len;
161dde8a05bSUgen J.S. Antsilevich 
162dde8a05bSUgen J.S. Antsilevich 
163dde8a05bSUgen J.S. Antsilevich 	if (n > s_free) {
164dde8a05bSUgen J.S. Antsilevich 		s = spltty();
165dde8a05bSUgen J.S. Antsilevich 		nblen = snp->snp_blen;
166dde8a05bSUgen J.S. Antsilevich 		while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
167dde8a05bSUgen J.S. Antsilevich 			nblen = snp->snp_blen * 2;
168dde8a05bSUgen J.S. Antsilevich 			s_free = nblen - (snp->snp_len + snp->snp_base);
169dde8a05bSUgen J.S. Antsilevich 		}
170dde8a05bSUgen J.S. Antsilevich 		if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) {
171dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
172dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
173dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
174dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
175dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
176dde8a05bSUgen J.S. Antsilevich 		} else {
177dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_OFLOW;
178dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_RWAIT) {
179dde8a05bSUgen J.S. Antsilevich 				snp->snp_flags &= ~SNOOP_RWAIT;
180dde8a05bSUgen J.S. Antsilevich 				wakeup((caddr_t) snp);
181dde8a05bSUgen J.S. Antsilevich 			}
182dde8a05bSUgen J.S. Antsilevich 			splx(s);
183dde8a05bSUgen J.S. Antsilevich 			return 0;
184dde8a05bSUgen J.S. Antsilevich 		}
185dde8a05bSUgen J.S. Antsilevich 		splx(s);
186dde8a05bSUgen J.S. Antsilevich 	}
187dde8a05bSUgen J.S. Antsilevich 	if (n > s_tail) {
188dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
189dde8a05bSUgen J.S. Antsilevich 		to = (caddr_t) (snp->snp_buf);
190dde8a05bSUgen J.S. Antsilevich 		len = snp->snp_len;
191dde8a05bSUgen J.S. Antsilevich 		bcopy(from, to, len);
192dde8a05bSUgen J.S. Antsilevich 		snp->snp_base = 0;
193dde8a05bSUgen J.S. Antsilevich 	}
194dde8a05bSUgen J.S. Antsilevich 	to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len);
195dde8a05bSUgen J.S. Antsilevich 	bcopy(buf, to, n);
196dde8a05bSUgen J.S. Antsilevich 	snp->snp_len += n;
197dde8a05bSUgen J.S. Antsilevich 
198dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_RWAIT) {
199dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_RWAIT;
200dde8a05bSUgen J.S. Antsilevich 		wakeup((caddr_t) snp);
201dde8a05bSUgen J.S. Antsilevich 	}
202dde8a05bSUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
203dde8a05bSUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
204dde8a05bSUgen J.S. Antsilevich 
205dde8a05bSUgen J.S. Antsilevich 	return n;
206dde8a05bSUgen J.S. Antsilevich }
207dde8a05bSUgen J.S. Antsilevich 
208dde8a05bSUgen J.S. Antsilevich int
209dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p)
210dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
211dde8a05bSUgen J.S. Antsilevich 	int             flag, mode;
212dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
213dde8a05bSUgen J.S. Antsilevich {
214dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
215dde8a05bSUgen J.S. Antsilevich 	register int    unit, error;
216dde8a05bSUgen J.S. Antsilevich 
217dde8a05bSUgen J.S. Antsilevich 	if (error = suser(p->p_ucred, &p->p_acflag))
218dde8a05bSUgen J.S. Antsilevich 		return (error);
219dde8a05bSUgen J.S. Antsilevich 
220dde8a05bSUgen J.S. Antsilevich 	if ((unit = minor(dev)) >= NSNP)
221dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
22277f77631SPaul Traina 
223dde8a05bSUgen J.S. Antsilevich 	snp = &snoopsw[unit];
22477f77631SPaul Traina 
225dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OPEN)
226dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
22777f77631SPaul Traina 
228019b4d63SUgen J.S. Antsilevich 	/*
229019b4d63SUgen J.S. Antsilevich 	 * We intentionally do not OR flags with SNOOP_OPEN,but set them so
230019b4d63SUgen J.S. Antsilevich 	 * all previous settings (especially SNOOP_OFLOW) will be cleared.
231019b4d63SUgen J.S. Antsilevich 	 */
232019b4d63SUgen J.S. Antsilevich 	snp->snp_flags = SNOOP_OPEN;
233dde8a05bSUgen J.S. Antsilevich 
234dde8a05bSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
235dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
236dde8a05bSUgen J.S. Antsilevich 	snp->snp_base = 0;
237dde8a05bSUgen J.S. Antsilevich 	snp->snp_len = 0;
238dde8a05bSUgen J.S. Antsilevich 
239dde8a05bSUgen J.S. Antsilevich 	/*
240019b4d63SUgen J.S. Antsilevich 	 * unit == -1  is for inactive snoop devices.
241dde8a05bSUgen J.S. Antsilevich 	 */
24277f77631SPaul Traina 	snp->snp_target = -1;
243dde8a05bSUgen J.S. Antsilevich 	return (0);
244dde8a05bSUgen J.S. Antsilevich }
245dde8a05bSUgen J.S. Antsilevich 
246019b4d63SUgen J.S. Antsilevich 
247019b4d63SUgen J.S. Antsilevich int
248019b4d63SUgen J.S. Antsilevich snp_detach(snp)
249019b4d63SUgen J.S. Antsilevich 	struct snoop   *snp;
250019b4d63SUgen J.S. Antsilevich {
251019b4d63SUgen J.S. Antsilevich 	struct tty     *tp;
252019b4d63SUgen J.S. Antsilevich 
253019b4d63SUgen J.S. Antsilevich 	snp->snp_base = 0;
254019b4d63SUgen J.S. Antsilevich 	snp->snp_len = 0;
255019b4d63SUgen J.S. Antsilevich 
256019b4d63SUgen J.S. Antsilevich 	/*
257019b4d63SUgen J.S. Antsilevich 	 * If line disc. changed we do not touch this pointer,SLIP/PPP will
258019b4d63SUgen J.S. Antsilevich 	 * change it anyway.
259019b4d63SUgen J.S. Antsilevich 	 */
260019b4d63SUgen J.S. Antsilevich 
26177f77631SPaul Traina 	if (snp->snp_target == -1)
262964587caSUgen J.S. Antsilevich 		goto detach_notty;
263019b4d63SUgen J.S. Antsilevich 
26477f77631SPaul Traina 	tp = devtotty(snp->snp_target);
265019b4d63SUgen J.S. Antsilevich 
26677f77631SPaul Traina 	if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
267019b4d63SUgen J.S. Antsilevich 	    (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) {
268019b4d63SUgen J.S. Antsilevich 		tp->t_sc = NULL;
269019b4d63SUgen J.S. Antsilevich 		tp->t_state &= ~TS_SNOOP;
270019b4d63SUgen J.S. Antsilevich 	} else
271019b4d63SUgen J.S. Antsilevich 		printf("Snoop: bad attached tty data.\n");
272019b4d63SUgen J.S. Antsilevich 
27377f77631SPaul Traina 	snp->snp_target = -1;
274019b4d63SUgen J.S. Antsilevich 
275964587caSUgen J.S. Antsilevich detach_notty:
276019b4d63SUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
277019b4d63SUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
278019b4d63SUgen J.S. Antsilevich 
279019b4d63SUgen J.S. Antsilevich 	return (0);
280019b4d63SUgen J.S. Antsilevich }
281019b4d63SUgen J.S. Antsilevich 
282dde8a05bSUgen J.S. Antsilevich int
283dde8a05bSUgen J.S. Antsilevich snpclose(dev, flag)
284dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
285dde8a05bSUgen J.S. Antsilevich 	int             flag;
286dde8a05bSUgen J.S. Antsilevich {
287dde8a05bSUgen J.S. Antsilevich 	register int    unit = minor(dev);
288dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
289dde8a05bSUgen J.S. Antsilevich 
290dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = 0;
291dde8a05bSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
292019b4d63SUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_OPEN;
293dde8a05bSUgen J.S. Antsilevich 
294019b4d63SUgen J.S. Antsilevich 	return (snp_detach(snp));
295dde8a05bSUgen J.S. Antsilevich }
296dde8a05bSUgen J.S. Antsilevich 
297964587caSUgen J.S. Antsilevich int
298964587caSUgen J.S. Antsilevich snpdown(snp)
299964587caSUgen J.S. Antsilevich 	struct snoop	*snp;
300964587caSUgen J.S. Antsilevich {
301964587caSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
302964587caSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
303964587caSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
304964587caSUgen J.S. Antsilevich 	snp->snp_flags |= SNOOP_DOWN;
305dde8a05bSUgen J.S. Antsilevich 
306964587caSUgen J.S. Antsilevich 	return (snp_detach(snp));
307964587caSUgen J.S. Antsilevich }
308dde8a05bSUgen J.S. Antsilevich 
309dde8a05bSUgen J.S. Antsilevich 
310dde8a05bSUgen J.S. Antsilevich int
311dde8a05bSUgen J.S. Antsilevich snpioctl(dev, cmd, data, flag)
312dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
313dde8a05bSUgen J.S. Antsilevich 	int             cmd;
314dde8a05bSUgen J.S. Antsilevich 	caddr_t         data;
315dde8a05bSUgen J.S. Antsilevich 	int             flag;
316dde8a05bSUgen J.S. Antsilevich {
317dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
31877f77631SPaul Traina 	dev_t		tdev;
319dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
320dde8a05bSUgen J.S. Antsilevich 	struct tty     *tp, *tpo;
321dde8a05bSUgen J.S. Antsilevich 
322dde8a05bSUgen J.S. Antsilevich 	switch (cmd) {
323dde8a05bSUgen J.S. Antsilevich 	case SNPSTTY:
32477f77631SPaul Traina 		tdev = *((dev_t *) data);
32577f77631SPaul Traina 		if (tdev == -1)
326964587caSUgen J.S. Antsilevich 			return (snpdown(snp));
327964587caSUgen J.S. Antsilevich 
32877f77631SPaul Traina 		tp = devtotty(tdev);
32977f77631SPaul Traina 		if (!tp)
330dde8a05bSUgen J.S. Antsilevich 			return (EINVAL);
331dde8a05bSUgen J.S. Antsilevich 
33277f77631SPaul Traina 		if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP))
333dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
334dde8a05bSUgen J.S. Antsilevich 
33577f77631SPaul Traina 		if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC))
336dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
337dde8a05bSUgen J.S. Antsilevich 
338dde8a05bSUgen J.S. Antsilevich 		s = spltty();
33977f77631SPaul Traina 
34077f77631SPaul Traina 		if (snp->snp_target == -1) {
34177f77631SPaul Traina 			tpo = devtotty(snp->snp_target);
34277f77631SPaul Traina 			if (tpo)
343dde8a05bSUgen J.S. Antsilevich 				tpo->t_state &= ~TS_SNOOP;
344dde8a05bSUgen J.S. Antsilevich 		}
34577f77631SPaul Traina 
346dde8a05bSUgen J.S. Antsilevich 		tp->t_sc = (caddr_t) snp;
347dde8a05bSUgen J.S. Antsilevich 		tp->t_state |= TS_SNOOP;
34877f77631SPaul Traina 		snp->snp_target = tdev;
34977f77631SPaul Traina 
350964587caSUgen J.S. Antsilevich 		/*
351964587caSUgen J.S. Antsilevich 		 * Clean overflow and down flags -
352964587caSUgen J.S. Antsilevich 		 * we'll have a chance to get them in the future :)))
353964587caSUgen J.S. Antsilevich 		 */
354964587caSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
355019b4d63SUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_DOWN;
356dde8a05bSUgen J.S. Antsilevich 		splx(s);
357dde8a05bSUgen J.S. Antsilevich 		break;
35877f77631SPaul Traina 
359dde8a05bSUgen J.S. Antsilevich 	case SNPGTTY:
36077f77631SPaul Traina 		*((dev_t *) data) = snp->snp_target;
361dde8a05bSUgen J.S. Antsilevich 		break;
362dde8a05bSUgen J.S. Antsilevich 
363dde8a05bSUgen J.S. Antsilevich 	case FIONBIO:
364dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
365dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_NBIO;
366dde8a05bSUgen J.S. Antsilevich 		else
367dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_NBIO;
368dde8a05bSUgen J.S. Antsilevich 		break;
36977f77631SPaul Traina 
370dde8a05bSUgen J.S. Antsilevich 	case FIOASYNC:
371dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
372dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_ASYNC;
373dde8a05bSUgen J.S. Antsilevich 		else
374dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_ASYNC;
375dde8a05bSUgen J.S. Antsilevich 		break;
37677f77631SPaul Traina 
377dde8a05bSUgen J.S. Antsilevich 	case FIONREAD:
378dde8a05bSUgen J.S. Antsilevich 		s = spltty();
37977f77631SPaul Traina 		if (snp->snp_target != -1)
380dde8a05bSUgen J.S. Antsilevich 			*(int *) data = snp->snp_len;
381dde8a05bSUgen J.S. Antsilevich 		else
382964587caSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_DOWN) {
383964587caSUgen J.S. Antsilevich 				if (snp->snp_flags & SNOOP_OFLOW)
384964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_OFLOW;
385964587caSUgen J.S. Antsilevich 				else
386964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_TTYCLOSE;
387964587caSUgen J.S. Antsilevich 			} else {
388964587caSUgen J.S. Antsilevich 				*(int *) data = SNP_DETACH;
389964587caSUgen J.S. Antsilevich 			}
390dde8a05bSUgen J.S. Antsilevich 		splx(s);
391dde8a05bSUgen J.S. Antsilevich 		break;
39277f77631SPaul Traina 
393dde8a05bSUgen J.S. Antsilevich 	default:
394dde8a05bSUgen J.S. Antsilevich 		return (ENOTTY);
395dde8a05bSUgen J.S. Antsilevich 	}
396dde8a05bSUgen J.S. Antsilevich 	return (0);
397dde8a05bSUgen J.S. Antsilevich }
398dde8a05bSUgen J.S. Antsilevich 
399dde8a05bSUgen J.S. Antsilevich 
400dde8a05bSUgen J.S. Antsilevich int
401dde8a05bSUgen J.S. Antsilevich snpselect(dev, rw, p)
402dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
403dde8a05bSUgen J.S. Antsilevich 	int             rw;
404dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
405dde8a05bSUgen J.S. Antsilevich {
406dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
407dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
408dde8a05bSUgen J.S. Antsilevich 
40977f77631SPaul Traina 	if (rw != FREAD)
410dde8a05bSUgen J.S. Antsilevich 		return 0;
41177f77631SPaul Traina 
41277f77631SPaul Traina 	if (snp->snp_len > 0)
413dde8a05bSUgen J.S. Antsilevich 		return 1;
41477f77631SPaul Traina 
415019b4d63SUgen J.S. Antsilevich 	/*
416019b4d63SUgen J.S. Antsilevich 	 * If snoop is down,we don't want to select() forever so we return 1.
417019b4d63SUgen J.S. Antsilevich 	 * Caller should see if we down via FIONREAD ioctl().The last should
418019b4d63SUgen J.S. Antsilevich 	 * return -1 to indicate down state.
419019b4d63SUgen J.S. Antsilevich 	 */
42077f77631SPaul Traina 	if (snp->snp_flags & SNOOP_DOWN)
421019b4d63SUgen J.S. Antsilevich 		return 1;
42277f77631SPaul Traina 
423dde8a05bSUgen J.S. Antsilevich 	selrecord(p, &snp->snp_sel);
424dde8a05bSUgen J.S. Antsilevich 	return 0;
425dde8a05bSUgen J.S. Antsilevich }
426dde8a05bSUgen J.S. Antsilevich 
427dde8a05bSUgen J.S. Antsilevich #endif
428