From owner-svn-src-head@FreeBSD.ORG Wed Nov 5 15:04:04 2008 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 605FA1065673; Wed, 5 Nov 2008 15:04:04 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4C1F08FC25; Wed, 5 Nov 2008 15:04:04 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mA5F440L029905; Wed, 5 Nov 2008 15:04:04 GMT (envelope-from ed@svn.freebsd.org) Received: (from ed@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mA5F44tx029900; Wed, 5 Nov 2008 15:04:04 GMT (envelope-from ed@svn.freebsd.org) Message-Id: <200811051504.mA5F44tx029900@svn.freebsd.org> From: Ed Schouten Date: Wed, 5 Nov 2008 15:04:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r184689 - in head: share/man/man4 sys/conf sys/dev/snp sys/modules sys/modules/snp X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Nov 2008 15:04:04 -0000 Author: ed Date: Wed Nov 5 15:04:03 2008 New Revision: 184689 URL: http://svn.freebsd.org/changeset/base/184689 Log: Reintroduce the snp(4) driver. Because the TTY hooks interface was not finished when I imported the MPSAFE TTY layer, I had to disconnect the snp(4) driver. This snp(4) implementation has been sitting in my P4 branch for some time now. Unfortunately it still doesn't use the same error handling as snp(4) (returning codes through FIONREAD), but it should already be usable. I'm committing this to SVN, hoping someone else could polish off its rough edges. It's always better than having a broken driver sitting in the tree. Modified: head/share/man/man4/snp.4 head/sys/conf/NOTES head/sys/dev/snp/snp.c head/sys/modules/Makefile head/sys/modules/snp/Makefile Modified: head/share/man/man4/snp.4 ============================================================================== --- head/share/man/man4/snp.4 Wed Nov 5 14:15:53 2008 (r184688) +++ head/share/man/man4/snp.4 Wed Nov 5 15:04:03 2008 (r184689) @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 18, 2005 +.Dd November 5, 2008 .Dt SNP 4 .Os .Sh NAME @@ -77,11 +77,23 @@ The .Nm device first appeared in .Fx 2.1 . +In +.Fx 8.0 +the +.Nm +driver was rewritten to work with the replaced TTY subsystem. .Sh AUTHORS -.An Ugen J.S. Antsilevich Aq ugen@NetVision.net.il +The author of the current implementation is +.An Ed Schouten Aq ed@FreeBSD.org . +Previous versions of +.Nm +were based on code written by +.An Ugen J.S. Antsilevich Aq ugen@NetVision.net.il . .Sh BUGS -Caveat emptor! -This manual page is horribly stale and wildly inaccurate in some places. -.Pp -While in line mode, user input cannot be seen. -No signals may be sent to the observed tty. +This version of +.Nm +does not return proper error codes when calling +.Dv FIONREAD . +It also does not allow +.Dv SNPSTTY +to detach itself from the TTY. Modified: head/sys/conf/NOTES ============================================================================== --- head/sys/conf/NOTES Wed Nov 5 14:15:53 2008 (r184688) +++ head/sys/conf/NOTES Wed Nov 5 15:04:03 2008 (r184689) @@ -1278,6 +1278,7 @@ options SES_ENABLE_PASSTHROUGH device pty #BSD-style compatibility pseudo ttys device nmdm #back-to-back tty devices device md #Memory/malloc disk +device snp #Snoop device - to look at pty/vty/etc.. device ccd #Concatenated disk driver device firmware #firmware(9) support Modified: head/sys/dev/snp/snp.c ============================================================================== --- head/sys/dev/snp/snp.c Wed Nov 5 14:15:53 2008 (r184688) +++ head/sys/dev/snp/snp.c Wed Nov 5 15:04:03 2008 (r184689) @@ -1,638 +1,352 @@ /*- - * Copyright (c) 1995 Ugen J.S.Antsilevich + * Copyright (c) 2008 Ed Schouten + * All rights reserved. * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * Snoop stuff. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include -#include +#include #include #include -#include -#include -#include -#include #include +#include #include -#include +#include #include +#include +#include +#include #include -#include -#include - -static l_close_t snplclose; -static l_write_t snplwrite; -static d_open_t snpopen; -static d_read_t snpread; -static d_write_t snpwrite; -static d_ioctl_t snpioctl; -static d_poll_t snppoll; - -static struct cdevsw snp_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_PSEUDO | D_NEEDGIANT, - .d_open = snpopen, - .d_read = snpread, - .d_write = snpwrite, - .d_ioctl = snpioctl, - .d_poll = snppoll, - .d_name = "snp", -}; -static struct linesw snpdisc = { - .l_open = tty_open, - .l_close = snplclose, - .l_read = ttread, - .l_write = snplwrite, - .l_ioctl = l_nullioctl, - .l_rint = ttyinput, - .l_start = ttstart, - .l_modem = ttymodem -}; +static struct cdev *snp_dev; +/* XXX: should be mtx, but TTY can be locked by Giant. */ +static struct sx snp_register_lock; +SX_SYSINIT(snp_register_lock, &snp_register_lock, + "tty snoop registration"); +static MALLOC_DEFINE(M_SNP, "snp", "tty snoop device"); /* - * This is the main snoop per-device structure. + * There is no need to have a big input buffer. In most typical setups, + * we won't inject much data into the TTY, because users can't type + * really fast. */ -struct snoop { - LIST_ENTRY(snoop) snp_list; /* List glue. */ - struct cdev *snp_target; /* Target tty device. */ - struct tty *snp_tty; /* Target tty pointer. */ - u_long snp_len; /* Possible length. */ - u_long snp_base; /* Data base. */ - u_long snp_blen; /* Used length. */ - caddr_t snp_buf; /* Allocation pointer. */ - int snp_flags; /* Flags. */ - struct selinfo snp_sel; /* Select info. */ - int snp_olddisc; /* Old line discipline. */ -}; - +#define SNP_INPUT_BUFSIZE 16 /* - * Possible flags. + * The output buffer has to be really big. Right now we don't support + * any form of flow control, which means we lost any data we can't + * accept. We set the output buffer size to about twice the size of a + * pseudo-terminal/virtual console's output buffer. */ -#define SNOOP_ASYNC 0x0002 -#define SNOOP_OPEN 0x0004 -#define SNOOP_RWAIT 0x0008 -#define SNOOP_OFLOW 0x0010 -#define SNOOP_DOWN 0x0020 +#define SNP_OUTPUT_BUFSIZE 16384 -/* - * Other constants. - */ -#define SNOOP_MINLEN (4*1024) /* This should be power of 2. - * 4K tested to be the minimum - * for which on normal tty - * usage there is no need to - * allocate more. - */ -#define SNOOP_MAXLEN (64*1024) /* This one also,64K enough - * If we grow more,something - * really bad in this world.. - */ +static d_open_t snp_open; +static d_read_t snp_read; +static d_write_t snp_write; +static d_ioctl_t snp_ioctl; +static d_poll_t snp_poll; -static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data"); -/* - * The number of the "snoop" line discipline. This gets determined at - * module load time. - */ -static int snooplinedisc; -static struct cdev *snoopdev; +static struct cdevsw snp_cdevsw = { + .d_version = D_VERSION, + .d_open = snp_open, + .d_read = snp_read, + .d_write = snp_write, + .d_ioctl = snp_ioctl, + .d_poll = snp_poll, + .d_name = "snp", +}; -static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist); +static th_getc_capture_t snp_getc_capture; -static struct tty *snpdevtotty(struct cdev *dev); -static void snp_detach(void *arg); -static int snp_down(struct snoop *snp); -static int snp_in(struct snoop *snp, char *buf, int n); -static int snp_modevent(module_t mod, int what, void *arg); -static struct snoop *ttytosnp(struct tty *); +static struct ttyhook snp_hook = { + .th_getc_capture = snp_getc_capture, +}; -static struct snoop * -ttytosnp(struct tty *tp) -{ - struct snoop *snp; - - LIST_FOREACH(snp, &snp_sclist, snp_list) { - if (snp->snp_tty == tp) - return (snp); - } - return (NULL); -} +/* + * Per-instance structure. + * + * List of locks + * (r) locked by snp_register_lock on assignment + * (t) locked by tty_lock + */ +struct snp_softc { + struct tty *snp_tty; /* (r) TTY we're snooping. */ + struct ttyoutq snp_outq; /* (t) Output queue. */ + struct cv snp_outwait; /* (t) Output wait queue. */ + struct selinfo snp_outpoll; /* (t) Output polling. */ +}; -static int -snplclose(struct tty *tp, int flag) +static void +snp_dtor(void *data) { - struct snoop *snp; - int error; - - snp = ttytosnp(tp); - error = snp_down(snp); - if (error != 0) - return (error); - error = ttylclose(tp, flag); - return (error); -} + struct snp_softc *ss = data; + struct tty *tp; -static int -snplwrite(struct tty *tp, struct uio *uio, int flag) -{ - struct iovec iov; - struct uio uio2; - struct snoop *snp; - int error, ilen; - char *ibuf; - - error = 0; - ibuf = NULL; - snp = ttytosnp(tp); - while (uio->uio_resid > 0) { - ilen = imin(512, uio->uio_resid); - ibuf = malloc(ilen, M_SNP, M_WAITOK); - error = uiomove(ibuf, ilen, uio); - if (error != 0) - break; - snp_in(snp, ibuf, ilen); - /* Hackish, but probably the least of all evils. */ - iov.iov_base = ibuf; - iov.iov_len = ilen; - uio2.uio_iov = &iov; - uio2.uio_iovcnt = 1; - uio2.uio_offset = 0; - uio2.uio_resid = ilen; - uio2.uio_segflg = UIO_SYSSPACE; - uio2.uio_rw = UIO_WRITE; - uio2.uio_td = uio->uio_td; - error = ttwrite(tp, &uio2, flag); - if (error != 0) - break; - free(ibuf, M_SNP); - ibuf = NULL; + tp = ss->snp_tty; + if (tp != NULL) { + tty_lock(tp); + ttyoutq_free(&ss->snp_outq); + ttyhook_unregister(tp); } - if (ibuf != NULL) - free(ibuf, M_SNP); - return (error); -} - -static struct tty * -snpdevtotty(struct cdev *dev) -{ - struct cdevsw *cdp; - struct tty *tp; - cdp = dev_refthread(dev); - if (cdp == NULL) - return (NULL); - if (!(cdp->d_flags & D_TTY)) - tp = NULL; - else - tp = dev->si_tty; - dev_relthread(dev); - return (tp); + cv_destroy(&ss->snp_outwait); + free(ss, M_SNP); } -#define SNP_INPUT_BUF 5 /* This is even too much, the maximal - * interactive mode write is 3 bytes - * length for function keys... - */ +/* + * Snoop device node routines. + */ static int -snpwrite(struct cdev *dev, struct uio *uio, int flag) +snp_open(struct cdev *dev, int flag, int mode, struct thread *td) { - struct snoop *snp; - struct tty *tp; - int error, i, len; - unsigned char c[SNP_INPUT_BUF]; + struct snp_softc *ss; - error = devfs_get_cdevpriv((void **)&snp); - if (error != 0) - return (error); + /* Allocate per-snoop data. */ + ss = malloc(sizeof(struct snp_softc), M_SNP, M_WAITOK|M_ZERO); + ttyoutq_init(&ss->snp_outq); + cv_init(&ss->snp_outwait, "snp out"); - tp = snp->snp_tty; - if (tp == NULL) - return (EIO); - if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc) - goto tty_input; + devfs_set_cdevpriv(ss, snp_dtor); - printf("snp: attempt to write to bad tty\n"); - return (EIO); - -tty_input: - if (!(tp->t_state & TS_ISOPEN)) - return (EIO); - - while (uio->uio_resid > 0) { - len = imin(uio->uio_resid, SNP_INPUT_BUF); - if ((error = uiomove(c, len, uio)) != 0) - return (error); - for (i=0; i < len; i++) { - if (ttyinput(c[i], tp)) - return (EIO); - } - } return (0); } - static int -snpread(struct cdev *dev, struct uio *uio, int flag) +snp_read(struct cdev *dev, struct uio *uio, int flag) { - struct snoop *snp; - int error, len, n, nblen, s; - caddr_t from; - char *nbuf; + int error, oresid = uio->uio_resid; + struct snp_softc *ss; + struct tty *tp; + + if (uio->uio_resid == 0) + return (0); - error = devfs_get_cdevpriv((void **)&snp); + error = devfs_get_cdevpriv((void **)&ss); if (error != 0) return (error); - - KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen, - ("snoop buffer error")); - - if (snp->snp_tty == NULL) + + tp = ss->snp_tty; + if (tp == NULL || tty_gone(tp)) return (EIO); - snp->snp_flags &= ~SNOOP_RWAIT; + tty_lock(tp); + for (;;) { + error = ttyoutq_read_uio(&ss->snp_outq, tp, uio); + if (error != 0 || uio->uio_resid != oresid) + break; - do { - if (snp->snp_len == 0) { - if (flag & O_NONBLOCK) - return (EWOULDBLOCK); - snp->snp_flags |= SNOOP_RWAIT; - error = tsleep(snp, (PZERO + 1) | PCATCH, - "snprd", 0); - if (error != 0) - return (error); + /* Wait for more data. */ + if (flag & O_NONBLOCK) { + error = EWOULDBLOCK; + break; } - } while (snp->snp_len == 0); - - n = snp->snp_len; - - error = 0; - while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { - len = min((unsigned)uio->uio_resid, snp->snp_len); - from = (caddr_t)(snp->snp_buf + snp->snp_base); - if (len == 0) + error = cv_wait_sig(&ss->snp_outwait, tp->t_mtx); + if (error != 0) + break; + if (tty_gone(tp)) { + error = EIO; break; - - error = uiomove(from, len, uio); - snp->snp_base += len; - snp->snp_len -= len; - } - if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) { - snp->snp_flags &= ~SNOOP_OFLOW; - } - s = spltty(); - nblen = snp->snp_blen; - if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) { - while (nblen / 2 >= snp->snp_len && nblen / 2 >= SNOOP_MINLEN) - nblen = nblen / 2; - if ((nbuf = malloc(nblen, M_SNP, M_NOWAIT)) != NULL) { - bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); - free(snp->snp_buf, M_SNP); - snp->snp_buf = nbuf; - snp->snp_blen = nblen; - snp->snp_base = 0; } } - splx(s); + tty_unlock(tp); return (error); } static int -snp_in(struct snoop *snp, char *buf, int n) +snp_write(struct cdev *dev, struct uio *uio, int flag) { - int s_free, s_tail; - int s, len, nblen; - caddr_t from, to; - char *nbuf; + struct snp_softc *ss; + struct tty *tp; + int error, len, i; + char in[SNP_INPUT_BUFSIZE]; + + error = devfs_get_cdevpriv((void **)&ss); + if (error != 0) + return (error); + + tp = ss->snp_tty; + if (tp == NULL || tty_gone(tp)) + return (EIO); - KASSERT(n >= 0, ("negative snoop char count")); + while (uio->uio_resid > 0) { + /* Read new data. */ + len = imin(uio->uio_resid, sizeof in); + error = uiomove(in, len, uio); + if (error != 0) + return (error); - if (n == 0) - return (0); + tty_lock(tp); - if (snp->snp_flags & SNOOP_DOWN) { - printf("snp: more data to down interface\n"); - return (0); - } + /* Driver could have abandoned the TTY in the mean time. */ + if (tty_gone(tp)) { + tty_unlock(tp); + return (ENXIO); + } - if (snp->snp_flags & SNOOP_OFLOW) { - printf("snp: buffer overflow\n"); /* - * On overflow we just repeat the standart close - * procedure...yes , this is waste of space but.. Then next - * read from device will fail if one would recall he is - * snooping and retry... + * Deliver data to the TTY. Ignore errors for now, + * because we shouldn't bail out when we're running + * close to the watermarks. */ - - return (snp_down(snp)); - } - s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base); - s_free = snp->snp_blen - snp->snp_len; - - - if (n > s_free) { - s = spltty(); - nblen = snp->snp_blen; - while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) { - nblen = snp->snp_blen * 2; - s_free = nblen - (snp->snp_len + snp->snp_base); - } - if ((n <= s_free) && (nbuf = malloc(nblen, M_SNP, M_NOWAIT))) { - bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); - free(snp->snp_buf, M_SNP); - snp->snp_buf = nbuf; - snp->snp_blen = nblen; - snp->snp_base = 0; + if (ttydisc_can_bypass(tp)) { + ttydisc_rint_bypass(tp, in, len); } else { - snp->snp_flags |= SNOOP_OFLOW; - if (snp->snp_flags & SNOOP_RWAIT) { - snp->snp_flags &= ~SNOOP_RWAIT; - wakeup(snp); - } - splx(s); - return (0); + for (i = 0; i < len; i++) + ttydisc_rint(tp, in[i], 0); } - splx(s); - } - if (n > s_tail) { - from = (caddr_t)(snp->snp_buf + snp->snp_base); - to = (caddr_t)(snp->snp_buf); - len = snp->snp_len; - bcopy(from, to, len); - snp->snp_base = 0; - } - to = (caddr_t)(snp->snp_buf + snp->snp_base + snp->snp_len); - bcopy(buf, to, n); - snp->snp_len += n; - - if (snp->snp_flags & SNOOP_RWAIT) { - snp->snp_flags &= ~SNOOP_RWAIT; - wakeup(snp); - } - selwakeuppri(&snp->snp_sel, PZERO + 1); - - return (n); -} - -static void -snp_dtor(void *data) -{ - struct snoop *snp = data; - - snp->snp_blen = 0; - LIST_REMOVE(snp, snp_list); - free(snp->snp_buf, M_SNP); - snp->snp_flags &= ~SNOOP_OPEN; - snp_detach(snp); -} - -static int -snpopen(struct cdev *dev, int flag, int mode, struct thread *td) -{ - struct snoop *snp; - int error; - - snp = malloc(sizeof(*snp), M_SNP, M_WAITOK | M_ZERO); - error = devfs_set_cdevpriv(snp, snp_dtor); - if (error != 0) { - free(snp, M_SNP); - return (error); - } - - /* - * We intentionally do not OR flags with SNOOP_OPEN, but set them so - * all previous settings (especially SNOOP_OFLOW) will be cleared. - */ - snp->snp_flags = SNOOP_OPEN; - - snp->snp_buf = malloc(SNOOP_MINLEN, M_SNP, M_WAITOK); - snp->snp_blen = SNOOP_MINLEN; - snp->snp_base = 0; - snp->snp_len = 0; - - /* - * snp_tty == NULL is for inactive snoop devices. - */ - snp->snp_tty = NULL; - snp->snp_target = NULL; - - LIST_INSERT_HEAD(&snp_sclist, snp, snp_list); - return (0); -} - - -static void -snp_detach(void *arg) -{ - struct snoop *snp; - struct tty *tp; - - snp = (struct snoop *)arg; - snp->snp_base = 0; - snp->snp_len = 0; - - /* - * If line disc. changed we do not touch this pointer, SLIP/PPP will - * change it anyway. - */ - tp = snp->snp_tty; - if (tp == NULL) - goto detach_notty; - - if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc) { - tp->t_state &= ~TS_SNOOP; - tp->t_line = snp->snp_olddisc; - } else - printf("snp: bad attached tty data\n"); - - snp->snp_tty = NULL; - snp->snp_target = NULL; - -detach_notty: - selwakeuppri(&snp->snp_sel, PZERO + 1); - if ((snp->snp_flags & SNOOP_OPEN) == 0) - free(snp, M_SNP); -} - -static int -snp_down(struct snoop *snp) -{ - if (snp->snp_blen != SNOOP_MINLEN) { - free(snp->snp_buf, M_SNP); - snp->snp_buf = malloc(SNOOP_MINLEN, M_SNP, M_WAITOK); - snp->snp_blen = SNOOP_MINLEN; + ttydisc_rint_done(tp); + tty_unlock(tp); } - snp->snp_flags |= SNOOP_DOWN; - snp_detach(snp); return (0); } static int -snpioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, +snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { - struct snoop *snp; + struct snp_softc *ss; struct tty *tp; - struct cdev *tdev; - struct file *fp; - int error, s; + int error; - error = devfs_get_cdevpriv((void **)&snp); + error = devfs_get_cdevpriv((void **)&ss); if (error != 0) return (error); switch (cmd) { case SNPSTTY: - s = *(int *)data; - if (s < 0) - return (snp_down(snp)); - - if (fget(td, s, &fp) != 0) - return (EINVAL); - if (fp->f_type != DTYPE_VNODE || - fp->f_vnode->v_type != VCHR || - fp->f_vnode->v_rdev == NULL) { - fdrop(fp, td); - return (EINVAL); - } - tdev = fp->f_vnode->v_rdev; - fdrop(fp, td); - - if (snp->snp_tty != NULL) - return (EBUSY); - - tp = snpdevtotty(tdev); - if (!tp) - return (EINVAL); - if (tp->t_state & TS_SNOOP) + /* Bind TTY to snoop instance. */ + sx_xlock(&snp_register_lock); + if (ss->snp_tty != NULL) { + sx_xunlock(&snp_register_lock); return (EBUSY); + } + error = ttyhook_register(&ss->snp_tty, td, *(int *)data, + &snp_hook, ss); + sx_xunlock(&snp_register_lock); + if (error != 0) + return (error); - s = spltty(); - tp->t_state |= TS_SNOOP; - snp->snp_olddisc = tp->t_line; - tp->t_line = snooplinedisc; - snp->snp_tty = tp; - snp->snp_target = tdev; - - /* - * Clean overflow and down flags - - * we'll have a chance to get them in the future :))) - */ - snp->snp_flags &= ~SNOOP_OFLOW; - snp->snp_flags &= ~SNOOP_DOWN; - splx(s); - break; + /* Now that went okay, allocate a buffer for the queue. */ + tp = ss->snp_tty; + tty_lock(tp); + ttyoutq_setsize(&ss->snp_outq, tp, SNP_OUTPUT_BUFSIZE); + tty_unlock(tp); + return (0); case SNPGTTY: - /* - * We keep snp_target field specially to make - * SNPGTTY happy, else we can't know what is device - * major/minor for tty. - */ - *((dev_t *)data) = dev2udev(snp->snp_target); - break; - - case FIONBIO: - break; - - case FIOASYNC: - if (*(int *)data) - snp->snp_flags |= SNOOP_ASYNC; + /* Obtain device number of associated TTY. */ + if (ss->snp_tty == NULL) + *(dev_t *)data = NODEV; else - snp->snp_flags &= ~SNOOP_ASYNC; - break; - + *(dev_t *)data = tty_udev(ss->snp_tty); + return (0); case FIONREAD: - s = spltty(); - if (snp->snp_tty != NULL) - *(int *)data = snp->snp_len; - else - if (snp->snp_flags & SNOOP_DOWN) { - if (snp->snp_flags & SNOOP_OFLOW) - *(int *)data = SNP_OFLOW; - else - *(int *)data = SNP_TTYCLOSE; - } else { - *(int *)data = SNP_DETACH; - } - splx(s); - break; - + tp = ss->snp_tty; + if (tp != NULL) { + tty_lock(tp); + *(int *)data = ttyoutq_bytesused(&ss->snp_outq); + tty_unlock(tp); + } else { + *(int *)data = 0; + } + return (0); default: return (ENOTTY); } - return (0); } static int -snppoll(struct cdev *dev, int events, struct thread *td) +snp_poll(struct cdev *dev, int events, struct thread *td) { - struct snoop *snp; + struct snp_softc *ss; + struct tty *tp; int revents; - if (devfs_get_cdevpriv((void **)&snp) != 0) + if (devfs_get_cdevpriv((void **)&ss) != 0) return (events & (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); revents = 0; - /* - * If snoop is down, we don't want to poll() forever so we return 1. - * Caller should see if we down via FIONREAD ioctl(). The last should - * return -1 to indicate down state. - */ + if (events & (POLLIN | POLLRDNORM)) { - if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0) - revents |= events & (POLLIN | POLLRDNORM); - else - selrecord(td, &snp->snp_sel); + tp = ss->snp_tty; + if (tp != NULL) { + tty_lock(tp); + if (ttyoutq_bytesused(&ss->snp_outq) > 0) + revents |= events & (POLLIN | POLLRDNORM); + tty_unlock(tp); + } } + + if (revents == 0) + selrecord(td, &ss->snp_outpoll); + return (revents); } +/* + * TTY hook events. + */ + static int snp_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: - snooplinedisc = ldisc_register(LDISC_LOAD, &snpdisc); - snoopdev = make_dev(&snp_cdevsw, 0, UID_ROOT, GID_WHEEL, - 0600, "snp"); - /* For compatibility */ - make_dev_alias(snoopdev, "snp0"); - break; + snp_dev = make_dev(&snp_cdevsw, 0, + UID_ROOT, GID_WHEEL, 0600, "snp"); + return (0); case MOD_UNLOAD: - if (!LIST_EMPTY(&snp_sclist)) - return (EBUSY); - destroy_dev(snoopdev); - ldisc_deregister(snooplinedisc); - break; + /* XXX: Make existing users leave. */ + destroy_dev(snp_dev); + return (0); default: return (EOPNOTSUPP); - break; } - return (0); +} + +static void +snp_getc_capture(struct tty *tp, const void *buf, size_t len) +{ + struct snp_softc *ss = ttyhook_softc(tp); + + ttyoutq_write(&ss->snp_outq, buf, len); + + cv_broadcast(&ss->snp_outwait); + selwakeup(&ss->snp_outpoll); } static moduledata_t snp_mod = { - "snp", - snp_modevent, - NULL + "snp", + snp_modevent, + NULL }; + DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); Modified: head/sys/modules/Makefile ============================================================================== --- head/sys/modules/Makefile Wed Nov 5 14:15:53 2008 (r184688) +++ head/sys/modules/Makefile Wed Nov 5 15:04:03 2008 (r184689) @@ -252,6 +252,7 @@ SUBDIR= ${_3dfx} \ ${_smbfs} \ sn \ ${_snc} \ + snp \ ${_sound} \ ${_speaker} \ ${_splash} \ Modified: head/sys/modules/snp/Makefile ============================================================================== --- head/sys/modules/snp/Makefile Wed Nov 5 14:15:53 2008 (r184688) +++ head/sys/modules/snp/Makefile Wed Nov 5 15:04:03 2008 (r184689) @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../dev/snp KMOD= snp -SRCS= snp.c vnode_if.h +SRCS= snp.c .include