pty.c revision 130585
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 4. Neither the name of the University nor the names of its contributors
141541Srgrimes *    may be used to endorse or promote products derived from this software
151541Srgrimes *    without specific prior written permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
291541Srgrimes *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
301541Srgrimes */
311541Srgrimes
321541Srgrimes#include <sys/cdefs.h>
331541Srgrimes__FBSDID("$FreeBSD: head/sys/kern/tty_pty.c 130585 2004-06-16 09:47:26Z phk $");
3412731Sbde
351541Srgrimes/*
361541Srgrimes * Pseudo-teletype Driver
371541Srgrimes * (Actually two drivers, requiring two entries in 'cdevsw')
381541Srgrimes */
391541Srgrimes#include "opt_compat.h"
401541Srgrimes#include "opt_tty.h"
411541Srgrimes#include <sys/param.h>
421541Srgrimes#include <sys/systm.h>
431541Srgrimes#include <sys/lock.h>
441541Srgrimes#include <sys/mutex.h>
451541Srgrimes#include <sys/sx.h>
461541Srgrimes#if defined(COMPAT_43)
471541Srgrimes#include <sys/ioctl_compat.h>
481541Srgrimes#endif
491541Srgrimes#include <sys/proc.h>
501541Srgrimes#include <sys/tty.h>
511541Srgrimes#include <sys/conf.h>
521541Srgrimes#include <sys/fcntl.h>
533308Sphk#include <sys/poll.h>
541541Srgrimes#include <sys/kernel.h>
5512517Sjulian#include <sys/vnode.h>
5612517Sjulian#include <sys/signalvar.h>
5712517Sjulian#include <sys/malloc.h>
5812517Sjulian
5911789Sbdestatic MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
6011789Sbde
6111789Sbdestatic void ptsstart(struct tty *tp);
6211789Sbdestatic void ptsstop(struct tty *tp, int rw);
6312675Sjulianstatic void ptcwakeup(struct tty *tp, int flag);
6412675Sjulianstatic struct cdev *ptyinit(struct cdev *cdev);
6512675Sjulian
6612675Sjulianstatic	d_open_t	ptsopen;
6712675Sjulianstatic	d_close_t	ptsclose;
6812675Sjulianstatic	d_read_t	ptsread;
6912731Sbdestatic	d_write_t	ptswrite;
7012675Sjulianstatic	d_ioctl_t	ptyioctl;
7112675Sjulianstatic	d_open_t	ptcopen;
7212675Sjulianstatic	d_close_t	ptcclose;
7312675Sjulianstatic	d_read_t	ptcread;
7412675Sjulianstatic	d_write_t	ptcwrite;
7512675Sjulianstatic	d_poll_t	ptcpoll;
7612675Sjulian
7712675Sjulian#define	CDEV_MAJOR_S	5
7812675Sjulianstatic struct cdevsw pts_cdevsw = {
7912678Sphk	.d_version =	D_VERSION,
8012675Sjulian	.d_open =	ptsopen,
8112675Sjulian	.d_close =	ptsclose,
8212675Sjulian	.d_read =	ptsread,
8312675Sjulian	.d_write =	ptswrite,
8412678Sphk	.d_ioctl =	ptyioctl,
8512675Sjulian	.d_name =	"pts",
8612675Sjulian	.d_maj =	CDEV_MAJOR_S,
8712675Sjulian	.d_flags =	D_TTY | D_NEEDGIANT,
8812675Sjulian};
8912675Sjulian
901541Srgrimes#define	CDEV_MAJOR_C	6
911541Srgrimesstatic struct cdevsw ptc_cdevsw = {
921541Srgrimes	.d_version =	D_VERSION,
931541Srgrimes	.d_open =	ptcopen,
941541Srgrimes	.d_close =	ptcclose,
951541Srgrimes	.d_read =	ptcread,
961541Srgrimes	.d_write =	ptcwrite,
971541Srgrimes	.d_ioctl =	ptyioctl,
9812564Sjulian	.d_poll =	ptcpoll,
9912564Sjulian	.d_name =	"ptc",
1001541Srgrimes	.d_maj =	CDEV_MAJOR_C,
1011541Srgrimes	.d_flags =	D_TTY | D_NEEDGIANT,
1021541Srgrimes};
1031541Srgrimes
1041541Srgrimes#define BUFSIZ 100		/* Chunk size iomoved to/from user */
1051541Srgrimes
1061541Srgrimesstruct	ptsc {
1071541Srgrimes	int	pt_flags;
1081541Srgrimes	struct	selinfo pt_selr, pt_selw;
1091541Srgrimes	u_char	pt_send;
1101541Srgrimes	u_char	pt_ucntl;
1111541Srgrimes	struct tty *pt_tty;
1121541Srgrimes	struct cdev *devs, *devc;
1131541Srgrimes	struct	prison *pt_prison;
1141541Srgrimes};
1151541Srgrimes
1161541Srgrimes#define	PF_PKT		0x08		/* packet mode */
1171541Srgrimes#define	PF_STOPPED	0x10		/* user told stopped */
1181541Srgrimes#define	PF_REMOTE	0x20		/* remote and flow controlled input */
1191541Srgrimes#define	PF_NOSTOP	0x40
1201541Srgrimes#define PF_UCNTL	0x80		/* user control mode */
1211541Srgrimes
1221541Srgrimes#define	TSA_PTC_READ(tp)	((void *)&(tp)->t_outq.c_cf)
1231541Srgrimes#define	TSA_PTC_WRITE(tp)	((void *)&(tp)->t_rawq.c_cl)
1241541Srgrimes#define	TSA_PTS_READ(tp)	((void *)&(tp)->t_canq)
1251541Srgrimes
1261541Srgrimesstatic char *names = "pqrsPQRS";
1271541Srgrimes/*
1281541Srgrimes * This function creates and initializes a pts/ptc pair
1291541Srgrimes *
1301541Srgrimes * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
1311541Srgrimes * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
1321541Srgrimes *
1331541Srgrimes * XXX: define and add mapping of upper minor bits to allow more
1341541Srgrimes *      than 256 ptys.
1351541Srgrimes */
1361541Srgrimesstatic struct cdev *
1371541Srgrimesptyinit(struct cdev *devc)
1381541Srgrimes{
1391541Srgrimes	struct cdev *devs;
1401541Srgrimes	struct ptsc *pt;
1411541Srgrimes	int n;
1421541Srgrimes
1431541Srgrimes	n = minor(devc);
14412675Sjulian	/* For now we only map the lower 8 bits of the minor */
1451541Srgrimes	if (n & ~0xff)
1461541Srgrimes		return (NODEV);
1471541Srgrimes
1481541Srgrimes	devc->si_flags &= ~SI_CHEAPCLONE;
1491541Srgrimes
1501541Srgrimes	pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
1511541Srgrimes	pt->devs = devs = make_dev(&pts_cdevsw, n,
1521541Srgrimes	    UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32);
1531541Srgrimes	pt->devc = devc;
1541541Srgrimes
1551541Srgrimes	pt->pt_tty = ttymalloc(pt->pt_tty);
1561541Srgrimes	devs->si_drv1 = devc->si_drv1 = pt;
1571541Srgrimes	devs->si_tty = devc->si_tty = pt->pt_tty;
1581541Srgrimes	pt->pt_tty->t_dev = devs;
1591541Srgrimes	return (devc);
1601541Srgrimes}
1611541Srgrimes
1621541Srgrimes/*ARGSUSED*/
1631541Srgrimesstatic	int
1641541Srgrimesptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
1651541Srgrimes{
1661541Srgrimes	struct tty *tp;
1679824Sbde	int error;
1681541Srgrimes	struct ptsc *pt;
1691541Srgrimes
1701541Srgrimes	if (!dev->si_drv1)
1719639Sbde		return(ENXIO);
1729624Sbde	pt = dev->si_drv1;
1733308Sphk	tp = dev->si_tty;
1741541Srgrimes	if ((tp->t_state & TS_ISOPEN) == 0) {
1751541Srgrimes		ttychars(tp);		/* Set up default chars */
1761541Srgrimes		tp->t_iflag = TTYDEF_IFLAG;
1777724Sache		tp->t_oflag = TTYDEF_OFLAG;
1787724Sache		tp->t_lflag = TTYDEF_LFLAG;
1791541Srgrimes		tp->t_cflag = TTYDEF_CFLAG;
1801541Srgrimes		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
1811541Srgrimes	} else if (tp->t_state & TS_XCLUDE && suser(td))
18212675Sjulian		return (EBUSY);
1831541Srgrimes	else if (pt->pt_prison != td->td_ucred->cr_prison)
1841541Srgrimes		return (EBUSY);
1851541Srgrimes	if (tp->t_oproc)			/* Ctrlr still around. */
1861541Srgrimes		(void)ttyld_modem(tp, 1);
1871541Srgrimes	while ((tp->t_state & TS_CARR_ON) == 0) {
1881541Srgrimes		if (flag&FNONBLOCK)
1891541Srgrimes			break;
1901541Srgrimes		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
1911541Srgrimes				 "ptsopn", 0);
1921541Srgrimes		if (error)
1937730Sache			return (error);
1947724Sache	}
1951541Srgrimes	error = ttyld_open(tp, dev);
1961541Srgrimes	if (error == 0)
1971541Srgrimes		ptcwakeup(tp, FREAD|FWRITE);
19812675Sjulian	return (error);
1991541Srgrimes}
2001541Srgrimes
2011541Srgrimesstatic	int
2021541Srgrimesptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
2031541Srgrimes{
2041541Srgrimes	struct tty *tp;
2051541Srgrimes	int err;
2061541Srgrimes
2071541Srgrimes	tp = dev->si_tty;
2081541Srgrimes	err = ttyld_close(tp, flag);
2091541Srgrimes	(void) ttyclose(tp);
2101541Srgrimes	return (err);
2111541Srgrimes}
2121541Srgrimes
2131541Srgrimesstatic	int
2141541Srgrimesptsread(struct cdev *dev, struct uio *uio, int flag)
2151541Srgrimes{
2161541Srgrimes	struct thread *td = curthread;
2171541Srgrimes	struct proc *p = td->td_proc;
2189624Sbde	struct tty *tp = dev->si_tty;
2199624Sbde	struct ptsc *pt = dev->si_drv1;
2203308Sphk	struct pgrp *pg;
2211541Srgrimes	int error = 0;
2221541Srgrimes
2231541Srgrimesagain:
2241541Srgrimes	if (pt->pt_flags & PF_REMOTE) {
2251541Srgrimes		while (isbackground(p, tp)) {
2269639Sbde			sx_slock(&proctree_lock);
2279624Sbde			PROC_LOCK(p);
2283308Sphk			if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) ||
2291541Srgrimes			    SIGISMEMBER(td->td_sigmask, SIGTTIN) ||
2301541Srgrimes			    p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) {
2311541Srgrimes				PROC_UNLOCK(p);
2321541Srgrimes				sx_sunlock(&proctree_lock);
2331541Srgrimes				return (EIO);
2341541Srgrimes			}
2351541Srgrimes			pg = p->p_pgrp;
2361541Srgrimes			PROC_UNLOCK(p);
2371541Srgrimes			PGRP_LOCK(pg);
2381541Srgrimes			sx_sunlock(&proctree_lock);
2391541Srgrimes			pgsignal(pg, SIGTTIN, 1);
2401541Srgrimes			PGRP_UNLOCK(pg);
2411541Srgrimes			error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
2421541Srgrimes					 0);
2431541Srgrimes			if (error)
2441541Srgrimes				return (error);
2451541Srgrimes		}
2461541Srgrimes		if (tp->t_canq.c_cc == 0) {
2471541Srgrimes			if (flag & IO_NDELAY)
2481541Srgrimes				return (EWOULDBLOCK);
2491541Srgrimes			error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
2501541Srgrimes					 "ptsin", 0);
2511541Srgrimes			if (error)
2521541Srgrimes				return (error);
25312675Sjulian			goto again;
2541541Srgrimes		}
2551541Srgrimes		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
2561541Srgrimes			if (ureadc(getc(&tp->t_canq), uio) < 0) {
2571541Srgrimes				error = EFAULT;
2581541Srgrimes				break;
2591541Srgrimes			}
2601541Srgrimes		if (tp->t_canq.c_cc == 1)
2611541Srgrimes			(void) getc(&tp->t_canq);
2621541Srgrimes		if (tp->t_canq.c_cc)
2631541Srgrimes			return (error);
2641541Srgrimes	} else
2651541Srgrimes		if (tp->t_oproc)
2661541Srgrimes			error = ttyld_read(tp, uio, flag);
2671541Srgrimes	ptcwakeup(tp, FWRITE);
2681541Srgrimes	return (error);
2691541Srgrimes}
2701541Srgrimes
2711541Srgrimes/*
2721541Srgrimes * Write to pseudo-tty.
2731541Srgrimes * Wakeups of controlling tty will happen
2741541Srgrimes * indirectly, when tty driver calls ptsstart.
2751541Srgrimes */
2761541Srgrimesstatic	int
2771541Srgrimesptswrite(struct cdev *dev, struct uio *uio, int flag)
2781541Srgrimes{
2791541Srgrimes	struct tty *tp;
2801541Srgrimes
2811541Srgrimes	tp = dev->si_tty;
2821541Srgrimes	if (tp->t_oproc == 0)
2831541Srgrimes		return (EIO);
2841541Srgrimes	return (ttyld_write(tp, uio, flag));
2851541Srgrimes}
2861549Srgrimes
2871541Srgrimes/*
2881541Srgrimes * Start output on pseudo-tty.
2891541Srgrimes * Wake up process selecting or sleeping for input from controlling tty.
2901541Srgrimes */
2911541Srgrimesstatic void
2921541Srgrimesptsstart(struct tty *tp)
2931541Srgrimes{
2941541Srgrimes	struct ptsc *pt = tp->t_dev->si_drv1;
2959639Sbde
2961541Srgrimes	if (tp->t_state & TS_TTSTOP)
2971541Srgrimes		return;
2981541Srgrimes	if (pt->pt_flags & PF_STOPPED) {
2999639Sbde		pt->pt_flags &= ~PF_STOPPED;
3001541Srgrimes		pt->pt_send = TIOCPKT_START;
3011541Srgrimes	}
3021541Srgrimes	ptcwakeup(tp, FREAD);
30312675Sjulian}
3041541Srgrimes
3051541Srgrimesstatic void
3061541Srgrimesptcwakeup(struct tty *tp, int flag)
3071541Srgrimes{
3081541Srgrimes	struct ptsc *pt = tp->t_dev->si_drv1;
3091541Srgrimes
3101541Srgrimes	if (flag & FREAD) {
3111541Srgrimes		selwakeuppri(&pt->pt_selr, TTIPRI);
3121541Srgrimes		wakeup(TSA_PTC_READ(tp));
3131541Srgrimes	}
3141541Srgrimes	if (flag & FWRITE) {
3151541Srgrimes		selwakeuppri(&pt->pt_selw, TTOPRI);
3161541Srgrimes		wakeup(TSA_PTC_WRITE(tp));
3171541Srgrimes	}
3181541Srgrimes}
3191541Srgrimes
3201541Srgrimesstatic	int
3211541Srgrimesptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
3221541Srgrimes{
3231541Srgrimes	struct tty *tp;
3241541Srgrimes	struct ptsc *pt;
3251541Srgrimes
3261541Srgrimes	if (!dev->si_drv1)
3271541Srgrimes		ptyinit(dev);
3281541Srgrimes	if (!dev->si_drv1)
3291541Srgrimes		return(ENXIO);
33012675Sjulian	tp = dev->si_tty;
33110624Sbde	if (tp->t_oproc)
3321541Srgrimes		return (EIO);
33310624Sbde	tp->t_timeout = -1;
33410624Sbde	tp->t_oproc = ptsstart;
33510624Sbde	tp->t_stop = ptsstop;
3361541Srgrimes	(void)ttyld_modem(tp, 1);
3371541Srgrimes	tp->t_lflag &= ~EXTPROC;
3381541Srgrimes	pt = dev->si_drv1;
3391541Srgrimes	pt->pt_prison = td->td_ucred->cr_prison;
3401541Srgrimes	pt->pt_flags = 0;
3419824Sbde	pt->pt_send = 0;
3429824Sbde	pt->pt_ucntl = 0;
3439824Sbde	return (0);
3449824Sbde}
3459824Sbde
3469824Sbdestatic	int
3479824Sbdeptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
3489824Sbde{
3499824Sbde	struct tty *tp;
3509850Sbde
3519850Sbde	tp = dev->si_tty;
3529850Sbde	(void)ttyld_modem(tp, 0);
3539850Sbde
3549850Sbde	/*
3559824Sbde	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
3561541Srgrimes	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
3571541Srgrimes	 * l_modem()s that ignore carrier drop make no sense for ptys but
3581541Srgrimes	 * may be in use because other parts of the line discipline make
3591541Srgrimes	 * sense for ptys.  Recover by doing everything that a normal
36012675Sjulian	 * ttymodem() would have done except for sending a SIGHUP.
3611541Srgrimes	 */
3621541Srgrimes	if (tp->t_state & TS_ISOPEN) {
3631541Srgrimes		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
3641541Srgrimes		tp->t_state |= TS_ZOMBIE;
3651541Srgrimes		ttyflush(tp, FREAD | FWRITE);
3661541Srgrimes	}
3671541Srgrimes
3681541Srgrimes	tp->t_oproc = 0;		/* mark closed */
3691541Srgrimes	return (0);
3701541Srgrimes}
3711541Srgrimes
3721541Srgrimesstatic	int
3731541Srgrimesptcread(struct cdev *dev, struct uio *uio, int flag)
3741541Srgrimes{
3751541Srgrimes	struct tty *tp = dev->si_tty;
3761541Srgrimes	struct ptsc *pt = dev->si_drv1;
3771541Srgrimes	char buf[BUFSIZ];
3781541Srgrimes	int error = 0, cc;
3791541Srgrimes
3801541Srgrimes	/*
3811541Srgrimes	 * We want to block until the slave
3821541Srgrimes	 * is open, and there's something to read;
3831541Srgrimes	 * but if we lost the slave or we're NBIO,
3841541Srgrimes	 * then return the appropriate error instead.
3851541Srgrimes	 */
3862807Sbde	for (;;) {
3872807Sbde		if (tp->t_state&TS_ISOPEN) {
3881541Srgrimes			if (pt->pt_flags&PF_PKT && pt->pt_send) {
3891541Srgrimes				error = ureadc((int)pt->pt_send, uio);
3901541Srgrimes				if (error)
3911541Srgrimes					return (error);
3921541Srgrimes				if (pt->pt_send & TIOCPKT_IOCTL) {
3931541Srgrimes					cc = min(uio->uio_resid,
3941541Srgrimes						sizeof(tp->t_termios));
3951541Srgrimes					uiomove(&tp->t_termios, cc, uio);
3961541Srgrimes				}
3971541Srgrimes				pt->pt_send = 0;
3981541Srgrimes				return (0);
3991541Srgrimes			}
4001541Srgrimes			if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
4011541Srgrimes				error = ureadc((int)pt->pt_ucntl, uio);
4029824Sbde				if (error)
4031541Srgrimes					return (error);
4041541Srgrimes				pt->pt_ucntl = 0;
4051541Srgrimes				return (0);
4069639Sbde			}
4073308Sphk			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
4081541Srgrimes				break;
4091541Srgrimes		}
4101541Srgrimes		if ((tp->t_state & TS_CONNECTED) == 0)
4111541Srgrimes			return (0);	/* EOF */
4121541Srgrimes		if (flag & IO_NDELAY)
4131541Srgrimes			return (EWOULDBLOCK);
4141541Srgrimes		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
4151541Srgrimes		if (error)
4161541Srgrimes			return (error);
4171541Srgrimes	}
4189626Sbde	if (pt->pt_flags & (PF_PKT|PF_UCNTL))
4191541Srgrimes		error = ureadc(0, uio);
4201541Srgrimes	while (uio->uio_resid > 0 && error == 0) {
4211541Srgrimes		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
42212675Sjulian		if (cc <= 0)
4231541Srgrimes			break;
4241541Srgrimes		error = uiomove(buf, cc, uio);
4251541Srgrimes	}
4261541Srgrimes	ttwwakeup(tp);
4271541Srgrimes	return (error);
4281541Srgrimes}
4291541Srgrimes
4301541Srgrimesstatic	void
4311541Srgrimesptsstop(struct tty *tp, int flush)
4321541Srgrimes{
4331541Srgrimes	struct ptsc *pt = tp->t_dev->si_drv1;
4341541Srgrimes	int flag;
4351541Srgrimes
4361541Srgrimes	/* note: FLUSHREAD and FLUSHWRITE already ok */
4371541Srgrimes	if (flush == 0) {
4381541Srgrimes		flush = TIOCPKT_STOP;
4391541Srgrimes		pt->pt_flags |= PF_STOPPED;
4401541Srgrimes	} else
4411541Srgrimes		pt->pt_flags &= ~PF_STOPPED;
4421541Srgrimes	pt->pt_send |= flush;
4431541Srgrimes	/* change of perspective */
4441541Srgrimes	flag = 0;
4451541Srgrimes	if (flush & FREAD)
44612675Sjulian		flag |= FWRITE;
4471541Srgrimes	if (flush & FWRITE)
4481541Srgrimes		flag |= FREAD;
4491541Srgrimes	ptcwakeup(tp, flag);
4501541Srgrimes}
4511541Srgrimes
4521541Srgrimesstatic	int
4531541Srgrimesptcpoll(struct cdev *dev, int events, struct thread *td)
4541541Srgrimes{
4551541Srgrimes	struct tty *tp = dev->si_tty;
4569824Sbde	struct ptsc *pt = dev->si_drv1;
4571541Srgrimes	int revents = 0;
4581541Srgrimes	int s;
4591541Srgrimes
4601541Srgrimes	if ((tp->t_state & TS_CONNECTED) == 0)
4611541Srgrimes		return (events &
4621541Srgrimes		   (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
4631541Srgrimes
4641541Srgrimes	/*
4651541Srgrimes	 * Need to block timeouts (ttrstart).
4661541Srgrimes	 */
4671541Srgrimes	s = spltty();
4681541Srgrimes
4691541Srgrimes	if (events & (POLLIN | POLLRDNORM))
4701541Srgrimes		if ((tp->t_state & TS_ISOPEN) &&
4711541Srgrimes		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
4721541Srgrimes		     ((pt->pt_flags & PF_PKT) && pt->pt_send) ||
4731541Srgrimes		     ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
4741541Srgrimes			revents |= events & (POLLIN | POLLRDNORM);
4753308Sphk
4763308Sphk	if (events & (POLLOUT | POLLWRNORM))
4771541Srgrimes		if (tp->t_state & TS_ISOPEN &&
4781541Srgrimes		    ((pt->pt_flags & PF_REMOTE) ?
4791541Srgrimes		     (tp->t_canq.c_cc == 0) :
4801541Srgrimes		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
4811541Srgrimes		      (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
4821541Srgrimes			revents |= events & (POLLOUT | POLLWRNORM);
4831541Srgrimes
4841541Srgrimes	if (events & POLLHUP)
4851541Srgrimes		if ((tp->t_state & TS_CARR_ON) == 0)
4861541Srgrimes			revents |= POLLHUP;
4871541Srgrimes
4881541Srgrimes	if (revents == 0) {
4891541Srgrimes		if (events & (POLLIN | POLLRDNORM))
4901541Srgrimes			selrecord(td, &pt->pt_selr);
4911541Srgrimes
4921541Srgrimes		if (events & (POLLOUT | POLLWRNORM))
4931541Srgrimes			selrecord(td, &pt->pt_selw);
4941541Srgrimes	}
4951541Srgrimes	splx(s);
4961541Srgrimes
4971541Srgrimes	return (revents);
4981541Srgrimes}
4991541Srgrimes
5001541Srgrimesstatic	int
50112675Sjulianptcwrite(struct cdev *dev, struct uio *uio, int flag)
5021541Srgrimes{
5031541Srgrimes	struct tty *tp = dev->si_tty;
5041541Srgrimes	u_char *cp = 0;
5051541Srgrimes	int cc = 0;
5061541Srgrimes	u_char locbuf[BUFSIZ];
5071541Srgrimes	int cnt = 0;
5081549Srgrimes	struct ptsc *pt = dev->si_drv1;
5091541Srgrimes	int error = 0;
5101541Srgrimes
5111541Srgrimesagain:
5121541Srgrimes	if ((tp->t_state&TS_ISOPEN) == 0)
5131541Srgrimes		goto block;
5141541Srgrimes	if (pt->pt_flags & PF_REMOTE) {
5151541Srgrimes		if (tp->t_canq.c_cc)
5161541Srgrimes			goto block;
5171541Srgrimes		while ((uio->uio_resid > 0 || cc > 0) &&
5181541Srgrimes		       tp->t_canq.c_cc < TTYHOG - 1) {
5191541Srgrimes			if (cc == 0) {
5201541Srgrimes				cc = min(uio->uio_resid, BUFSIZ);
52111789Sbde				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
52211789Sbde				cp = locbuf;
5231541Srgrimes				error = uiomove(cp, cc, uio);
5241541Srgrimes				if (error)
5251541Srgrimes					return (error);
5261541Srgrimes				/* check again for safety */
5271541Srgrimes				if ((tp->t_state & TS_ISOPEN) == 0) {
5281541Srgrimes					/* adjust as usual */
5291541Srgrimes					uio->uio_resid += cc;
5301541Srgrimes					return (EIO);
53111789Sbde				}
53211789Sbde			}
53311789Sbde			if (cc > 0) {
5341541Srgrimes				cc = b_to_q((char *)cp, cc, &tp->t_canq);
53511789Sbde				/*
5361541Srgrimes				 * XXX we don't guarantee that the canq size
5371541Srgrimes				 * is >= TTYHOG, so the above b_to_q() may
53811789Sbde				 * leave some bytes uncopied.  However, space
5391541Srgrimes				 * is guaranteed for the null terminator if
54011789Sbde				 * we don't fail here since (TTYHOG - 1) is
54111789Sbde				 * not a multiple of CBSIZE.
5421541Srgrimes				 */
5431541Srgrimes				if (cc > 0)
5449639Sbde					break;
5451541Srgrimes			}
5461541Srgrimes		}
54711789Sbde		/* adjust for data copied in but not written */
5481541Srgrimes		uio->uio_resid += cc;
5491541Srgrimes		(void) putc(0, &tp->t_canq);
5501541Srgrimes		ttwakeup(tp);
5511541Srgrimes		wakeup(TSA_PTS_READ(tp));
5521541Srgrimes		return (0);
5531541Srgrimes	}
5541541Srgrimes	while (uio->uio_resid > 0 || cc > 0) {
55511789Sbde		if (cc == 0) {
55611789Sbde			cc = min(uio->uio_resid, BUFSIZ);
55711789Sbde			cp = locbuf;
5581541Srgrimes			error = uiomove(cp, cc, uio);
55911789Sbde			if (error)
5601541Srgrimes				return (error);
5611541Srgrimes			/* check again for safety */
5621541Srgrimes			if ((tp->t_state & TS_ISOPEN) == 0) {
5631541Srgrimes				/* adjust for data copied in but not written */
5649824Sbde				uio->uio_resid += cc;
5651541Srgrimes				return (EIO);
5661541Srgrimes			}
5671541Srgrimes		}
5681541Srgrimes		while (cc > 0) {
5691541Srgrimes			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
5701541Srgrimes			   (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
5711541Srgrimes				wakeup(TSA_HUP_OR_INPUT(tp));
5721541Srgrimes				goto block;
5731541Srgrimes			}
5741541Srgrimes			ttyld_rint(tp, *cp++);
5751541Srgrimes			cnt++;
5761541Srgrimes			cc--;
5771541Srgrimes		}
5781541Srgrimes		cc = 0;
57911789Sbde	}
58011789Sbde	return (0);
58111789Sbdeblock:
5821541Srgrimes	/*
58311789Sbde	 * Come here to wait for slave to open, for space
5841541Srgrimes	 * in outq, or space in rawq, or an empty canq.
5851541Srgrimes	 */
5861541Srgrimes	if ((tp->t_state & TS_CONNECTED) == 0) {
5871541Srgrimes		/* adjust for data copied in but not written */
5881541Srgrimes		uio->uio_resid += cc;
5891541Srgrimes		return (EIO);
5901541Srgrimes	}
5919639Sbde	if (flag & IO_NDELAY) {
5923308Sphk		/* adjust for data copied in but not written */
5931541Srgrimes		uio->uio_resid += cc;
5941541Srgrimes		if (cnt == 0)
5951541Srgrimes			return (EWOULDBLOCK);
5961541Srgrimes		return (0);
5971541Srgrimes	}
5981541Srgrimes	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
5991541Srgrimes	if (error) {
60012675Sjulian		/* adjust for data copied in but not written */
6016712Spst		uio->uio_resid += cc;
6026712Spst		return (error);
6036712Spst	}
6046712Spst	goto again;
6056712Spst}
6066712Spst
6076712Spst/*ARGSUSED*/
6086712Spststatic	int
6096712Spstptyioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
6101541Srgrimes{
61112675Sjulian	struct tty *tp = dev->si_tty;
6121541Srgrimes	struct ptsc *pt = dev->si_drv1;
6131541Srgrimes	u_char *cc = tp->t_cc;
6141541Srgrimes	int stop, error;
6151541Srgrimes
6161541Srgrimes	if (devsw(dev)->d_open == ptcopen) {
6171541Srgrimes		switch (cmd) {
6181541Srgrimes
6191541Srgrimes		case TIOCGPGRP:
6201541Srgrimes			/*
6211541Srgrimes			 * We avoid calling ttioctl on the controller since,
6221541Srgrimes			 * in that case, tp must be the controlling terminal.
6231541Srgrimes			 */
6241541Srgrimes			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
6251541Srgrimes			return (0);
6261541Srgrimes
6271541Srgrimes		case TIOCPKT:
6281541Srgrimes			if (*(int *)data) {
6291541Srgrimes				if (pt->pt_flags & PF_UCNTL)
6301541Srgrimes					return (EINVAL);
6311541Srgrimes				pt->pt_flags |= PF_PKT;
6321541Srgrimes			} else
6331541Srgrimes				pt->pt_flags &= ~PF_PKT;
6341541Srgrimes			return (0);
6351541Srgrimes
6361541Srgrimes		case TIOCUCNTL:
6371541Srgrimes			if (*(int *)data) {
6381541Srgrimes				if (pt->pt_flags & PF_PKT)
6391541Srgrimes					return (EINVAL);
6401541Srgrimes				pt->pt_flags |= PF_UCNTL;
6411541Srgrimes			} else
6421541Srgrimes				pt->pt_flags &= ~PF_UCNTL;
6431541Srgrimes			return (0);
6441541Srgrimes
6451541Srgrimes		case TIOCREMOTE:
6461541Srgrimes			if (*(int *)data)
6471541Srgrimes				pt->pt_flags |= PF_REMOTE;
6481541Srgrimes			else
6491541Srgrimes				pt->pt_flags &= ~PF_REMOTE;
6501541Srgrimes			ttyflush(tp, FREAD|FWRITE);
6511541Srgrimes			return (0);
6521541Srgrimes		}
6531541Srgrimes
6541541Srgrimes		/*
6551541Srgrimes		 * The rest of the ioctls shouldn't be called until
6561541Srgrimes		 * the slave is open.
6571541Srgrimes		 */
6581541Srgrimes		if ((tp->t_state & TS_ISOPEN) == 0)
6591541Srgrimes			return (EAGAIN);
6601541Srgrimes
6611541Srgrimes		switch (cmd) {
6621541Srgrimes#ifdef COMPAT_43
6631541Srgrimes		case TIOCSETP:
6641541Srgrimes		case TIOCSETN:
6651541Srgrimes#endif
6661541Srgrimes		case TIOCSETD:
6671541Srgrimes		case TIOCSETA:
6681541Srgrimes		case TIOCSETAW:
6691541Srgrimes		case TIOCSETAF:
6701541Srgrimes			/*
6711541Srgrimes			 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
6721541Srgrimes			 * ttywflush(tp) will hang if there are characters in
6731541Srgrimes			 * the outq.
6741541Srgrimes			 */
6751541Srgrimes			ndflush(&tp->t_outq, tp->t_outq.c_cc);
6761541Srgrimes			break;
6771541Srgrimes
6781541Srgrimes		case TIOCSIG:
6791541Srgrimes			if (*(unsigned int *)data >= NSIG ||
6801541Srgrimes			    *(unsigned int *)data == 0)
6811541Srgrimes				return(EINVAL);
6821541Srgrimes			if ((tp->t_lflag&NOFLSH) == 0)
6831541Srgrimes				ttyflush(tp, FREAD|FWRITE);
6841541Srgrimes			if (tp->t_pgrp != NULL) {
6851541Srgrimes				PGRP_LOCK(tp->t_pgrp);
6861541Srgrimes				pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
6871541Srgrimes				PGRP_UNLOCK(tp->t_pgrp);
6888876Srgrimes			}
6891541Srgrimes			if ((*(unsigned int *)data == SIGINFO) &&
6901541Srgrimes			    ((tp->t_lflag&NOKERNINFO) == 0))
6911541Srgrimes				ttyinfo(tp);
6921541Srgrimes			return(0);
6931541Srgrimes		}
6949858Sache	}
6951541Srgrimes	if (cmd == TIOCEXT) {
6961541Srgrimes		/*
6971541Srgrimes		 * When the EXTPROC bit is being toggled, we need
6981541Srgrimes		 * to send an TIOCPKT_IOCTL if the packet driver
6991541Srgrimes		 * is turned on.
7001541Srgrimes		 */
7011541Srgrimes		if (*(int *)data) {
7021541Srgrimes			if (pt->pt_flags & PF_PKT) {
7031541Srgrimes				pt->pt_send |= TIOCPKT_IOCTL;
7041541Srgrimes				ptcwakeup(tp, FREAD);
7051541Srgrimes			}
7061541Srgrimes			tp->t_lflag |= EXTPROC;
7071541Srgrimes		} else {
7081541Srgrimes			if ((tp->t_lflag & EXTPROC) &&
7091541Srgrimes			    (pt->pt_flags & PF_PKT)) {
7101541Srgrimes				pt->pt_send |= TIOCPKT_IOCTL;
7111541Srgrimes				ptcwakeup(tp, FREAD);
7121541Srgrimes			}
7131541Srgrimes			tp->t_lflag &= ~EXTPROC;
7141541Srgrimes		}
7151541Srgrimes		return(0);
7161541Srgrimes	}
7171541Srgrimes	error = ttyioctl(dev, cmd, data, flag, td);
7181541Srgrimes	if (error == ENOTTY) {
7191541Srgrimes		if (pt->pt_flags & PF_UCNTL &&
7201541Srgrimes		    (cmd & ~0xff) == UIOCCMD(0)) {
7211541Srgrimes			if (cmd & 0xff) {
7221541Srgrimes				pt->pt_ucntl = (u_char)cmd;
7231541Srgrimes				ptcwakeup(tp, FREAD);
7241541Srgrimes			}
7251541Srgrimes			return (0);
7261541Srgrimes		}
7271541Srgrimes		error = ENOTTY;
7281541Srgrimes	}
7291541Srgrimes	/*
7301541Srgrimes	 * If external processing and packet mode send ioctl packet.
7311541Srgrimes	 */
7321541Srgrimes	if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
7331541Srgrimes		switch(cmd) {
7341541Srgrimes		case TIOCSETA:
7351541Srgrimes		case TIOCSETAW:
7361541Srgrimes		case TIOCSETAF:
7371541Srgrimes#ifdef COMPAT_43
7381541Srgrimes		case TIOCSETP:
7391541Srgrimes		case TIOCSETN:
7401541Srgrimes#endif
7411541Srgrimes#if defined(COMPAT_43)
7421541Srgrimes		case TIOCSETC:
7431541Srgrimes		case TIOCSLTC:
7441541Srgrimes		case TIOCLBIS:
7451541Srgrimes		case TIOCLBIC:
7461541Srgrimes		case TIOCLSET:
7471541Srgrimes#endif
7488876Srgrimes			pt->pt_send |= TIOCPKT_IOCTL;
7491541Srgrimes			ptcwakeup(tp, FREAD);
7501541Srgrimes			break;
7511541Srgrimes		default:
7521541Srgrimes			break;
7531541Srgrimes		}
7541541Srgrimes	}
7551541Srgrimes	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
7561541Srgrimes		&& CCEQ(cc[VSTART], CTRL('q'));
7571541Srgrimes	if (pt->pt_flags & PF_NOSTOP) {
7581541Srgrimes		if (stop) {
7591541Srgrimes			pt->pt_send &= ~TIOCPKT_NOSTOP;
7601541Srgrimes			pt->pt_send |= TIOCPKT_DOSTOP;
7611541Srgrimes			pt->pt_flags &= ~PF_NOSTOP;
7621541Srgrimes			ptcwakeup(tp, FREAD);
7631541Srgrimes		}
7641541Srgrimes	} else {
7651541Srgrimes		if (!stop) {
7661541Srgrimes			pt->pt_send &= ~TIOCPKT_DOSTOP;
76712517Sjulian			pt->pt_send |= TIOCPKT_NOSTOP;
76812517Sjulian			pt->pt_flags |= PF_NOSTOP;
76912675Sjulian			ptcwakeup(tp, FREAD);
77012675Sjulian		}
77112675Sjulian	}
77212675Sjulian	return (error);
77312675Sjulian}
77412675Sjulian
77512675Sjulianstatic void
77612517Sjulianpty_clone(void *arg, char *name, int namelen, struct cdev **dev)
77712675Sjulian{
77812675Sjulian	int u;
77912517Sjulian
78012517Sjulian	if (*dev != NODEV)
78112567Sjulian		return;
78212675Sjulian	if (bcmp(name, "pty", 3) != 0)
78312517Sjulian		return;
78412517Sjulian	if (name[5] != '\0')
78512517Sjulian		return;
78612517Sjulian	switch (name[3]) {
78712675Sjulian	case 'p': u =   0; break;
78812675Sjulian	case 'q': u =  32; break;
78912675Sjulian	case 'r': u =  64; break;
79012675Sjulian	case 's': u =  96; break;
79112517Sjulian	case 'P': u = 128; break;
79212517Sjulian	case 'Q': u = 160; break;
79312517Sjulian	case 'R': u = 192; break;
79412517Sjulian	case 'S': u = 224; break;
79512517Sjulian	default: return;
79612517Sjulian	}
79712517Sjulian	if (name[4] >= '0' && name[4] <= '9')
79812521Sjulian		u += name[4] - '0';
79912675Sjulian	else if (name[4] >= 'a' && name[4] <= 'v')
80012517Sjulian		u += name[4] - 'a' + 10;
80112564Sjulian	else
80212564Sjulian		return;
80312675Sjulian	*dev = make_dev(&ptc_cdevsw, u,
80412675Sjulian	    UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
80512675Sjulian	(*dev)->si_flags |= SI_CHEAPCLONE;
80612675Sjulian	return;
80712675Sjulian}
80812675Sjulian
80912675Sjulianstatic void
81012675Sjulianptc_drvinit(void *unused)
81112521Sjulian{
81212521Sjulian
81312517Sjulian	EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000);
81412517Sjulian}
81512517Sjulian
81612517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
81712517Sjulian