xref: /freebsd/sys/dev/snp/snp.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1098ca2bdSWarner Losh /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4932ef5b5SEd Schouten  * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
5932ef5b5SEd Schouten  * All rights reserved.
6dde8a05bSUgen J.S. Antsilevich  *
7932ef5b5SEd Schouten  * Redistribution and use in source and binary forms, with or without
8932ef5b5SEd Schouten  * modification, are permitted provided that the following conditions
9932ef5b5SEd Schouten  * are met:
10932ef5b5SEd Schouten  * 1. Redistributions of source code must retain the above copyright
11932ef5b5SEd Schouten  *    notice, this list of conditions and the following disclaimer.
12932ef5b5SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
13932ef5b5SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
14932ef5b5SEd Schouten  *    documentation and/or other materials provided with the distribution.
15dde8a05bSUgen J.S. Antsilevich  *
16932ef5b5SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17932ef5b5SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18932ef5b5SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19932ef5b5SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20932ef5b5SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21932ef5b5SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22932ef5b5SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23932ef5b5SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24932ef5b5SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25932ef5b5SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26932ef5b5SEd Schouten  * SUCH DAMAGE.
27dde8a05bSUgen J.S. Antsilevich  */
28dde8a05bSUgen J.S. Antsilevich 
29dde8a05bSUgen J.S. Antsilevich #include <sys/param.h>
30932ef5b5SEd Schouten #include <sys/conf.h>
311ef0fc1dSPoul-Henning Kamp #include <sys/fcntl.h>
3271455815SBruce Evans #include <sys/filio.h>
33dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h>
34932ef5b5SEd Schouten #include <sys/malloc.h>
35fe12f24bSPoul-Henning Kamp #include <sys/module.h>
36932ef5b5SEd Schouten #include <sys/poll.h>
37a9385ad1SAlexander Motin #include <sys/proc.h>
3887f6c662SJulian Elischer #include <sys/snoop.h>
39932ef5b5SEd Schouten #include <sys/sx.h>
40932ef5b5SEd Schouten #include <sys/systm.h>
41932ef5b5SEd Schouten #include <sys/tty.h>
421ef0fc1dSPoul-Henning Kamp #include <sys/uio.h>
4387f6c662SJulian Elischer 
44932ef5b5SEd Schouten static struct cdev	*snp_dev;
457fb6f685SEd Schouten static MALLOC_DEFINE(M_SNP, "snp", "tty snoop device");
467fb6f685SEd Schouten 
47932ef5b5SEd Schouten /* XXX: should be mtx, but TTY can be locked by Giant. */
487fb6f685SEd Schouten #if 0
497fb6f685SEd Schouten static struct mtx	snp_register_lock;
507fb6f685SEd Schouten MTX_SYSINIT(snp_register_lock, &snp_register_lock,
517fb6f685SEd Schouten     "tty snoop registration", MTX_DEF);
527fb6f685SEd Schouten #define	SNP_LOCK()	mtx_lock(&snp_register_lock)
537fb6f685SEd Schouten #define	SNP_UNLOCK()	mtx_unlock(&snp_register_lock)
547fb6f685SEd Schouten #else
55932ef5b5SEd Schouten static struct sx	snp_register_lock;
56932ef5b5SEd Schouten SX_SYSINIT(snp_register_lock, &snp_register_lock,
57932ef5b5SEd Schouten     "tty snoop registration");
587fb6f685SEd Schouten #define	SNP_LOCK()	sx_xlock(&snp_register_lock)
597fb6f685SEd Schouten #define	SNP_UNLOCK()	sx_xunlock(&snp_register_lock)
607fb6f685SEd Schouten #endif
61932ef5b5SEd Schouten 
6269921123SKonstantin Belousov #define	SNPGTYY_32DEV	_IOR('T', 89, uint32_t)
6369921123SKonstantin Belousov 
64932ef5b5SEd Schouten /*
65932ef5b5SEd Schouten  * There is no need to have a big input buffer. In most typical setups,
66932ef5b5SEd Schouten  * we won't inject much data into the TTY, because users can't type
67932ef5b5SEd Schouten  * really fast.
68932ef5b5SEd Schouten  */
69932ef5b5SEd Schouten #define SNP_INPUT_BUFSIZE	16
70932ef5b5SEd Schouten /*
71932ef5b5SEd Schouten  * The output buffer has to be really big. Right now we don't support
72932ef5b5SEd Schouten  * any form of flow control, which means we lost any data we can't
73932ef5b5SEd Schouten  * accept. We set the output buffer size to about twice the size of a
74932ef5b5SEd Schouten  * pseudo-terminal/virtual console's output buffer.
75932ef5b5SEd Schouten  */
76932ef5b5SEd Schouten #define SNP_OUTPUT_BUFSIZE	16384
77932ef5b5SEd Schouten 
78932ef5b5SEd Schouten static d_open_t		snp_open;
79932ef5b5SEd Schouten static d_read_t		snp_read;
80932ef5b5SEd Schouten static d_write_t	snp_write;
81932ef5b5SEd Schouten static d_ioctl_t	snp_ioctl;
82932ef5b5SEd Schouten static d_poll_t		snp_poll;
8387f6c662SJulian Elischer 
844e2f199eSPoul-Henning Kamp static struct cdevsw snp_cdevsw = {
85dc08ffecSPoul-Henning Kamp 	.d_version	= D_VERSION,
86932ef5b5SEd Schouten 	.d_open		= snp_open,
87932ef5b5SEd Schouten 	.d_read		= snp_read,
88932ef5b5SEd Schouten 	.d_write	= snp_write,
89932ef5b5SEd Schouten 	.d_ioctl	= snp_ioctl,
90932ef5b5SEd Schouten 	.d_poll		= snp_poll,
917ac40f5fSPoul-Henning Kamp 	.d_name		= "snp",
924e2f199eSPoul-Henning Kamp };
9387f6c662SJulian Elischer 
94932ef5b5SEd Schouten static th_getc_capture_t	snp_getc_capture;
95932ef5b5SEd Schouten 
96932ef5b5SEd Schouten static struct ttyhook snp_hook = {
97932ef5b5SEd Schouten 	.th_getc_capture	= snp_getc_capture,
98f09f49f1SDima Dorfman };
9953ac6efbSJulian Elischer 
100101f105dSDima Dorfman /*
101932ef5b5SEd Schouten  * Per-instance structure.
102932ef5b5SEd Schouten  *
103932ef5b5SEd Schouten  * List of locks
104932ef5b5SEd Schouten  * (r)	locked by snp_register_lock on assignment
105932ef5b5SEd Schouten  * (t)	locked by tty_lock
106101f105dSDima Dorfman  */
107932ef5b5SEd Schouten struct snp_softc {
108932ef5b5SEd Schouten 	struct tty	*snp_tty;	/* (r) TTY we're snooping. */
109932ef5b5SEd Schouten 	struct ttyoutq	snp_outq;	/* (t) Output queue. */
110932ef5b5SEd Schouten 	struct cv	snp_outwait;	/* (t) Output wait queue. */
111932ef5b5SEd Schouten 	struct selinfo	snp_outpoll;	/* (t) Output polling. */
112101f105dSDima Dorfman };
113101f105dSDima Dorfman 
1142e37c8eaSEd Schouten static void
snp_dtor(void * data)1152e37c8eaSEd Schouten snp_dtor(void *data)
1162e37c8eaSEd Schouten {
117932ef5b5SEd Schouten 	struct snp_softc *ss = data;
118932ef5b5SEd Schouten 	struct tty *tp;
1192e37c8eaSEd Schouten 
120932ef5b5SEd Schouten 	tp = ss->snp_tty;
121932ef5b5SEd Schouten 	if (tp != NULL) {
122932ef5b5SEd Schouten 		tty_lock(tp);
123932ef5b5SEd Schouten 		ttyoutq_free(&ss->snp_outq);
124932ef5b5SEd Schouten 		ttyhook_unregister(tp);
125550e01c5SKonstantin Belousov 		ss->snp_tty = NULL;
126932ef5b5SEd Schouten 	}
127932ef5b5SEd Schouten 
128932ef5b5SEd Schouten 	cv_destroy(&ss->snp_outwait);
129932ef5b5SEd Schouten 	free(ss, M_SNP);
130932ef5b5SEd Schouten }
131932ef5b5SEd Schouten 
132932ef5b5SEd Schouten /*
133932ef5b5SEd Schouten  * Snoop device node routines.
134932ef5b5SEd Schouten  */
135932ef5b5SEd Schouten 
136932ef5b5SEd Schouten static int
snp_open(struct cdev * dev,int flag,int mode,struct thread * td)137932ef5b5SEd Schouten snp_open(struct cdev *dev, int flag, int mode, struct thread *td)
138932ef5b5SEd Schouten {
139932ef5b5SEd Schouten 	struct snp_softc *ss;
140932ef5b5SEd Schouten 
141932ef5b5SEd Schouten 	/* Allocate per-snoop data. */
142932ef5b5SEd Schouten 	ss = malloc(sizeof(struct snp_softc), M_SNP, M_WAITOK|M_ZERO);
143932ef5b5SEd Schouten 	cv_init(&ss->snp_outwait, "snp out");
144932ef5b5SEd Schouten 
145932ef5b5SEd Schouten 	devfs_set_cdevpriv(ss, snp_dtor);
146932ef5b5SEd Schouten 
147932ef5b5SEd Schouten 	return (0);
1482e37c8eaSEd Schouten }
1492e37c8eaSEd Schouten 
15087f6c662SJulian Elischer static int
snp_read(struct cdev * dev,struct uio * uio,int flag)151932ef5b5SEd Schouten snp_read(struct cdev *dev, struct uio *uio, int flag)
152dde8a05bSUgen J.S. Antsilevich {
153932ef5b5SEd Schouten 	int error, oresid = uio->uio_resid;
154932ef5b5SEd Schouten 	struct snp_softc *ss;
155932ef5b5SEd Schouten 	struct tty *tp;
156dde8a05bSUgen J.S. Antsilevich 
157932ef5b5SEd Schouten 	if (uio->uio_resid == 0)
158932ef5b5SEd Schouten 		return (0);
159932ef5b5SEd Schouten 
160932ef5b5SEd Schouten 	error = devfs_get_cdevpriv((void **)&ss);
161932ef5b5SEd Schouten 	if (error != 0)
162932ef5b5SEd Schouten 		return (error);
163932ef5b5SEd Schouten 
164932ef5b5SEd Schouten 	tp = ss->snp_tty;
165932ef5b5SEd Schouten 	if (tp == NULL || tty_gone(tp))
166932ef5b5SEd Schouten 		return (EIO);
167932ef5b5SEd Schouten 
168932ef5b5SEd Schouten 	tty_lock(tp);
169932ef5b5SEd Schouten 	for (;;) {
170932ef5b5SEd Schouten 		error = ttyoutq_read_uio(&ss->snp_outq, tp, uio);
171932ef5b5SEd Schouten 		if (error != 0 || uio->uio_resid != oresid)
172932ef5b5SEd Schouten 			break;
173932ef5b5SEd Schouten 
174932ef5b5SEd Schouten 		/* Wait for more data. */
175932ef5b5SEd Schouten 		if (flag & O_NONBLOCK) {
176932ef5b5SEd Schouten 			error = EWOULDBLOCK;
177932ef5b5SEd Schouten 			break;
178932ef5b5SEd Schouten 		}
179ed623289SKyle Evans 		error = cv_wait_sig(&ss->snp_outwait, tty_getlock(tp));
180932ef5b5SEd Schouten 		if (error != 0)
181932ef5b5SEd Schouten 			break;
182932ef5b5SEd Schouten 		if (tty_gone(tp)) {
183932ef5b5SEd Schouten 			error = EIO;
184932ef5b5SEd Schouten 			break;
185932ef5b5SEd Schouten 		}
186932ef5b5SEd Schouten 	}
187932ef5b5SEd Schouten 	tty_unlock(tp);
188932ef5b5SEd Schouten 
1892e37c8eaSEd Schouten 	return (error);
1902e37c8eaSEd Schouten }
19177f77631SPaul Traina 
192932ef5b5SEd Schouten static int
snp_write(struct cdev * dev,struct uio * uio,int flag)193932ef5b5SEd Schouten snp_write(struct cdev *dev, struct uio *uio, int flag)
194019b4d63SUgen J.S. Antsilevich {
195932ef5b5SEd Schouten 	struct snp_softc *ss;
196019b4d63SUgen J.S. Antsilevich 	struct tty *tp;
1975c67885aSEd Schouten 	int error, len;
198932ef5b5SEd Schouten 	char in[SNP_INPUT_BUFSIZE];
199019b4d63SUgen J.S. Antsilevich 
200932ef5b5SEd Schouten 	error = devfs_get_cdevpriv((void **)&ss);
201932ef5b5SEd Schouten 	if (error != 0)
202932ef5b5SEd Schouten 		return (error);
203932ef5b5SEd Schouten 
204932ef5b5SEd Schouten 	tp = ss->snp_tty;
205932ef5b5SEd Schouten 	if (tp == NULL || tty_gone(tp))
206932ef5b5SEd Schouten 		return (EIO);
207932ef5b5SEd Schouten 
208932ef5b5SEd Schouten 	while (uio->uio_resid > 0) {
209932ef5b5SEd Schouten 		/* Read new data. */
210932ef5b5SEd Schouten 		len = imin(uio->uio_resid, sizeof in);
211932ef5b5SEd Schouten 		error = uiomove(in, len, uio);
212932ef5b5SEd Schouten 		if (error != 0)
213932ef5b5SEd Schouten 			return (error);
214932ef5b5SEd Schouten 
215932ef5b5SEd Schouten 		tty_lock(tp);
216932ef5b5SEd Schouten 
217932ef5b5SEd Schouten 		/* Driver could have abandoned the TTY in the mean time. */
218932ef5b5SEd Schouten 		if (tty_gone(tp)) {
219932ef5b5SEd Schouten 			tty_unlock(tp);
220932ef5b5SEd Schouten 			return (ENXIO);
221932ef5b5SEd Schouten 		}
222019b4d63SUgen J.S. Antsilevich 
223019b4d63SUgen J.S. Antsilevich 		/*
224932ef5b5SEd Schouten 		 * Deliver data to the TTY. Ignore errors for now,
225932ef5b5SEd Schouten 		 * because we shouldn't bail out when we're running
226932ef5b5SEd Schouten 		 * close to the watermarks.
227019b4d63SUgen J.S. Antsilevich 		 */
2285c67885aSEd Schouten 		ttydisc_rint_simple(tp, in, len);
229932ef5b5SEd Schouten 		ttydisc_rint_done(tp);
2305c67885aSEd Schouten 
231932ef5b5SEd Schouten 		tty_unlock(tp);
23276e90dbcSBrian Feldman 	}
233dde8a05bSUgen J.S. Antsilevich 
234542a8db5SKonstantin Belousov 	return (0);
235964587caSUgen J.S. Antsilevich }
236dde8a05bSUgen J.S. Antsilevich 
23787f6c662SJulian Elischer static int
snp_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)238932ef5b5SEd Schouten snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
2397409f6cdSCraig Rodrigues     struct thread *td)
240dde8a05bSUgen J.S. Antsilevich {
241932ef5b5SEd Schouten 	struct snp_softc *ss;
242316d90a3SKonstantin Belousov 	struct tty *tp;
243932ef5b5SEd Schouten 	int error;
244dde8a05bSUgen J.S. Antsilevich 
245932ef5b5SEd Schouten 	error = devfs_get_cdevpriv((void **)&ss);
2462e37c8eaSEd Schouten 	if (error != 0)
2472e37c8eaSEd Schouten 		return (error);
2482e37c8eaSEd Schouten 
249dde8a05bSUgen J.S. Antsilevich 	switch (cmd) {
250dde8a05bSUgen J.S. Antsilevich 	case SNPSTTY:
251932ef5b5SEd Schouten 		/* Bind TTY to snoop instance. */
2527fb6f685SEd Schouten 		SNP_LOCK();
253550e01c5SKonstantin Belousov 		tp = ss->snp_tty;
254550e01c5SKonstantin Belousov 		if (tp != NULL) {
255550e01c5SKonstantin Belousov 			if (*(int *)data == -1) {
256550e01c5SKonstantin Belousov 				tty_lock(tp);
257550e01c5SKonstantin Belousov 				ss->snp_tty = NULL;
258550e01c5SKonstantin Belousov 				ttyoutq_free(&ss->snp_outq);
259550e01c5SKonstantin Belousov 				ttyhook_unregister(tp);
260550e01c5SKonstantin Belousov 				error = 0;
261550e01c5SKonstantin Belousov 			} else {
262550e01c5SKonstantin Belousov 				error = EBUSY;
263550e01c5SKonstantin Belousov 			}
2647fb6f685SEd Schouten 			SNP_UNLOCK();
265550e01c5SKonstantin Belousov 			return (error);
26630ce1aadSOlivier Houchard 		}
267a9d2f8d8SRobert Watson 		/*
268a9d2f8d8SRobert Watson 		 * XXXRW / XXXJA: no capability check here.
269a9d2f8d8SRobert Watson 		 */
270aa16f86cSEd Schouten 		error = ttyhook_register(&ss->snp_tty, td->td_proc,
271aa16f86cSEd Schouten 		    *(int *)data, &snp_hook, ss);
2727fb6f685SEd Schouten 		SNP_UNLOCK();
273932ef5b5SEd Schouten 		if (error != 0)
274932ef5b5SEd Schouten 			return (error);
275964587caSUgen J.S. Antsilevich 
276932ef5b5SEd Schouten 		/* Now that went okay, allocate a buffer for the queue. */
277932ef5b5SEd Schouten 		tp = ss->snp_tty;
278932ef5b5SEd Schouten 		tty_lock(tp);
279932ef5b5SEd Schouten 		ttyoutq_setsize(&ss->snp_outq, tp, SNP_OUTPUT_BUFSIZE);
280932ef5b5SEd Schouten 		tty_unlock(tp);
281316d90a3SKonstantin Belousov 
282932ef5b5SEd Schouten 		return (0);
283dde8a05bSUgen J.S. Antsilevich 	case SNPGTTY:
284932ef5b5SEd Schouten 		/* Obtain device number of associated TTY. */
285932ef5b5SEd Schouten 		if (ss->snp_tty == NULL)
286932ef5b5SEd Schouten 			*(dev_t *)data = NODEV;
287dde8a05bSUgen J.S. Antsilevich 		else
288932ef5b5SEd Schouten 			*(dev_t *)data = tty_udev(ss->snp_tty);
289932ef5b5SEd Schouten 		return (0);
29069921123SKonstantin Belousov 	case SNPGTYY_32DEV:
29169921123SKonstantin Belousov 		if (ss->snp_tty == NULL)
29269921123SKonstantin Belousov 			*(uint32_t *)data = -1;
29369921123SKonstantin Belousov 		else
29469921123SKonstantin Belousov 			*(uint32_t *)data = tty_udev(ss->snp_tty); /* trunc */
29569921123SKonstantin Belousov 		return (0);
296dde8a05bSUgen J.S. Antsilevich 	case FIONREAD:
297932ef5b5SEd Schouten 		tp = ss->snp_tty;
298932ef5b5SEd Schouten 		if (tp != NULL) {
299932ef5b5SEd Schouten 			tty_lock(tp);
300bb4be76cSKonstantin Belousov 			if (tty_gone(tp))
301bb4be76cSKonstantin Belousov 				*(int *)data = SNP_TTYCLOSE;
302bb4be76cSKonstantin Belousov 			else
303932ef5b5SEd Schouten 				*(int *)data = ttyoutq_bytesused(&ss->snp_outq);
304932ef5b5SEd Schouten 			tty_unlock(tp);
305964587caSUgen J.S. Antsilevich 		} else {
306bb4be76cSKonstantin Belousov 			*(int *)data = SNP_DETACH;
307964587caSUgen J.S. Antsilevich 		}
308932ef5b5SEd Schouten 		return (0);
309dde8a05bSUgen J.S. Antsilevich 	default:
310dde8a05bSUgen J.S. Antsilevich 		return (ENOTTY);
311dde8a05bSUgen J.S. Antsilevich 	}
312dde8a05bSUgen J.S. Antsilevich }
313dde8a05bSUgen J.S. Antsilevich 
31487f6c662SJulian Elischer static int
snp_poll(struct cdev * dev,int events,struct thread * td)315932ef5b5SEd Schouten snp_poll(struct cdev *dev, int events, struct thread *td)
316dde8a05bSUgen J.S. Antsilevich {
317932ef5b5SEd Schouten 	struct snp_softc *ss;
318932ef5b5SEd Schouten 	struct tty *tp;
319f09f49f1SDima Dorfman 	int revents;
320dde8a05bSUgen J.S. Antsilevich 
321932ef5b5SEd Schouten 	if (devfs_get_cdevpriv((void **)&ss) != 0)
3222e37c8eaSEd Schouten 		return (events &
3232e37c8eaSEd Schouten 		    (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
3242e37c8eaSEd Schouten 
325f09f49f1SDima Dorfman 	revents = 0;
326932ef5b5SEd Schouten 
327dfd5dee1SPeter Wemm 	if (events & (POLLIN | POLLRDNORM)) {
328932ef5b5SEd Schouten 		tp = ss->snp_tty;
329932ef5b5SEd Schouten 		if (tp != NULL) {
330932ef5b5SEd Schouten 			tty_lock(tp);
331932ef5b5SEd Schouten 			if (ttyoutq_bytesused(&ss->snp_outq) > 0)
332659ffb48SPeter Wemm 				revents |= events & (POLLIN | POLLRDNORM);
333932ef5b5SEd Schouten 			tty_unlock(tp);
334dfd5dee1SPeter Wemm 		}
335932ef5b5SEd Schouten 	}
336932ef5b5SEd Schouten 
337932ef5b5SEd Schouten 	if (revents == 0)
338932ef5b5SEd Schouten 		selrecord(td, &ss->snp_outpoll);
339932ef5b5SEd Schouten 
340659ffb48SPeter Wemm 	return (revents);
341dde8a05bSUgen J.S. Antsilevich }
342dde8a05bSUgen J.S. Antsilevich 
343932ef5b5SEd Schouten /*
344932ef5b5SEd Schouten  * TTY hook events.
345932ef5b5SEd Schouten  */
346932ef5b5SEd Schouten 
34747eaa5f5SDima Dorfman static int
snp_modevent(module_t mod,int type,void * data)3487409f6cdSCraig Rodrigues snp_modevent(module_t mod, int type, void *data)
34953ac6efbSJulian Elischer {
35053ac6efbSJulian Elischer 
35147eaa5f5SDima Dorfman 	switch (type) {
35247eaa5f5SDima Dorfman 	case MOD_LOAD:
353932ef5b5SEd Schouten 		snp_dev = make_dev(&snp_cdevsw, 0,
354932ef5b5SEd Schouten 		    UID_ROOT, GID_WHEEL, 0600, "snp");
355932ef5b5SEd Schouten 		return (0);
35647eaa5f5SDima Dorfman 	case MOD_UNLOAD:
357932ef5b5SEd Schouten 		/* XXX: Make existing users leave. */
358932ef5b5SEd Schouten 		destroy_dev(snp_dev);
359932ef5b5SEd Schouten 		return (0);
36047eaa5f5SDima Dorfman 	default:
3613e019deaSPoul-Henning Kamp 		return (EOPNOTSUPP);
36247eaa5f5SDima Dorfman 	}
363932ef5b5SEd Schouten }
364932ef5b5SEd Schouten 
365932ef5b5SEd Schouten static void
snp_getc_capture(struct tty * tp,const void * buf,size_t len)366932ef5b5SEd Schouten snp_getc_capture(struct tty *tp, const void *buf, size_t len)
367932ef5b5SEd Schouten {
368932ef5b5SEd Schouten 	struct snp_softc *ss = ttyhook_softc(tp);
369932ef5b5SEd Schouten 
370932ef5b5SEd Schouten 	ttyoutq_write(&ss->snp_outq, buf, len);
371932ef5b5SEd Schouten 
372932ef5b5SEd Schouten 	cv_broadcast(&ss->snp_outwait);
373932ef5b5SEd Schouten 	selwakeup(&ss->snp_outpoll);
3747198bf47SJulian Elischer }
37553ac6efbSJulian Elischer 
37647eaa5f5SDima Dorfman static moduledata_t snp_mod = {
37747eaa5f5SDima Dorfman 	"snp",
37847eaa5f5SDima Dorfman 	snp_modevent,
37947eaa5f5SDima Dorfman 	NULL
38047eaa5f5SDima Dorfman };
381932ef5b5SEd Schouten 
382b0b03348SPoul-Henning Kamp DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
383