xref: /freebsd/sys/dev/snp/snp.c (revision 7198bf4725543c8dfcb79b0e7cf38d97e5a6aa80)
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 
3653ac6efbSJulian Elischer #ifdef JREMOD
3753ac6efbSJulian Elischer #ifdef DEVFS
3853ac6efbSJulian Elischer #include <sys/devfsext.h>
3953ac6efbSJulian Elischer #endif /*DEVFS*/
4053ac6efbSJulian Elischer #define CDEV_MAJOR 53
4153ac6efbSJulian Elischer #endif /*JREMOD*/
4253ac6efbSJulian Elischer 
43dde8a05bSUgen J.S. Antsilevich #ifndef MIN
44dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b))
45dde8a05bSUgen J.S. Antsilevich #endif
46dde8a05bSUgen J.S. Antsilevich 
47dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP];
48dde8a05bSUgen J.S. Antsilevich 
4977f77631SPaul Traina static struct tty *
5077f77631SPaul Traina devtotty (dev)
5177f77631SPaul Traina 	dev_t		dev;
5277f77631SPaul Traina {
5377f77631SPaul Traina 	if (major(dev) > nchrdev)
5477f77631SPaul Traina 		return (NULL);		/* no such device available */
5577f77631SPaul Traina 
5677f77631SPaul Traina 	return (*cdevsw[major(dev)].d_devtotty)(dev);
5777f77631SPaul Traina }
5877f77631SPaul Traina 
590739a0dcSUgen J.S. Antsilevich #define SNP_INPUT_BUF	5	/* This is even too  much,the maximal
600739a0dcSUgen J.S. Antsilevich 				 * interactive mode write is 3 bytes
610739a0dcSUgen J.S. Antsilevich 				 * length for function keys...
620739a0dcSUgen J.S. Antsilevich 				 */
630739a0dcSUgen J.S. Antsilevich 
640739a0dcSUgen J.S. Antsilevich int
650739a0dcSUgen J.S. Antsilevich snpwrite(dev, uio, flag)
660739a0dcSUgen J.S. Antsilevich 	dev_t           dev;
670739a0dcSUgen J.S. Antsilevich 	struct uio     *uio;
680739a0dcSUgen J.S. Antsilevich 	int             flag;
690739a0dcSUgen J.S. Antsilevich {
700739a0dcSUgen J.S. Antsilevich 	int             unit = minor(dev), len, i, error;
710739a0dcSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
720739a0dcSUgen J.S. Antsilevich 	struct tty     *tp;
730739a0dcSUgen J.S. Antsilevich 	char		c[SNP_INPUT_BUF];
740739a0dcSUgen J.S. Antsilevich 
750739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
760739a0dcSUgen J.S. Antsilevich 		return (EIO);
770739a0dcSUgen J.S. Antsilevich 
780739a0dcSUgen J.S. Antsilevich 	tp = snp->snp_tty;
790739a0dcSUgen J.S. Antsilevich 
800739a0dcSUgen J.S. Antsilevich 	if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
810739a0dcSUgen J.S. Antsilevich 	    (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC))
820739a0dcSUgen J.S. Antsilevich 		goto tty_input;
830739a0dcSUgen J.S. Antsilevich 
840739a0dcSUgen J.S. Antsilevich 	printf("Snoop: attempt to write to bad tty.\n");
850739a0dcSUgen J.S. Antsilevich 	return (EIO);
860739a0dcSUgen J.S. Antsilevich 
870739a0dcSUgen J.S. Antsilevich tty_input:
880739a0dcSUgen J.S. Antsilevich 	if (!(tp->t_state & TS_ISOPEN))
890739a0dcSUgen J.S. Antsilevich 		return (EIO);
900739a0dcSUgen J.S. Antsilevich 
910739a0dcSUgen J.S. Antsilevich 	while (uio->uio_resid > 0) {
920739a0dcSUgen J.S. Antsilevich 		len = MIN(uio->uio_resid,SNP_INPUT_BUF);
930739a0dcSUgen J.S. Antsilevich 		if ((error = uiomove(c, len, uio)) != 0)
940739a0dcSUgen J.S. Antsilevich 			return (error);
950739a0dcSUgen J.S. Antsilevich 		for (i=0;i<len;i++) {
960739a0dcSUgen J.S. Antsilevich 			if (ttyinput(c[i] , tp))
970739a0dcSUgen J.S. Antsilevich 				return (EIO);
980739a0dcSUgen J.S. Antsilevich 		}
990739a0dcSUgen J.S. Antsilevich 	}
1000739a0dcSUgen J.S. Antsilevich 	return 0;
1010739a0dcSUgen J.S. Antsilevich 
1020739a0dcSUgen J.S. Antsilevich }
1030739a0dcSUgen J.S. Antsilevich 
1040739a0dcSUgen J.S. Antsilevich 
105dde8a05bSUgen J.S. Antsilevich int
106dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag)
107dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
108dde8a05bSUgen J.S. Antsilevich 	struct uio     *uio;
109dde8a05bSUgen J.S. Antsilevich 	int             flag;
110dde8a05bSUgen J.S. Antsilevich {
111dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
112dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
113dde8a05bSUgen J.S. Antsilevich 	int             len, n, nblen, error = 0;
114dde8a05bSUgen J.S. Antsilevich 	caddr_t         from;
115dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
116dde8a05bSUgen J.S. Antsilevich 
117dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
118dde8a05bSUgen J.S. Antsilevich 	if ((snp->snp_len + snp->snp_base) > snp->snp_blen)
119dde8a05bSUgen J.S. Antsilevich 		panic("snoop buffer error");
120dde8a05bSUgen J.S. Antsilevich #endif
12177f77631SPaul Traina 
1220739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
123dde8a05bSUgen J.S. Antsilevich 		return (EIO);
124dde8a05bSUgen J.S. Antsilevich 
125dde8a05bSUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_RWAIT;
126dde8a05bSUgen J.S. Antsilevich 
127dde8a05bSUgen J.S. Antsilevich 	do {
128dde8a05bSUgen J.S. Antsilevich 		if (snp->snp_len == 0) {
129dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_NBIO) {
130dde8a05bSUgen J.S. Antsilevich 				return EWOULDBLOCK;
131dde8a05bSUgen J.S. Antsilevich 			}
132dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_RWAIT;
133dde8a05bSUgen J.S. Antsilevich 			tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
134dde8a05bSUgen J.S. Antsilevich 		}
135dde8a05bSUgen J.S. Antsilevich 	} while (snp->snp_len == 0);
136dde8a05bSUgen J.S. Antsilevich 
137019b4d63SUgen J.S. Antsilevich 	n = snp->snp_len;
138dde8a05bSUgen J.S. Antsilevich 
139dde8a05bSUgen J.S. Antsilevich 	while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
140dde8a05bSUgen J.S. Antsilevich 		len = MIN(uio->uio_resid, snp->snp_len);
141dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
142dde8a05bSUgen J.S. Antsilevich 		if (len == 0)
143dde8a05bSUgen J.S. Antsilevich 			break;
144dde8a05bSUgen J.S. Antsilevich 
145dde8a05bSUgen J.S. Antsilevich 		error = uiomove(from, len, uio);
146dde8a05bSUgen J.S. Antsilevich 		snp->snp_base += len;
147dde8a05bSUgen J.S. Antsilevich 		snp->snp_len -= len;
148dde8a05bSUgen J.S. Antsilevich 	}
149019b4d63SUgen J.S. Antsilevich 	if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
150dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
151019b4d63SUgen J.S. Antsilevich 	}
152dde8a05bSUgen J.S. Antsilevich 	s = spltty();
153dde8a05bSUgen J.S. Antsilevich 	nblen = snp->snp_blen;
154dde8a05bSUgen J.S. Antsilevich 	if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
155dde8a05bSUgen J.S. Antsilevich 		while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN))
156dde8a05bSUgen J.S. Antsilevich 			nblen = nblen / 2;
157dde8a05bSUgen J.S. Antsilevich 		if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) {
158dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
159dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
160dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
161dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
162dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
163dde8a05bSUgen J.S. Antsilevich 		}
164dde8a05bSUgen J.S. Antsilevich 	}
165dde8a05bSUgen J.S. Antsilevich 	splx(s);
166dde8a05bSUgen J.S. Antsilevich 
167dde8a05bSUgen J.S. Antsilevich 	return error;
168dde8a05bSUgen J.S. Antsilevich }
169dde8a05bSUgen J.S. Antsilevich 
1700739a0dcSUgen J.S. Antsilevich int
1710739a0dcSUgen J.S. Antsilevich snpinc(snp, c)
1720739a0dcSUgen J.S. Antsilevich         struct snoop    *snp;
1730739a0dcSUgen J.S. Antsilevich         char            c;
1740739a0dcSUgen J.S. Antsilevich {
1750739a0dcSUgen J.S. Antsilevich         char    buf[1];
1760739a0dcSUgen J.S. Antsilevich 
1770739a0dcSUgen J.S. Antsilevich         buf[0]=c;
1780739a0dcSUgen J.S. Antsilevich         return (snpin(snp,buf,1));
1790739a0dcSUgen J.S. Antsilevich }
1800739a0dcSUgen J.S. Antsilevich 
181dde8a05bSUgen J.S. Antsilevich 
182dde8a05bSUgen J.S. Antsilevich int
183dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n)
184dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
185dde8a05bSUgen J.S. Antsilevich 	char           *buf;
186dde8a05bSUgen J.S. Antsilevich 	int             n;
187dde8a05bSUgen J.S. Antsilevich {
188dde8a05bSUgen J.S. Antsilevich 	int             s_free, s_tail;
189dde8a05bSUgen J.S. Antsilevich 	int             s, len, nblen;
190dde8a05bSUgen J.S. Antsilevich 	caddr_t         from, to;
191dde8a05bSUgen J.S. Antsilevich 	char           *nbuf;
192dde8a05bSUgen J.S. Antsilevich 
193dde8a05bSUgen J.S. Antsilevich 
194dde8a05bSUgen J.S. Antsilevich 	if (n == 0)
195dde8a05bSUgen J.S. Antsilevich 		return 0;
196dde8a05bSUgen J.S. Antsilevich 
197dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC
198dde8a05bSUgen J.S. Antsilevich 	if (n < 0)
199dde8a05bSUgen J.S. Antsilevich 		panic("bad snoop char count");
200dde8a05bSUgen J.S. Antsilevich 
201019b4d63SUgen J.S. Antsilevich 	if (!(snp->snp_flags & SNOOP_OPEN)) {
202019b4d63SUgen J.S. Antsilevich 		printf("Snoop: data coming to closed device.\n");
203019b4d63SUgen J.S. Antsilevich 		return 0;
204dde8a05bSUgen J.S. Antsilevich 	}
205019b4d63SUgen J.S. Antsilevich #endif
206019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_DOWN) {
207019b4d63SUgen J.S. Antsilevich 		printf("Snoop: more data to down interface.\n");
208019b4d63SUgen J.S. Antsilevich 		return 0;
209019b4d63SUgen J.S. Antsilevich 	}
210964587caSUgen J.S. Antsilevich 
211019b4d63SUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OFLOW) {
212019b4d63SUgen J.S. Antsilevich 		printf("Snoop: buffer overflow.\n");
213019b4d63SUgen J.S. Antsilevich 		/*
214019b4d63SUgen J.S. Antsilevich 		 * On overflow we just repeat the standart close
215019b4d63SUgen J.S. Antsilevich 		 * procedure...yes , this is waste of space but.. Then next
216019b4d63SUgen J.S. Antsilevich 		 * read from device will fail if one would recall he is
217019b4d63SUgen J.S. Antsilevich 		 * snooping and retry...
218019b4d63SUgen J.S. Antsilevich 		 */
219dde8a05bSUgen J.S. Antsilevich 
220964587caSUgen J.S. Antsilevich 		return (snpdown(snp));
221019b4d63SUgen J.S. Antsilevich 	}
222019b4d63SUgen J.S. Antsilevich 	s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
223019b4d63SUgen J.S. Antsilevich 	s_free = snp->snp_blen - snp->snp_len;
224dde8a05bSUgen J.S. Antsilevich 
225dde8a05bSUgen J.S. Antsilevich 
226dde8a05bSUgen J.S. Antsilevich 	if (n > s_free) {
227dde8a05bSUgen J.S. Antsilevich 		s = spltty();
228dde8a05bSUgen J.S. Antsilevich 		nblen = snp->snp_blen;
229dde8a05bSUgen J.S. Antsilevich 		while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
230dde8a05bSUgen J.S. Antsilevich 			nblen = snp->snp_blen * 2;
231dde8a05bSUgen J.S. Antsilevich 			s_free = nblen - (snp->snp_len + snp->snp_base);
232dde8a05bSUgen J.S. Antsilevich 		}
233dde8a05bSUgen J.S. Antsilevich 		if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) {
234dde8a05bSUgen J.S. Antsilevich 			bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
235dde8a05bSUgen J.S. Antsilevich 			free(snp->snp_buf, M_TTYS);
236dde8a05bSUgen J.S. Antsilevich 			snp->snp_buf = nbuf;
237dde8a05bSUgen J.S. Antsilevich 			snp->snp_blen = nblen;
238dde8a05bSUgen J.S. Antsilevich 			snp->snp_base = 0;
239dde8a05bSUgen J.S. Antsilevich 		} else {
240dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_OFLOW;
241dde8a05bSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_RWAIT) {
242dde8a05bSUgen J.S. Antsilevich 				snp->snp_flags &= ~SNOOP_RWAIT;
243dde8a05bSUgen J.S. Antsilevich 				wakeup((caddr_t) snp);
244dde8a05bSUgen J.S. Antsilevich 			}
245dde8a05bSUgen J.S. Antsilevich 			splx(s);
246dde8a05bSUgen J.S. Antsilevich 			return 0;
247dde8a05bSUgen J.S. Antsilevich 		}
248dde8a05bSUgen J.S. Antsilevich 		splx(s);
249dde8a05bSUgen J.S. Antsilevich 	}
250dde8a05bSUgen J.S. Antsilevich 	if (n > s_tail) {
251dde8a05bSUgen J.S. Antsilevich 		from = (caddr_t) (snp->snp_buf + snp->snp_base);
252dde8a05bSUgen J.S. Antsilevich 		to = (caddr_t) (snp->snp_buf);
253dde8a05bSUgen J.S. Antsilevich 		len = snp->snp_len;
254dde8a05bSUgen J.S. Antsilevich 		bcopy(from, to, len);
255dde8a05bSUgen J.S. Antsilevich 		snp->snp_base = 0;
256dde8a05bSUgen J.S. Antsilevich 	}
257dde8a05bSUgen J.S. Antsilevich 	to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len);
258dde8a05bSUgen J.S. Antsilevich 	bcopy(buf, to, n);
259dde8a05bSUgen J.S. Antsilevich 	snp->snp_len += n;
260dde8a05bSUgen J.S. Antsilevich 
261dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_RWAIT) {
262dde8a05bSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_RWAIT;
263dde8a05bSUgen J.S. Antsilevich 		wakeup((caddr_t) snp);
264dde8a05bSUgen J.S. Antsilevich 	}
265dde8a05bSUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
266dde8a05bSUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
267dde8a05bSUgen J.S. Antsilevich 
268dde8a05bSUgen J.S. Antsilevich 	return n;
269dde8a05bSUgen J.S. Antsilevich }
270dde8a05bSUgen J.S. Antsilevich 
271dde8a05bSUgen J.S. Antsilevich int
272dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p)
273dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
274dde8a05bSUgen J.S. Antsilevich 	int             flag, mode;
275dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
276dde8a05bSUgen J.S. Antsilevich {
277dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp;
278dde8a05bSUgen J.S. Antsilevich 	register int    unit, error;
279dde8a05bSUgen J.S. Antsilevich 
280dde8a05bSUgen J.S. Antsilevich 	if (error = suser(p->p_ucred, &p->p_acflag))
281dde8a05bSUgen J.S. Antsilevich 		return (error);
282dde8a05bSUgen J.S. Antsilevich 
283dde8a05bSUgen J.S. Antsilevich 	if ((unit = minor(dev)) >= NSNP)
284dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
28577f77631SPaul Traina 
286dde8a05bSUgen J.S. Antsilevich 	snp = &snoopsw[unit];
28777f77631SPaul Traina 
288dde8a05bSUgen J.S. Antsilevich 	if (snp->snp_flags & SNOOP_OPEN)
289dde8a05bSUgen J.S. Antsilevich 		return (ENXIO);
29077f77631SPaul Traina 
291019b4d63SUgen J.S. Antsilevich 	/*
292019b4d63SUgen J.S. Antsilevich 	 * We intentionally do not OR flags with SNOOP_OPEN,but set them so
293019b4d63SUgen J.S. Antsilevich 	 * all previous settings (especially SNOOP_OFLOW) will be cleared.
294019b4d63SUgen J.S. Antsilevich 	 */
295019b4d63SUgen J.S. Antsilevich 	snp->snp_flags = SNOOP_OPEN;
296dde8a05bSUgen J.S. Antsilevich 
297dde8a05bSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
298dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
299dde8a05bSUgen J.S. Antsilevich 	snp->snp_base = 0;
300dde8a05bSUgen J.S. Antsilevich 	snp->snp_len = 0;
301dde8a05bSUgen J.S. Antsilevich 
302dde8a05bSUgen J.S. Antsilevich 	/*
3030739a0dcSUgen J.S. Antsilevich 	 * snp_tty == NULL  is for inactive snoop devices.
304dde8a05bSUgen J.S. Antsilevich 	 */
3050739a0dcSUgen J.S. Antsilevich 	snp->snp_tty = NULL;
30677f77631SPaul Traina 	snp->snp_target = -1;
307dde8a05bSUgen J.S. Antsilevich 	return (0);
308dde8a05bSUgen J.S. Antsilevich }
309dde8a05bSUgen J.S. Antsilevich 
310019b4d63SUgen J.S. Antsilevich 
311019b4d63SUgen J.S. Antsilevich int
312019b4d63SUgen J.S. Antsilevich snp_detach(snp)
313019b4d63SUgen J.S. Antsilevich 	struct snoop   *snp;
314019b4d63SUgen J.S. Antsilevich {
315019b4d63SUgen J.S. Antsilevich 	struct tty     *tp;
316019b4d63SUgen J.S. Antsilevich 
317019b4d63SUgen J.S. Antsilevich 	snp->snp_base = 0;
318019b4d63SUgen J.S. Antsilevich 	snp->snp_len = 0;
319019b4d63SUgen J.S. Antsilevich 
320019b4d63SUgen J.S. Antsilevich 	/*
321019b4d63SUgen J.S. Antsilevich 	 * If line disc. changed we do not touch this pointer,SLIP/PPP will
322019b4d63SUgen J.S. Antsilevich 	 * change it anyway.
323019b4d63SUgen J.S. Antsilevich 	 */
324019b4d63SUgen J.S. Antsilevich 
3250739a0dcSUgen J.S. Antsilevich 	if (snp->snp_tty == NULL)
326964587caSUgen J.S. Antsilevich 		goto detach_notty;
327019b4d63SUgen J.S. Antsilevich 
3280739a0dcSUgen J.S. Antsilevich 	tp = snp->snp_tty;
329019b4d63SUgen J.S. Antsilevich 
33077f77631SPaul Traina 	if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
331019b4d63SUgen J.S. Antsilevich 	    (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) {
332019b4d63SUgen J.S. Antsilevich 		tp->t_sc = NULL;
333019b4d63SUgen J.S. Antsilevich 		tp->t_state &= ~TS_SNOOP;
334019b4d63SUgen J.S. Antsilevich 	} else
335019b4d63SUgen J.S. Antsilevich 		printf("Snoop: bad attached tty data.\n");
336019b4d63SUgen J.S. Antsilevich 
3370739a0dcSUgen J.S. Antsilevich 	snp->snp_tty = NULL;
33877f77631SPaul Traina 	snp->snp_target = -1;
339019b4d63SUgen J.S. Antsilevich 
340964587caSUgen J.S. Antsilevich detach_notty:
341019b4d63SUgen J.S. Antsilevich 	selwakeup(&snp->snp_sel);
342019b4d63SUgen J.S. Antsilevich 	snp->snp_sel.si_pid = 0;
343019b4d63SUgen J.S. Antsilevich 
344019b4d63SUgen J.S. Antsilevich 	return (0);
345019b4d63SUgen J.S. Antsilevich }
346019b4d63SUgen J.S. Antsilevich 
347dde8a05bSUgen J.S. Antsilevich int
34860039670SBruce Evans snpclose(dev, flags, fmt, p)
349dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
35060039670SBruce Evans 	int             flags;
35160039670SBruce Evans 	int             fmt;
35260039670SBruce Evans 	struct proc    *p;
353dde8a05bSUgen J.S. Antsilevich {
354dde8a05bSUgen J.S. Antsilevich 	register int    unit = minor(dev);
355dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
356dde8a05bSUgen J.S. Antsilevich 
357dde8a05bSUgen J.S. Antsilevich 	snp->snp_blen = 0;
358dde8a05bSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
359019b4d63SUgen J.S. Antsilevich 	snp->snp_flags &= ~SNOOP_OPEN;
360dde8a05bSUgen J.S. Antsilevich 
361019b4d63SUgen J.S. Antsilevich 	return (snp_detach(snp));
362dde8a05bSUgen J.S. Antsilevich }
363dde8a05bSUgen J.S. Antsilevich 
364964587caSUgen J.S. Antsilevich int
365964587caSUgen J.S. Antsilevich snpdown(snp)
366964587caSUgen J.S. Antsilevich 	struct snoop	*snp;
367964587caSUgen J.S. Antsilevich {
368964587caSUgen J.S. Antsilevich 	snp->snp_blen = SNOOP_MINLEN;
369964587caSUgen J.S. Antsilevich 	free(snp->snp_buf, M_TTYS);
370964587caSUgen J.S. Antsilevich 	snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
371964587caSUgen J.S. Antsilevich 	snp->snp_flags |= SNOOP_DOWN;
372dde8a05bSUgen J.S. Antsilevich 
373964587caSUgen J.S. Antsilevich 	return (snp_detach(snp));
374964587caSUgen J.S. Antsilevich }
375dde8a05bSUgen J.S. Antsilevich 
376dde8a05bSUgen J.S. Antsilevich 
377dde8a05bSUgen J.S. Antsilevich int
37860039670SBruce Evans snpioctl(dev, cmd, data, flags, p)
379dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
380dde8a05bSUgen J.S. Antsilevich 	int             cmd;
381dde8a05bSUgen J.S. Antsilevich 	caddr_t         data;
38260039670SBruce Evans 	int             flags;
38360039670SBruce Evans 	struct proc    *p;
384dde8a05bSUgen J.S. Antsilevich {
385dde8a05bSUgen J.S. Antsilevich 	int             unit = minor(dev), s;
38677f77631SPaul Traina 	dev_t		tdev;
387dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
388dde8a05bSUgen J.S. Antsilevich 	struct tty     *tp, *tpo;
389dde8a05bSUgen J.S. Antsilevich 
390dde8a05bSUgen J.S. Antsilevich 	switch (cmd) {
391dde8a05bSUgen J.S. Antsilevich 	case SNPSTTY:
39277f77631SPaul Traina 		tdev = *((dev_t *) data);
39377f77631SPaul Traina 		if (tdev == -1)
394964587caSUgen J.S. Antsilevich 			return (snpdown(snp));
395964587caSUgen J.S. Antsilevich 
39677f77631SPaul Traina 		tp = devtotty(tdev);
39777f77631SPaul Traina 		if (!tp)
398dde8a05bSUgen J.S. Antsilevich 			return (EINVAL);
399dde8a05bSUgen J.S. Antsilevich 
40077f77631SPaul Traina 		if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP))
401dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
402dde8a05bSUgen J.S. Antsilevich 
40377f77631SPaul Traina 		if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC))
404dde8a05bSUgen J.S. Antsilevich 			return (EBUSY);
405dde8a05bSUgen J.S. Antsilevich 
406dde8a05bSUgen J.S. Antsilevich 		s = spltty();
40777f77631SPaul Traina 
40877f77631SPaul Traina 		if (snp->snp_target == -1) {
4090739a0dcSUgen J.S. Antsilevich 			tpo = snp->snp_tty;
41077f77631SPaul Traina 			if (tpo)
411dde8a05bSUgen J.S. Antsilevich 				tpo->t_state &= ~TS_SNOOP;
412dde8a05bSUgen J.S. Antsilevich 		}
41377f77631SPaul Traina 
414dde8a05bSUgen J.S. Antsilevich 		tp->t_sc = (caddr_t) snp;
415dde8a05bSUgen J.S. Antsilevich 		tp->t_state |= TS_SNOOP;
4160739a0dcSUgen J.S. Antsilevich 		snp->snp_tty = tp;
41777f77631SPaul Traina 		snp->snp_target = tdev;
41877f77631SPaul Traina 
419964587caSUgen J.S. Antsilevich 		/*
420964587caSUgen J.S. Antsilevich 		 * Clean overflow and down flags -
421964587caSUgen J.S. Antsilevich 		 * we'll have a chance to get them in the future :)))
422964587caSUgen J.S. Antsilevich 		 */
423964587caSUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_OFLOW;
424019b4d63SUgen J.S. Antsilevich 		snp->snp_flags &= ~SNOOP_DOWN;
425dde8a05bSUgen J.S. Antsilevich 		splx(s);
426dde8a05bSUgen J.S. Antsilevich 		break;
42777f77631SPaul Traina 
428dde8a05bSUgen J.S. Antsilevich 	case SNPGTTY:
4290739a0dcSUgen J.S. Antsilevich 		/*
4300739a0dcSUgen J.S. Antsilevich 		 * We keep snp_target field specially to make
4310739a0dcSUgen J.S. Antsilevich 		 * SNPGTTY happy,else we can't know what is device
4320739a0dcSUgen J.S. Antsilevich 		 * major/minor for tty.
4330739a0dcSUgen J.S. Antsilevich 		 */
43477f77631SPaul Traina 		*((dev_t *) data) = snp->snp_target;
435dde8a05bSUgen J.S. Antsilevich 		break;
436dde8a05bSUgen J.S. Antsilevich 
437dde8a05bSUgen J.S. Antsilevich 	case FIONBIO:
438dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
439dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_NBIO;
440dde8a05bSUgen J.S. Antsilevich 		else
441dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_NBIO;
442dde8a05bSUgen J.S. Antsilevich 		break;
44377f77631SPaul Traina 
444dde8a05bSUgen J.S. Antsilevich 	case FIOASYNC:
445dde8a05bSUgen J.S. Antsilevich 		if (*(int *) data)
446dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags |= SNOOP_ASYNC;
447dde8a05bSUgen J.S. Antsilevich 		else
448dde8a05bSUgen J.S. Antsilevich 			snp->snp_flags &= ~SNOOP_ASYNC;
449dde8a05bSUgen J.S. Antsilevich 		break;
45077f77631SPaul Traina 
451dde8a05bSUgen J.S. Antsilevich 	case FIONREAD:
452dde8a05bSUgen J.S. Antsilevich 		s = spltty();
4530739a0dcSUgen J.S. Antsilevich 		if (snp->snp_tty != NULL)
454dde8a05bSUgen J.S. Antsilevich 			*(int *) data = snp->snp_len;
455dde8a05bSUgen J.S. Antsilevich 		else
456964587caSUgen J.S. Antsilevich 			if (snp->snp_flags & SNOOP_DOWN) {
457964587caSUgen J.S. Antsilevich 				if (snp->snp_flags & SNOOP_OFLOW)
458964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_OFLOW;
459964587caSUgen J.S. Antsilevich 				else
460964587caSUgen J.S. Antsilevich 					*(int *) data = SNP_TTYCLOSE;
461964587caSUgen J.S. Antsilevich 			} else {
462964587caSUgen J.S. Antsilevich 				*(int *) data = SNP_DETACH;
463964587caSUgen J.S. Antsilevich 			}
464dde8a05bSUgen J.S. Antsilevich 		splx(s);
465dde8a05bSUgen J.S. Antsilevich 		break;
46677f77631SPaul Traina 
467dde8a05bSUgen J.S. Antsilevich 	default:
468dde8a05bSUgen J.S. Antsilevich 		return (ENOTTY);
469dde8a05bSUgen J.S. Antsilevich 	}
470dde8a05bSUgen J.S. Antsilevich 	return (0);
471dde8a05bSUgen J.S. Antsilevich }
472dde8a05bSUgen J.S. Antsilevich 
473dde8a05bSUgen J.S. Antsilevich 
474dde8a05bSUgen J.S. Antsilevich int
475dde8a05bSUgen J.S. Antsilevich snpselect(dev, rw, p)
476dde8a05bSUgen J.S. Antsilevich 	dev_t           dev;
477dde8a05bSUgen J.S. Antsilevich 	int             rw;
478dde8a05bSUgen J.S. Antsilevich 	struct proc    *p;
479dde8a05bSUgen J.S. Antsilevich {
480a98ca469SPoul-Henning Kamp 	int             unit = minor(dev);
481dde8a05bSUgen J.S. Antsilevich 	struct snoop   *snp = &snoopsw[unit];
482dde8a05bSUgen J.S. Antsilevich 
48377f77631SPaul Traina 	if (rw != FREAD)
4840739a0dcSUgen J.S. Antsilevich 		return 1;
48577f77631SPaul Traina 
48677f77631SPaul Traina 	if (snp->snp_len > 0)
487dde8a05bSUgen J.S. Antsilevich 		return 1;
48877f77631SPaul Traina 
489019b4d63SUgen J.S. Antsilevich 	/*
490019b4d63SUgen J.S. Antsilevich 	 * If snoop is down,we don't want to select() forever so we return 1.
491019b4d63SUgen J.S. Antsilevich 	 * Caller should see if we down via FIONREAD ioctl().The last should
492019b4d63SUgen J.S. Antsilevich 	 * return -1 to indicate down state.
493019b4d63SUgen J.S. Antsilevich 	 */
49477f77631SPaul Traina 	if (snp->snp_flags & SNOOP_DOWN)
495019b4d63SUgen J.S. Antsilevich 		return 1;
49677f77631SPaul Traina 
497dde8a05bSUgen J.S. Antsilevich 	selrecord(p, &snp->snp_sel);
498dde8a05bSUgen J.S. Antsilevich 	return 0;
499dde8a05bSUgen J.S. Antsilevich }
500dde8a05bSUgen J.S. Antsilevich 
50153ac6efbSJulian Elischer #ifdef JREMOD
50253ac6efbSJulian Elischer struct cdevsw snp_cdevsw =
50353ac6efbSJulian Elischer 	{ snpopen,	snpclose,	snpread,	snpwrite,	/*53*/
50453ac6efbSJulian Elischer 	  snpioctl,	nostop,		nullreset,	nodevtotty,/* snoop */
50553ac6efbSJulian Elischer 	  snpselect,	nommap,		NULL };
50653ac6efbSJulian Elischer 
50753ac6efbSJulian Elischer static snp_devsw_installed = 0;
50853ac6efbSJulian Elischer 
50953ac6efbSJulian Elischer static void 	snp_drvinit(void *unused)
51053ac6efbSJulian Elischer {
51153ac6efbSJulian Elischer 	dev_t dev;
51253ac6efbSJulian Elischer 
51353ac6efbSJulian Elischer 	if( ! snp_devsw_installed ) {
51453ac6efbSJulian Elischer 		dev = makedev(CDEV_MAJOR,0);
51553ac6efbSJulian Elischer 		cdevsw_add(&dev,&snp_cdevsw,NULL);
51653ac6efbSJulian Elischer 		snp_devsw_installed = 1;
51753ac6efbSJulian Elischer #ifdef DEVFS
51853ac6efbSJulian Elischer 		{
51953ac6efbSJulian Elischer 			int x;
52053ac6efbSJulian Elischer /* default for a simple device with no probe routine (usually delete this) */
52153ac6efbSJulian Elischer 			x=devfs_add_devsw(
52253ac6efbSJulian Elischer /*	path	name	devsw		minor	type   uid gid perm*/
52353ac6efbSJulian Elischer 	"/",	"snp",	major(dev),	0,	DV_CHR,	0,  0, 0600);
52453ac6efbSJulian Elischer 		}
52553ac6efbSJulian Elischer #endif
52653ac6efbSJulian Elischer     	}
5277198bf47SJulian Elischer }
52853ac6efbSJulian Elischer 
52953ac6efbSJulian Elischer SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL)
53053ac6efbSJulian Elischer 
53153ac6efbSJulian Elischer #endif /* JREMOD */
53253ac6efbSJulian Elischer 
533dde8a05bSUgen J.S. Antsilevich #endif
534