Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Sep 2008 18:47:59 +0200
From:      Ed Schouten <ed@80386.nl>
To:        FreeBSD Current <freebsd-current@freebsd.org>
Cc:        Giorgos Keramidas <keramida@ceid.upatras.gr>
Subject:   CFT: pts(4) "packet mode" support
Message-ID:  <20080902164759.GL99951@hoeg.nl>
In-Reply-To: <87fxot5hoi.fsf@kobe.laptop>
References:  <87fxot5hoi.fsf@kobe.laptop>

next in thread | previous in thread | raw e-mail | index | archive | help

--Zek6ooiun86DS3+c
Content-Type: multipart/mixed; boundary="kn2F/kOnIYRmW7Hu"
Content-Disposition: inline


--kn2F/kOnIYRmW7Hu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hello everyone,

One of the things I couldn't fix in time for the MPSAFE TTY import, was
pts(4) packet mode. Because people have noticed it was missing, I
decided to implement it, for inclusion in the SVN tree. ;-)

Giorgos and I have already tried the attached patch, but it would be
nice if others could test it as well. I'm planning to integrate this
patch by the end of the week.

Any feedback? Comments? Obscure panics?

--=20
 Ed Schouten <ed@80386.nl>
 WWW: http://80386.nl/

--kn2F/kOnIYRmW7Hu
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="packet-mode.diff"
Content-Transfer-Encoding: quoted-printable

Index: share/man/man4/pts.4
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- share/man/man4/pts.4	(revision 182681)
+++ share/man/man4/pts.4	(working copy)
@@ -173,9 +173,3 @@
 it was replaced with the
 .Nm
 driver.
-.Sh BUGS
-Packet mode has not been properly implemented in this version of
-.Fx .
-When enabled, it will always prepend
-.Dv TIOCPKT_DATA ,
-even if other events have been triggered.
Index: sys/kern/tty_pts.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/kern/tty_pts.c	(revision 182681)
+++ sys/kern/tty_pts.c	(working copy)
@@ -82,6 +82,7 @@
 	int		pts_unit;	/* (c) Device unit number. */
 	unsigned int	pts_flags;	/* (t) Device flags. */
 #define PTS_PKT		0x1	/* Packet mode. */
+	char		pts_pkt;	/* (t) Unread packet mode data. */
=20
 	struct cv	pts_inwait;	/* (t) Blocking write() on master. */
 	struct selinfo	pts_inpoll;	/* (t) Select queue for write(). */
@@ -105,34 +106,54 @@
 {
 	struct tty *tp =3D fp->f_data;
 	struct pts_softc *psc =3D tty_softc(tp);
-	int error, oresid;
+	int error =3D 0;
+	char pkt;
=20
 	if (uio->uio_resid =3D=3D 0)
 		return (0);
-=09
-	/*
-	 * Implement packet mode. When packet mode is turned on, the
-	 * first byte contains a bitmask of events that occured (start,
-	 * stop, flush, window size, etc).
-	 */
=20
-	if (psc->pts_flags & PTS_PKT) {
-		/* XXX: return proper bits. */
-		error =3D ureadc(0, uio);
-		if (error !=3D 0)
+	tty_lock(tp);
+
+	for (;;) {
+		/*
+		 * Implement packet mode. When packet mode is turned on,
+		 * the first byte contains a bitmask of events that
+		 * occured (start, stop, flush, window size, etc).
+		 */
+		if (psc->pts_flags & PTS_PKT && psc->pts_pkt) {
+			pkt =3D psc->pts_pkt;
+			psc->pts_pkt =3D 0;
+			tty_unlock(tp);
+
+			error =3D ureadc(pkt, uio);
 			return (error);
-		if (uio->uio_resid =3D=3D 0)
-			return (0);
-	}
+		}
=20
-	oresid =3D uio->uio_resid;
+		/*
+		 * Transmit regular data.
+		 *
+		 * XXX: We shouldn't use ttydisc_getc_poll()! Even
+		 * though in this implementation, there is likely going
+		 * to be data, we should just call ttydisc_getc_uio()
+		 * and use its return value to sleep.
+		 */
+		if (ttydisc_getc_poll(tp)) {
+			if (psc->pts_flags & PTS_PKT) {
+				/*
+				 * XXX: Small race. Fortunately PTY
+				 * consumers aren't multithreaded.
+				 */
=20
-	tty_lock(tp);
-	for (;;) {
-		error =3D ttydisc_getc_uio(tp, uio);
-		/* We've got data (or an error). */
-		if (error !=3D 0 || uio->uio_resid !=3D oresid)
+				tty_unlock(tp);
+				error =3D ureadc(TIOCPKT_DATA, uio);
+				if (error)
+					return (error);
+				tty_lock(tp);
+			}
+
+			error =3D ttydisc_getc_uio(tp, uio);
 			break;
+		}
=20
 		/* Maybe the device isn't used anyway. */
 		if (tty_opened(tp) =3D=3D 0)
@@ -147,6 +168,7 @@
 		if (error !=3D 0)
 			break;
 	}
+
 	tty_unlock(tp);
=20
 	return (error);
@@ -162,14 +184,14 @@
 	size_t iblen, rintlen;
 	int error =3D 0;
=20
-	tty_lock(tp);
+	if (uio->uio_resid =3D=3D 0)
+		return (0);
=20
-	while (uio->uio_resid > 0) {
-		/* Temporarily unlock to buffer new characters. */
-		tty_unlock(tp);
+	for (;;) {
 		ibstart =3D ib;
 		iblen =3D MIN(uio->uio_resid, sizeof ib);
 		error =3D uiomove(ib, iblen, uio);
+
 		tty_lock(tp);
 		if (error !=3D 0)
 			goto done;
@@ -178,7 +200,8 @@
 		 * When possible, avoid the slow path. rint_bypass()
 		 * copies all input to the input queue at once.
 		 */
-		while (iblen > 0) {
+		MPASS(iblen > 0);
+		do {
 			if (ttydisc_can_bypass(tp)) {
 				/* Store data at once. */
 				rintlen =3D ttydisc_rint_bypass(tp,
@@ -188,7 +211,7 @@
=20
 				if (iblen =3D=3D 0) {
 					/* All data written. */
-					continue;
+					break;
 				}
 			} else {
 				error =3D ttydisc_rint(tp, *ibstart, 0);
@@ -217,7 +240,11 @@
 			error =3D cv_wait_sig(&psc->pts_inwait, tp->t_mtx);
 			if (error !=3D 0)
 				goto done;
-		}
+		} while (iblen > 0);
+
+		if (uio->uio_resid =3D=3D 0)
+			break;
+		tty_unlock(tp);
 	}
=20
 done:	ttydisc_rint_done(tp);
@@ -362,7 +389,8 @@
=20
 	if (events & (POLLIN|POLLRDNORM)) {
 		/* See if we can getc something. */
-		if (ttydisc_getc_poll(tp))
+		if (ttydisc_getc_poll(tp) ||
+		    (psc->pts_flags & PTS_PKT && psc->pts_pkt))
 			revents |=3D events & (POLLIN|POLLRDNORM);
 	}
 	if (events & (POLLOUT|POLLWRNORM)) {
@@ -481,6 +509,34 @@
 }
=20
 static void
+ptsdrv_pktnotify(struct tty *tp, char event)
+{
+	struct pts_softc *psc =3D tty_softc(tp);
+
+	/*
+	 * Clear conflicting flags.
+	 */
+
+	switch (event) {
+	case TIOCPKT_STOP:
+		psc->pts_pkt &=3D ~TIOCPKT_START;
+		break;
+	case TIOCPKT_START:
+		psc->pts_pkt &=3D ~TIOCPKT_STOP;
+		break;
+	case TIOCPKT_NOSTOP:
+		psc->pts_pkt &=3D ~TIOCPKT_DOSTOP;
+		break;
+	case TIOCPKT_DOSTOP:
+		psc->pts_pkt &=3D ~TIOCPKT_NOSTOP;
+		break;
+	}
+
+	psc->pts_pkt |=3D event;
+	ptsdrv_outwakeup(tp);
+}
+
+static void
 ptsdrv_free(void *softc)
 {
 	struct pts_softc *psc =3D softc;
@@ -506,6 +562,7 @@
 	.tsw_outwakeup	=3D ptsdrv_outwakeup,
 	.tsw_inwakeup	=3D ptsdrv_inwakeup,
 	.tsw_close	=3D ptsdrv_close,
+	.tsw_pktnotify	=3D ptsdrv_pktnotify,
 	.tsw_free	=3D ptsdrv_free,
 };
=20
Index: sys/kern/tty.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/kern/tty.c	(revision 182681)
+++ sys/kern/tty.c	(working copy)
@@ -816,6 +816,11 @@
 }
=20
 static void
+ttydevsw_defpktnotify(struct tty *tp, char event)
+{
+}
+
+static void
 ttydevsw_deffree(void *softc)
 {
=20
@@ -846,6 +851,7 @@
 	PATCH_FUNC(param);
 	PATCH_FUNC(modem);
 	PATCH_FUNC(mmap);
+	PATCH_FUNC(pktnotify);
 	PATCH_FUNC(free);
 #undef PATCH_FUNC
=20
@@ -1226,11 +1232,13 @@
 		tp->t_flags &=3D ~TF_HIWAT_OUT;
 		ttyoutq_flush(&tp->t_outq);
 		tty_wakeup(tp, FWRITE);
+		ttydevsw_pktnotify(tp, TIOCPKT_FLUSHWRITE);
 	}
 	if (flags & FREAD) {
 		tty_hiwat_in_unblock(tp);
 		ttyinq_flush(&tp->t_inq);
 		ttydevsw_inwakeup(tp);
+		ttydevsw_pktnotify(tp, TIOCPKT_FLUSHREAD);
 	}
 }
=20
@@ -1372,6 +1380,17 @@
 			ttyinq_canonicalize(&tp->t_inq);
 			tty_wakeup(tp, FREAD);
 		}
+
+		/*
+		 * For packet mode: notify the PTY consumer that VSTOP
+		 * and VSTART may have been changed.
+		 */
+		if (tp->t_termios.c_iflag & IXON &&
+		    tp->t_termios.c_cc[VSTOP] =3D=3D CTRL('S') &&
+		    tp->t_termios.c_cc[VSTART] =3D=3D CTRL('Q'))
+			ttydevsw_pktnotify(tp, TIOCPKT_DOSTOP);
+		else
+			ttydevsw_pktnotify(tp, TIOCPKT_NOSTOP);
 		return (0);
 	}
 	case TIOCGETD:
@@ -1562,10 +1581,12 @@
 		return (0);
 	case TIOCSTOP:
 		tp->t_flags |=3D TF_STOPPED;
+		ttydevsw_pktnotify(tp, TIOCPKT_STOP);
 		return (0);
 	case TIOCSTART:
 		tp->t_flags &=3D ~TF_STOPPED;
 		ttydevsw_outwakeup(tp);
+		ttydevsw_pktnotify(tp, TIOCPKT_START);
 		return (0);
 	case TIOCSTAT:
 		tty_info(tp);
Index: sys/sys/ttydevsw.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/sys/ttydevsw.h	(revision 182681)
+++ sys/sys/ttydevsw.h	(working copy)
@@ -48,6 +48,7 @@
 typedef int tsw_param_t(struct tty *, struct termios *);
 typedef int tsw_modem_t(struct tty *, int, int);
 typedef int tsw_mmap_t(struct tty *, vm_offset_t, vm_paddr_t *, int);
+typedef void tsw_pktnotify_t(struct tty *, char);
 typedef void tsw_free_t(void *);
=20
 struct ttydevsw {
@@ -64,6 +65,7 @@
 	tsw_modem_t	*tsw_modem;	/* Modem sigon/sigoff. */
=20
 	tsw_mmap_t	*tsw_mmap;	/* mmap() hooks. */
+	tsw_pktnotify_t	*tsw_pktnotify;	/* TIOCPKT events. */
=20
 	tsw_free_t	*tsw_free;	/* Destructor. */
 };
@@ -148,6 +150,15 @@
 }
=20
 static __inline void
+ttydevsw_pktnotify(struct tty *tp, char event)
+{
+	tty_lock_assert(tp, MA_OWNED);
+	MPASS(!tty_gone(tp));
+
+	tp->t_devsw->tsw_pktnotify(tp, event);
+}
+
+static __inline void
 ttydevsw_free(struct tty *tp)
 {
 	MPASS(tty_gone(tp));

--kn2F/kOnIYRmW7Hu--

--Zek6ooiun86DS3+c
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (FreeBSD)

iEYEARECAAYFAki9bj8ACgkQ52SDGA2eCwUk3ACfTRsZXw8t/JdsJq/jFTKyDdoU
2AQAn3jd9jREmvDmuIxyH/rdA9Wnthy3
=rjaz
-----END PGP SIGNATURE-----

--Zek6ooiun86DS3+c--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080902164759.GL99951>