xref: /freebsd/sys/dev/snp/snp.c (revision 659ffb486aa1c0a7ef1dcc0d0c5282b41895492e)
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>
2271455815SBruce Evans #include <sys/filio.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 #include <sys/tty.h>
263ac4d1efSBruce Evans #include <sys/fcntl.h>
27dde8a05bSUgen J.S. Antsilevich #include <sys/conf.h>
28659ffb48SPeter Wemm #include <sys/poll.h>
29dde8a05bSUgen J.S. Antsilevich #include <sys/uio.h>
30dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h>
31dde8a05bSUgen J.S. Antsilevich #include <sys/malloc.h>
3253ac6efbSJulian Elischer #ifdef DEVFS
3353ac6efbSJulian Elischer #include <sys/devfsext.h>
3453ac6efbSJulian Elischer #endif /*DEVFS*/
3587f6c662SJulian Elischer 
3687f6c662SJulian Elischer #include <sys/snoop.h>
3787f6c662SJulian Elischer 
3887f6c662SJulian Elischer static	d_open_t	snpopen;
3987f6c662SJulian Elischer static	d_close_t	snpclose;
4087f6c662SJulian Elischer static	d_read_t	snpread;
4187f6c662SJulian Elischer static	d_write_t	snpwrite;
4287f6c662SJulian Elischer static	d_ioctl_t	snpioctl;
43659ffb48SPeter Wemm static	d_poll_t	snppoll;
4487f6c662SJulian Elischer 
4553ac6efbSJulian Elischer #define CDEV_MAJOR 53
46d2f265faSPoul-Henning Kamp static struct cdevsw snp_cdevsw =
4787f6c662SJulian Elischer 	{ snpopen,	snpclose,	snpread,	snpwrite,	/*53*/
4887f6c662SJulian Elischer 	  snpioctl,	nostop,		nullreset,	nodevtotty,/* snoop */
49659ffb48SPeter Wemm 	  snppoll,	nommap,		NULL,	"snp",	NULL,	-1 };
5087f6c662SJulian Elischer 
5153ac6efbSJulian Elischer 
52dde8a05bSUgen J.S. Antsilevich #ifndef MIN
53dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b))
54dde8a05bSUgen J.S. Antsilevich #endif
55dde8a05bSUgen J.S. Antsilevich 
56dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP];
57dde8a05bSUgen J.S. Antsilevich 
58444f003cSBruce Evans static struct tty	*snpdevtotty __P((dev_t dev));
5987b6de2bSPoul-Henning Kamp static int		snp_detach __P((struct snoop *snp));
6098d93822SBruce Evans 
6177f77631SPaul Traina static struct tty *
62444f003cSBruce Evans snpdevtotty (dev)
6377f77631SPaul Traina 	dev_t		dev;
6477f77631SPaul Traina {
65444f003cSBruce Evans 	struct cdevsw	*cdp;
66444f003cSBruce Evans 	int		maj;
6777f77631SPaul Traina 
68444f003cSBruce Evans 	maj = major(dev);
69444f003cSBruce Evans 	if ((u_int)maj >= nchrdev)
70444f003cSBruce Evans 		return (NULL);
71444f003cSBruce Evans 	cdp = cdevsw[maj];
72444f003cSBruce Evans 	if (cdp == NULL)
73444f003cSBruce Evans 		return (NULL);
74444f003cSBruce Evans 	return ((*cdp->d_devtotty)(dev));
7577f77631SPaul Traina }
7677f77631SPaul Traina 
770739a0dcSUgen J.S. Antsilevich #define SNP_INPUT_BUF	5	/* This is even too  much,the maximal
780739a0dcSUgen J.S. Antsilevich 				 * interactive mode write is 3 bytes
790739a0dcSUgen J.S. Antsilevich 				 * length for function keys...
800739a0dcSUgen J.S. Antsilevich 				 */
810739a0dcSUgen J.S. Antsilevich 
8287f6c662SJulian Elischer static	int
830739a0dcSUgen J.S. Antsilevich snpwrite(dev, uio, flag)
840739a0dcSUgen J.S. Antsilevich 	dev_t           dev;
850739a0dcSUgen J.S. Antsilevich 	struct uio     *uio;
860739a0dcSUgen J.S. Antsilevich 	int             flag;
870739a0dcSUgen J.S. Antsilevich {
880739a0dcSUgen J.S. Antsilevich 	int             unit = minor(dev), len, i, error;
890739a0dcSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
900739a0dcSUgen J.S. Antsilevich 	struct tty     *tp;
910739a0dcSUgen J.S. Antsilevich 	char		c[SNP_INPUT_BUF];
920739a0dcSUgen J.S. Antsilevich 
930739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
940739a0dcSUgen J.S. Antsilevich 		return (EIO);
950739a0dcSUgen J.S. Antsilevich 
960739a0dcSUgen J.S. Antsilevich 	tp = snp->snp_tty;
970739a0dcSUgen J.S. Antsilevich 
980739a0dcSUgen J.S. Antsilevich 	if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
990739a0dcSUgen J.S. Antsilevich 	    (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC))
1000739a0dcSUgen J.S. Antsilevich 		goto tty_input;
1010739a0dcSUgen J.S. Antsilevich 
1020739a0dcSUgen J.S. Antsilevich 	printf("Snoop: attempt to write to bad tty.\n");
1030739a0dcSUgen J.S. Antsilevich 	return (EIO);
1040739a0dcSUgen J.S. Antsilevich 
1050739a0dcSUgen J.S. Antsilevich tty_input:
1060739a0dcSUgen J.S. Antsilevich 	if (!(tp->t_state & TS_ISOPEN))
1070739a0dcSUgen J.S. Antsilevich 		return (EIO);
1080739a0dcSUgen J.S. Antsilevich 
1090739a0dcSUgen J.S. Antsilevich 	while (uio->uio_resid > 0) {
1100739a0dcSUgen J.S. Antsilevich 		len = MIN(uio->uio_resid,SNP_INPUT_BUF);
1110739a0dcSUgen J.S. Antsilevich 		if ((error = uiomove(c, len, uio)) != 0)
1120739a0dcSUgen J.S. Antsilevich 			return (error);
1130739a0dcSUgen J.S. Antsilevich 		for (i=0;i<len;i++) {
1140739a0dcSUgen J.S. Antsilevich 			if (ttyinput(c[i] , tp))
1150739a0dcSUgen J.S. Antsilevich 				return (EIO);
1160739a0dcSUgen J.S. Antsilevich 		}
1170739a0dcSUgen J.S. Antsilevich 	}
1180739a0dcSUgen J.S. Antsilevich 	return 0;
1190739a0dcSUgen J.S. Antsilevich 
1200739a0dcSUgen J.S. Antsilevich }
1210739a0dcSUgen J.S. Antsilevich 
1220739a0dcSUgen J.S. Antsilevich 
12387f6c662SJulian Elischer static	int
124dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag)
125dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
126dde8a05bSUgen J.S. Antsilevich 	struct uio     *uio;
127dde8a05bSUgen J.S. Antsilevich 	int             flag;
128dde8a05bSUgen J.S. Antsilevich {
129dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
130dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
131dde8a05bSUgen J.S. Antsilevich 	int             len, n, nblen, error = 0;
132dde8a05bSUgen J.S. Antsilevich 	caddr_t         from;
133dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
134dde8a05bSUgen J.S. Antsilevich 
135dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
136dde8a05bSUgen J.S. Antsilevich 	if ((snp->snp_len + snp->snp_base) > snp->snp_blen)
137dde8a05bSUgen J.S. Antsilevich 		panic("snoop buffer error");
138dde8a05bSUgen J.S. Antsilevich #endif
13977f77631SPaul Traina 
1400739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
141dde8a05bSUgen J.S. Antsilevich 		return (EIO);
142dde8a05bSUgen J.S. Antsilevich 
143dde8a05bSUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_RWAIT;
144dde8a05bSUgen J.S. Antsilevich 
145dde8a05bSUgen J.S. Antsilevich 	do {
146dde8a05bSUgen J.S. Antsilevich 		if (snp->snp_len == 0) {
147dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_NBIO) {
148dde8a05bSUgen J.S. Antsilevich 				return EWOULDBLOCK;
149dde8a05bSUgen J.S. Antsilevich 			}
150dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_RWAIT;
151dde8a05bSUgen J.S. Antsilevich 			tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
152dde8a05bSUgen J.S. Antsilevich 		}
153dde8a05bSUgen J.S. Antsilevich 	} while (snp->snp_len == 0);
154dde8a05bSUgen J.S. Antsilevich 
155019b4d63SUgen J.S. Antsilevich 	n = snp->snp_len;
156dde8a05bSUgen J.S. Antsilevich 
157dde8a05bSUgen J.S. Antsilevich 	while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
158dde8a05bSUgen J.S. Antsilevich 		len = MIN(uio->uio_resid, snp->snp_len);
159dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
160dde8a05bSUgen J.S. Antsilevich 		if (len == 0)
161dde8a05bSUgen J.S. Antsilevich 			break;
162dde8a05bSUgen J.S. Antsilevich 
163dde8a05bSUgen J.S. Antsilevich 		error = uiomove(from, len, uio);
164dde8a05bSUgen J.S. Antsilevich 		snp->snp_base += len;
165dde8a05bSUgen J.S. Antsilevich 		snp->snp_len -= len;
166dde8a05bSUgen J.S. Antsilevich 	}
167019b4d63SUgen J.S. Antsilevich 	if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
168dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
169019b4d63SUgen J.S. Antsilevich 	}
170dde8a05bSUgen J.S. Antsilevich 	s = spltty();
171dde8a05bSUgen J.S. Antsilevich 	nblen = snp->snp_blen;
172dde8a05bSUgen J.S. Antsilevich 	if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
173dde8a05bSUgen J.S. Antsilevich 		while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN))
174dde8a05bSUgen J.S. Antsilevich 			nblen = nblen / 2;
175dde8a05bSUgen J.S. Antsilevich 		if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) {
176dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
177dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
178dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
179dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
180dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
181dde8a05bSUgen J.S. Antsilevich 		}
182dde8a05bSUgen J.S. Antsilevich 	}
183dde8a05bSUgen J.S. Antsilevich 	splx(s);
184dde8a05bSUgen J.S. Antsilevich 
185dde8a05bSUgen J.S. Antsilevich 	return error;
186dde8a05bSUgen J.S. Antsilevich }
187dde8a05bSUgen J.S. Antsilevich 
1880739a0dcSUgen J.S. Antsilevich int
1890739a0dcSUgen J.S. Antsilevich snpinc(snp, c)
1900739a0dcSUgen J.S. Antsilevich         struct snoop    *snp;
1910739a0dcSUgen J.S. Antsilevich         char            c;
1920739a0dcSUgen J.S. Antsilevich {
1930739a0dcSUgen J.S. Antsilevich         char    buf[1];
1940739a0dcSUgen J.S. Antsilevich 
1950739a0dcSUgen J.S. Antsilevich         buf[0]=c;
1960739a0dcSUgen J.S. Antsilevich         return (snpin(snp,buf,1));
1970739a0dcSUgen J.S. Antsilevich }
1980739a0dcSUgen J.S. Antsilevich 
199dde8a05bSUgen J.S. Antsilevich 
200dde8a05bSUgen J.S. Antsilevich int
201dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n)
202dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
203dde8a05bSUgen J.S. Antsilevich 	char           *buf;
204dde8a05bSUgen J.S. Antsilevich 	int             n;
205dde8a05bSUgen J.S. Antsilevich {
206dde8a05bSUgen J.S. Antsilevich 	int             s_free, s_tail;
207dde8a05bSUgen J.S. Antsilevich 	int             s, len, nblen;
208dde8a05bSUgen J.S. Antsilevich 	caddr_t         from, to;
209dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
210dde8a05bSUgen J.S. Antsilevich 
211dde8a05bSUgen J.S. Antsilevich 
212dde8a05bSUgen J.S. Antsilevich 	if (n == 0)
213dde8a05bSUgen J.S. Antsilevich 		return 0;
214dde8a05bSUgen J.S. Antsilevich 
215dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
216dde8a05bSUgen J.S. Antsilevich 	if (n < 0)
217dde8a05bSUgen J.S. Antsilevich 		panic("bad snoop char count");
218dde8a05bSUgen J.S. Antsilevich 
219019b4d63SUgen J.S. Antsilevich 	if (!(snp->snp_flags & SNOOP_OPEN)) {
220019b4d63SUgen J.S. Antsilevich 		printf("Snoop: data coming to closed device.\n");
221019b4d63SUgen J.S. Antsilevich 		return 0;
222dde8a05bSUgen J.S. Antsilevich 	}
223019b4d63SUgen J.S. Antsilevich #endif
224019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_DOWN) {
225019b4d63SUgen J.S. Antsilevich 		printf("Snoop: more data to down interface.\n");
226019b4d63SUgen J.S. Antsilevich 		return 0;
227019b4d63SUgen J.S. Antsilevich 	}
228964587caSUgen J.S. Antsilevich 
229019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OFLOW) {
230019b4d63SUgen J.S. Antsilevich 		printf("Snoop: buffer overflow.\n");
231019b4d63SUgen J.S. Antsilevich 		/*
232019b4d63SUgen J.S. Antsilevich 		 * On overflow we just repeat the standart close
233019b4d63SUgen J.S. Antsilevich 		 * procedure...yes , this is waste of space but.. Then next
234019b4d63SUgen J.S. Antsilevich 		 * read from device will fail if one would recall he is
235019b4d63SUgen J.S. Antsilevich 		 * snooping and retry...
236019b4d63SUgen J.S. Antsilevich 		 */
237dde8a05bSUgen J.S. Antsilevich 
238964587caSUgen J.S. Antsilevich 		return (snpdown(snp));
239019b4d63SUgen J.S. Antsilevich 	}
240019b4d63SUgen J.S. Antsilevich 	s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
241019b4d63SUgen J.S. Antsilevich 	s_free = snp->snp_blen - snp->snp_len;
242dde8a05bSUgen J.S. Antsilevich 
243dde8a05bSUgen J.S. Antsilevich 
244dde8a05bSUgen J.S. Antsilevich 	if (n > s_free) {
245dde8a05bSUgen J.S. Antsilevich 		s = spltty();
246dde8a05bSUgen J.S. Antsilevich 		nblen = snp->snp_blen;
247dde8a05bSUgen J.S. Antsilevich 		while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
248dde8a05bSUgen J.S. Antsilevich 			nblen = snp->snp_blen * 2;
249dde8a05bSUgen J.S. Antsilevich 			s_free = nblen - (snp->snp_len + snp->snp_base);
250dde8a05bSUgen J.S. Antsilevich 		}
251dde8a05bSUgen J.S. Antsilevich 		if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) {
252dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
253dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
254dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
255dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
256dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
257dde8a05bSUgen J.S. Antsilevich 		} else {
258dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_OFLOW;
259dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_RWAIT) {
260dde8a05bSUgen J.S. Antsilevich 				snp->snp_flags &= ~SNOOP_RWAIT;
261dde8a05bSUgen J.S. Antsilevich 				wakeup((caddr_t) snp);
262dde8a05bSUgen J.S. Antsilevich 			}
263dde8a05bSUgen J.S. Antsilevich 			splx(s);
264dde8a05bSUgen J.S. Antsilevich 			return 0;
265dde8a05bSUgen J.S. Antsilevich 		}
266dde8a05bSUgen J.S. Antsilevich 		splx(s);
267dde8a05bSUgen J.S. Antsilevich 	}
268dde8a05bSUgen J.S. Antsilevich 	if (n > s_tail) {
269dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
270dde8a05bSUgen J.S. Antsilevich 		to = (caddr_t) (snp->snp_buf);
271dde8a05bSUgen J.S. Antsilevich 		len = snp->snp_len;
272dde8a05bSUgen J.S. Antsilevich 		bcopy(from, to, len);
273dde8a05bSUgen J.S. Antsilevich 		snp->snp_base = 0;
274dde8a05bSUgen J.S. Antsilevich 	}
275dde8a05bSUgen J.S. Antsilevich 	to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len);
276dde8a05bSUgen J.S. Antsilevich 	bcopy(buf, to, n);
277dde8a05bSUgen J.S. Antsilevich 	snp->snp_len += n;
278dde8a05bSUgen J.S. Antsilevich 
279dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_RWAIT) {
280dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_RWAIT;
281dde8a05bSUgen J.S. Antsilevich 		wakeup((caddr_t) snp);
282dde8a05bSUgen J.S. Antsilevich 	}
283dde8a05bSUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
284dde8a05bSUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
285dde8a05bSUgen J.S. Antsilevich 
286dde8a05bSUgen J.S. Antsilevich 	return n;
287dde8a05bSUgen J.S. Antsilevich }
288dde8a05bSUgen J.S. Antsilevich 
28987f6c662SJulian Elischer static	int
290dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p)
291dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
292dde8a05bSUgen J.S. Antsilevich 	int             flag, mode;
293dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
294dde8a05bSUgen J.S. Antsilevich {
295dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
296dde8a05bSUgen J.S. Antsilevich 	register int    unit, error;
297dde8a05bSUgen J.S. Antsilevich 
298dde8a05bSUgen J.S. Antsilevich 	if (error = suser(p->p_ucred, &p->p_acflag))
299dde8a05bSUgen J.S. Antsilevich 		return (error);
300dde8a05bSUgen J.S. Antsilevich 
301dde8a05bSUgen J.S. Antsilevich 	if ((unit = minor(dev)) >= NSNP)
302dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
30377f77631SPaul Traina 
304dde8a05bSUgen J.S. Antsilevich 	snp = &snoopsw[unit];
30577f77631SPaul Traina 
306dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OPEN)
307dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
30877f77631SPaul Traina 
309019b4d63SUgen J.S. Antsilevich 	/*
310019b4d63SUgen J.S. Antsilevich 	 * We intentionally do not OR flags with SNOOP_OPEN,but set them so
311019b4d63SUgen J.S. Antsilevich 	 * all previous settings (especially SNOOP_OFLOW) will be cleared.
312019b4d63SUgen J.S. Antsilevich 	 */
313019b4d63SUgen J.S. Antsilevich 	snp->snp_flags = SNOOP_OPEN;
314dde8a05bSUgen J.S. Antsilevich 
315dde8a05bSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
316dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
317dde8a05bSUgen J.S. Antsilevich 	snp->snp_base = 0;
318dde8a05bSUgen J.S. Antsilevich 	snp->snp_len = 0;
319dde8a05bSUgen J.S. Antsilevich 
320dde8a05bSUgen J.S. Antsilevich 	/*
3210739a0dcSUgen J.S. Antsilevich 	 * snp_tty == NULL  is for inactive snoop devices.
322dde8a05bSUgen J.S. Antsilevich 	 */
3230739a0dcSUgen J.S. Antsilevich 	snp->snp_tty = NULL;
32477f77631SPaul Traina 	snp->snp_target = -1;
325dde8a05bSUgen J.S. Antsilevich 	return (0);
326dde8a05bSUgen J.S. Antsilevich }
327dde8a05bSUgen J.S. Antsilevich 
328019b4d63SUgen J.S. Antsilevich 
32987b6de2bSPoul-Henning Kamp static int
330019b4d63SUgen J.S. Antsilevich snp_detach(snp)
331019b4d63SUgen J.S. Antsilevich 	struct snoop   *snp;
332019b4d63SUgen J.S. Antsilevich {
333019b4d63SUgen J.S. Antsilevich 	struct tty     *tp;
334019b4d63SUgen J.S. Antsilevich 
335019b4d63SUgen J.S. Antsilevich 	snp->snp_base = 0;
336019b4d63SUgen J.S. Antsilevich 	snp->snp_len = 0;
337019b4d63SUgen J.S. Antsilevich 
338019b4d63SUgen J.S. Antsilevich 	/*
339019b4d63SUgen J.S. Antsilevich 	 * If line disc. changed we do not touch this pointer,SLIP/PPP will
340019b4d63SUgen J.S. Antsilevich 	 * change it anyway.
341019b4d63SUgen J.S. Antsilevich 	 */
342019b4d63SUgen J.S. Antsilevich 
3430739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
344964587caSUgen J.S. Antsilevich 		goto detach_notty;
345019b4d63SUgen J.S. Antsilevich 
3460739a0dcSUgen J.S. Antsilevich 	tp = snp->snp_tty;
347019b4d63SUgen J.S. Antsilevich 
34877f77631SPaul Traina 	if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
349019b4d63SUgen J.S. Antsilevich 	    (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) {
350019b4d63SUgen J.S. Antsilevich 		tp->t_sc = NULL;
351019b4d63SUgen J.S. Antsilevich 		tp->t_state &= ~TS_SNOOP;
352019b4d63SUgen J.S. Antsilevich 	} else
353019b4d63SUgen J.S. Antsilevich 		printf("Snoop: bad attached tty data.\n");
354019b4d63SUgen J.S. Antsilevich 
3550739a0dcSUgen J.S. Antsilevich 	snp->snp_tty = NULL;
35677f77631SPaul Traina 	snp->snp_target = -1;
357019b4d63SUgen J.S. Antsilevich 
358964587caSUgen J.S. Antsilevich detach_notty:
359019b4d63SUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
360019b4d63SUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
361019b4d63SUgen J.S. Antsilevich 
362019b4d63SUgen J.S. Antsilevich 	return (0);
363019b4d63SUgen J.S. Antsilevich }
364019b4d63SUgen J.S. Antsilevich 
36587f6c662SJulian Elischer static	int
36660039670SBruce Evans snpclose(dev, flags, fmt, p)
367dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
36860039670SBruce Evans 	int             flags;
36960039670SBruce Evans 	int             fmt;
37060039670SBruce Evans 	struct proc    *p;
371dde8a05bSUgen J.S. Antsilevich {
372dde8a05bSUgen J.S. Antsilevich 	register int    unit = minor(dev);
373dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
374dde8a05bSUgen J.S. Antsilevich 
375dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = 0;
376dde8a05bSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
377019b4d63SUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_OPEN;
378dde8a05bSUgen J.S. Antsilevich 
379019b4d63SUgen J.S. Antsilevich 	return (snp_detach(snp));
380dde8a05bSUgen J.S. Antsilevich }
381dde8a05bSUgen J.S. Antsilevich 
382964587caSUgen J.S. Antsilevich int
383964587caSUgen J.S. Antsilevich snpdown(snp)
384964587caSUgen J.S. Antsilevich 	struct snoop	*snp;
385964587caSUgen J.S. Antsilevich {
386964587caSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
387964587caSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
388964587caSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
389964587caSUgen J.S. Antsilevich 	snp->snp_flags |= SNOOP_DOWN;
390dde8a05bSUgen J.S. Antsilevich 
391964587caSUgen J.S. Antsilevich 	return (snp_detach(snp));
392964587caSUgen J.S. Antsilevich }
393dde8a05bSUgen J.S. Antsilevich 
394dde8a05bSUgen J.S. Antsilevich 
39587f6c662SJulian Elischer static	int
39660039670SBruce Evans snpioctl(dev, cmd, data, flags, p)
397dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
398dde8a05bSUgen J.S. Antsilevich 	int             cmd;
399dde8a05bSUgen J.S. Antsilevich 	caddr_t         data;
40060039670SBruce Evans 	int             flags;
40160039670SBruce Evans 	struct proc    *p;
402dde8a05bSUgen J.S. Antsilevich {
403dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
40477f77631SPaul Traina 	dev_t		tdev;
405dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
406dde8a05bSUgen J.S. Antsilevich 	struct tty     *tp, *tpo;
407dde8a05bSUgen J.S. Antsilevich 
408dde8a05bSUgen J.S. Antsilevich 	switch (cmd) {
409dde8a05bSUgen J.S. Antsilevich 	case SNPSTTY:
41077f77631SPaul Traina 		tdev = *((dev_t *) data);
41177f77631SPaul Traina 		if (tdev == -1)
412964587caSUgen J.S. Antsilevich 			return (snpdown(snp));
413964587caSUgen J.S. Antsilevich 
414444f003cSBruce Evans 		tp = snpdevtotty(tdev);
41577f77631SPaul Traina 		if (!tp)
416dde8a05bSUgen J.S. Antsilevich 			return (EINVAL);
417dde8a05bSUgen J.S. Antsilevich 
41877f77631SPaul Traina 		if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP))
419dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
420dde8a05bSUgen J.S. Antsilevich 
42177f77631SPaul Traina 		if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC))
422dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
423dde8a05bSUgen J.S. Antsilevich 
424dde8a05bSUgen J.S. Antsilevich 		s = spltty();
42577f77631SPaul Traina 
42677f77631SPaul Traina 		if (snp->snp_target == -1) {
4270739a0dcSUgen J.S. Antsilevich 			tpo = snp->snp_tty;
42877f77631SPaul Traina 			if (tpo)
429dde8a05bSUgen J.S. Antsilevich 				tpo->t_state &= ~TS_SNOOP;
430dde8a05bSUgen J.S. Antsilevich 		}
43177f77631SPaul Traina 
432dde8a05bSUgen J.S. Antsilevich 		tp->t_sc = (caddr_t) snp;
433dde8a05bSUgen J.S. Antsilevich 		tp->t_state |= TS_SNOOP;
4340739a0dcSUgen J.S. Antsilevich 		snp->snp_tty = tp;
43577f77631SPaul Traina 		snp->snp_target = tdev;
43677f77631SPaul Traina 
437964587caSUgen J.S. Antsilevich 		/*
438964587caSUgen J.S. Antsilevich 		 * Clean overflow and down flags -
439964587caSUgen J.S. Antsilevich 		 * we'll have a chance to get them in the future :)))
440964587caSUgen J.S. Antsilevich 		 */
441964587caSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
442019b4d63SUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_DOWN;
443dde8a05bSUgen J.S. Antsilevich 		splx(s);
444dde8a05bSUgen J.S. Antsilevich 		break;
44577f77631SPaul Traina 
446dde8a05bSUgen J.S. Antsilevich 	case SNPGTTY:
4470739a0dcSUgen J.S. Antsilevich 		/*
4480739a0dcSUgen J.S. Antsilevich 		 * We keep snp_target field specially to make
4490739a0dcSUgen J.S. Antsilevich 		 * SNPGTTY happy,else we can't know what is device
4500739a0dcSUgen J.S. Antsilevich 		 * major/minor for tty.
4510739a0dcSUgen J.S. Antsilevich 		 */
45277f77631SPaul Traina 		*((dev_t *) data) = snp->snp_target;
453dde8a05bSUgen J.S. Antsilevich 		break;
454dde8a05bSUgen J.S. Antsilevich 
455dde8a05bSUgen J.S. Antsilevich 	case FIONBIO:
456dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
457dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_NBIO;
458dde8a05bSUgen J.S. Antsilevich 		else
459dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_NBIO;
460dde8a05bSUgen J.S. Antsilevich 		break;
46177f77631SPaul Traina 
462dde8a05bSUgen J.S. Antsilevich 	case FIOASYNC:
463dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
464dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_ASYNC;
465dde8a05bSUgen J.S. Antsilevich 		else
466dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_ASYNC;
467dde8a05bSUgen J.S. Antsilevich 		break;
46877f77631SPaul Traina 
469dde8a05bSUgen J.S. Antsilevich 	case FIONREAD:
470dde8a05bSUgen J.S. Antsilevich 		s = spltty();
4710739a0dcSUgen J.S. Antsilevich 		if (snp->snp_tty != NULL)
472dde8a05bSUgen J.S. Antsilevich 			*(int *) data = snp->snp_len;
473dde8a05bSUgen J.S. Antsilevich 		else
474964587caSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_DOWN) {
475964587caSUgen J.S. Antsilevich 				if (snp->snp_flags & SNOOP_OFLOW)
476964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_OFLOW;
477964587caSUgen J.S. Antsilevich 				else
478964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_TTYCLOSE;
479964587caSUgen J.S. Antsilevich 			} else {
480964587caSUgen J.S. Antsilevich 				*(int *) data = SNP_DETACH;
481964587caSUgen J.S. Antsilevich 			}
482dde8a05bSUgen J.S. Antsilevich 		splx(s);
483dde8a05bSUgen J.S. Antsilevich 		break;
48477f77631SPaul Traina 
485dde8a05bSUgen J.S. Antsilevich 	default:
486dde8a05bSUgen J.S. Antsilevich 		return (ENOTTY);
487dde8a05bSUgen J.S. Antsilevich 	}
488dde8a05bSUgen J.S. Antsilevich 	return (0);
489dde8a05bSUgen J.S. Antsilevich }
490dde8a05bSUgen J.S. Antsilevich 
491dde8a05bSUgen J.S. Antsilevich 
49287f6c662SJulian Elischer static	int
493659ffb48SPeter Wemm snppoll(dev, events, p)
494dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
495659ffb48SPeter Wemm 	int             events;
496dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
497dde8a05bSUgen J.S. Antsilevich {
498a98ca469SPoul-Henning Kamp 	int             unit = minor(dev);
499dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
500659ffb48SPeter Wemm 	int		revents = 0;
501dde8a05bSUgen J.S. Antsilevich 
50277f77631SPaul Traina 
503019b4d63SUgen J.S. Antsilevich 	/*
504659ffb48SPeter Wemm 	 * If snoop is down,we don't want to poll() forever so we return 1.
505019b4d63SUgen J.S. Antsilevich 	 * Caller should see if we down via FIONREAD ioctl().The last should
506019b4d63SUgen J.S. Antsilevich 	 * return -1 to indicate down state.
507019b4d63SUgen J.S. Antsilevich 	 */
508659ffb48SPeter Wemm 	if (events & (POLLIN | POLLRDNORM))
509659ffb48SPeter Wemm 		if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0)
510659ffb48SPeter Wemm 			revents |= events & (POLLIN | POLLRDNORM);
511659ffb48SPeter Wemm 		else
512dde8a05bSUgen J.S. Antsilevich 			selrecord(p, &snp->snp_sel);
513659ffb48SPeter Wemm 
514659ffb48SPeter Wemm 	return (revents);
515dde8a05bSUgen J.S. Antsilevich }
516dde8a05bSUgen J.S. Antsilevich 
517734daefcSMarc G. Fournier #ifdef DEVFS
51887f6c662SJulian Elischer static	void	*snp_devfs_token[NSNP];
519734daefcSMarc G. Fournier #endif
52053ac6efbSJulian Elischer static snp_devsw_installed = 0;
52153ac6efbSJulian Elischer 
52287f6c662SJulian Elischer static void
52387f6c662SJulian Elischer snp_drvinit(void *unused)
52453ac6efbSJulian Elischer {
52553ac6efbSJulian Elischer 	dev_t dev;
526734daefcSMarc G. Fournier #ifdef DEVFS
52787f6c662SJulian Elischer 	int	i;
528734daefcSMarc G. Fournier #endif
52953ac6efbSJulian Elischer 
53053ac6efbSJulian Elischer 	if( ! snp_devsw_installed ) {
53153ac6efbSJulian Elischer 		dev = makedev(CDEV_MAJOR, 0);
53253ac6efbSJulian Elischer 		cdevsw_add(&dev,&snp_cdevsw, NULL);
53353ac6efbSJulian Elischer 		snp_devsw_installed = 1;
53453ac6efbSJulian Elischer #ifdef DEVFS
53587f6c662SJulian Elischer 		for ( i = 0 ; i < NSNP ; i++) {
53687f6c662SJulian Elischer 			snp_devfs_token[i] =
537734daefcSMarc G. Fournier 				devfs_add_devswf(&snp_cdevsw, i, DV_CHR, 0, 0,
538734daefcSMarc G. Fournier 						0600, "snp%d", i);
53953ac6efbSJulian Elischer 		}
54053ac6efbSJulian Elischer #endif
54153ac6efbSJulian Elischer     	}
5427198bf47SJulian Elischer }
54353ac6efbSJulian Elischer 
54453ac6efbSJulian Elischer SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL)
54553ac6efbSJulian Elischer 
54653ac6efbSJulian Elischer 
547dde8a05bSUgen J.S. Antsilevich #endif
548