Home | History | Annotate | Line # | Download | only in kern
tty_pty.c revision 1.1.1.3
      1      1.1   cgd /*
      2  1.1.1.2  fvdl  * Copyright (c) 1982, 1986, 1989, 1993
      3  1.1.1.2  fvdl  *	The Regents of the University of California.  All rights reserved.
      4      1.1   cgd  *
      5      1.1   cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1   cgd  * modification, are permitted provided that the following conditions
      7      1.1   cgd  * are met:
      8      1.1   cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1   cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1   cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1   cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1   cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1   cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1   cgd  *    must display the following acknowledgement:
     15      1.1   cgd  *	This product includes software developed by the University of
     16      1.1   cgd  *	California, Berkeley and its contributors.
     17      1.1   cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1   cgd  *    may be used to endorse or promote products derived from this software
     19      1.1   cgd  *    without specific prior written permission.
     20      1.1   cgd  *
     21      1.1   cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1   cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1   cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1   cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1   cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1   cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1   cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1   cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1   cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1   cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1   cgd  * SUCH DAMAGE.
     32      1.1   cgd  *
     33  1.1.1.3  fvdl  *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
     34      1.1   cgd  */
     35      1.1   cgd 
     36      1.1   cgd /*
     37      1.1   cgd  * Pseudo-teletype Driver
     38      1.1   cgd  * (Actually two drivers, requiring two entries in 'cdevsw')
     39      1.1   cgd  */
     40  1.1.1.2  fvdl #include "pty.h"		/* XXX */
     41      1.1   cgd 
     42  1.1.1.2  fvdl #include <sys/param.h>
     43  1.1.1.2  fvdl #include <sys/systm.h>
     44  1.1.1.2  fvdl #include <sys/ioctl.h>
     45  1.1.1.2  fvdl #include <sys/proc.h>
     46  1.1.1.2  fvdl #include <sys/tty.h>
     47  1.1.1.2  fvdl #include <sys/conf.h>
     48  1.1.1.2  fvdl #include <sys/file.h>
     49  1.1.1.2  fvdl #include <sys/uio.h>
     50  1.1.1.2  fvdl #include <sys/kernel.h>
     51  1.1.1.2  fvdl #include <sys/vnode.h>
     52      1.1   cgd 
     53      1.1   cgd #if NPTY == 1
     54      1.1   cgd #undef NPTY
     55      1.1   cgd #define	NPTY	32		/* crude XXX */
     56      1.1   cgd #endif
     57      1.1   cgd 
     58      1.1   cgd #define BUFSIZ 100		/* Chunk size iomoved to/from user */
     59      1.1   cgd 
     60      1.1   cgd /*
     61      1.1   cgd  * pts == /dev/tty[pqrs]?
     62      1.1   cgd  * ptc == /dev/pty[pqrs]?
     63      1.1   cgd  */
     64  1.1.1.2  fvdl struct	tty pt_tty[NPTY];	/* XXX */
     65      1.1   cgd struct	pt_ioctl {
     66      1.1   cgd 	int	pt_flags;
     67  1.1.1.2  fvdl 	struct	selinfo pt_selr, pt_selw;
     68      1.1   cgd 	u_char	pt_send;
     69      1.1   cgd 	u_char	pt_ucntl;
     70  1.1.1.2  fvdl } pt_ioctl[NPTY];		/* XXX */
     71      1.1   cgd int	npty = NPTY;		/* for pstat -t */
     72      1.1   cgd 
     73      1.1   cgd #define	PF_PKT		0x08		/* packet mode */
     74      1.1   cgd #define	PF_STOPPED	0x10		/* user told stopped */
     75      1.1   cgd #define	PF_REMOTE	0x20		/* remote and flow controlled input */
     76      1.1   cgd #define	PF_NOSTOP	0x40
     77      1.1   cgd #define PF_UCNTL	0x80		/* user control mode */
     78      1.1   cgd 
     79  1.1.1.2  fvdl void	ptsstop __P((struct tty *, int));
     80  1.1.1.2  fvdl 
     81  1.1.1.2  fvdl /*
     82  1.1.1.2  fvdl  * Establish n (or default if n is 1) ptys in the system.
     83  1.1.1.2  fvdl  *
     84  1.1.1.2  fvdl  * XXX cdevsw & pstat require the array `pty[]' to be an array
     85  1.1.1.2  fvdl  */
     86  1.1.1.2  fvdl void
     87  1.1.1.2  fvdl ptyattach(n)
     88  1.1.1.2  fvdl 	int n;
     89  1.1.1.2  fvdl {
     90  1.1.1.2  fvdl #ifdef notyet
     91  1.1.1.2  fvdl 	char *mem;
     92  1.1.1.2  fvdl 	register u_long ntb;
     93  1.1.1.2  fvdl #define	DEFAULT_NPTY	32
     94  1.1.1.2  fvdl 
     95  1.1.1.2  fvdl 	/* maybe should allow 0 => none? */
     96  1.1.1.2  fvdl 	if (n <= 1)
     97  1.1.1.2  fvdl 		n = DEFAULT_NPTY;
     98  1.1.1.2  fvdl 	ntb = n * sizeof(struct tty);
     99  1.1.1.2  fvdl 	mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
    100  1.1.1.2  fvdl 	    M_DEVBUF, M_WAITOK);
    101  1.1.1.2  fvdl 	pt_tty = (struct tty *)mem;
    102  1.1.1.2  fvdl 	mem = (char *)ALIGN(mem + ntb);
    103  1.1.1.2  fvdl 	pt_ioctl = (struct pt_ioctl *)mem;
    104  1.1.1.2  fvdl 	npty = n;
    105  1.1.1.2  fvdl #endif
    106  1.1.1.2  fvdl }
    107  1.1.1.2  fvdl 
    108      1.1   cgd /*ARGSUSED*/
    109      1.1   cgd ptsopen(dev, flag, devtype, p)
    110      1.1   cgd 	dev_t dev;
    111  1.1.1.2  fvdl 	int flag, devtype;
    112      1.1   cgd 	struct proc *p;
    113      1.1   cgd {
    114      1.1   cgd 	register struct tty *tp;
    115      1.1   cgd 	int error;
    116      1.1   cgd 
    117  1.1.1.2  fvdl 	if (minor(dev) >= npty)
    118      1.1   cgd 		return (ENXIO);
    119      1.1   cgd 	tp = &pt_tty[minor(dev)];
    120      1.1   cgd 	if ((tp->t_state & TS_ISOPEN) == 0) {
    121      1.1   cgd 		tp->t_state |= TS_WOPEN;
    122      1.1   cgd 		ttychars(tp);		/* Set up default chars */
    123      1.1   cgd 		tp->t_iflag = TTYDEF_IFLAG;
    124      1.1   cgd 		tp->t_oflag = TTYDEF_OFLAG;
    125      1.1   cgd 		tp->t_lflag = TTYDEF_LFLAG;
    126      1.1   cgd 		tp->t_cflag = TTYDEF_CFLAG;
    127      1.1   cgd 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
    128      1.1   cgd 		ttsetwater(tp);		/* would be done in xxparam() */
    129      1.1   cgd 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
    130      1.1   cgd 		return (EBUSY);
    131      1.1   cgd 	if (tp->t_oproc)			/* Ctrlr still around. */
    132      1.1   cgd 		tp->t_state |= TS_CARR_ON;
    133      1.1   cgd 	while ((tp->t_state & TS_CARR_ON) == 0) {
    134      1.1   cgd 		tp->t_state |= TS_WOPEN;
    135      1.1   cgd 		if (flag&FNONBLOCK)
    136      1.1   cgd 			break;
    137  1.1.1.2  fvdl 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
    138      1.1   cgd 		    ttopen, 0))
    139      1.1   cgd 			return (error);
    140      1.1   cgd 	}
    141  1.1.1.2  fvdl 	error = (*linesw[tp->t_line].l_open)(dev, tp);
    142      1.1   cgd 	ptcwakeup(tp, FREAD|FWRITE);
    143      1.1   cgd 	return (error);
    144      1.1   cgd }
    145      1.1   cgd 
    146      1.1   cgd ptsclose(dev, flag, mode, p)
    147      1.1   cgd 	dev_t dev;
    148      1.1   cgd 	int flag, mode;
    149      1.1   cgd 	struct proc *p;
    150      1.1   cgd {
    151      1.1   cgd 	register struct tty *tp;
    152  1.1.1.2  fvdl 	int err;
    153      1.1   cgd 
    154      1.1   cgd 	tp = &pt_tty[minor(dev)];
    155  1.1.1.2  fvdl 	err = (*linesw[tp->t_line].l_close)(tp, flag);
    156  1.1.1.2  fvdl 	err |= ttyclose(tp);
    157      1.1   cgd 	ptcwakeup(tp, FREAD|FWRITE);
    158  1.1.1.2  fvdl 	return (err);
    159      1.1   cgd }
    160      1.1   cgd 
    161      1.1   cgd ptsread(dev, uio, flag)
    162      1.1   cgd 	dev_t dev;
    163      1.1   cgd 	struct uio *uio;
    164  1.1.1.2  fvdl 	int flag;
    165      1.1   cgd {
    166      1.1   cgd 	struct proc *p = curproc;
    167      1.1   cgd 	register struct tty *tp = &pt_tty[minor(dev)];
    168      1.1   cgd 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
    169      1.1   cgd 	int error = 0;
    170      1.1   cgd 
    171      1.1   cgd again:
    172      1.1   cgd 	if (pti->pt_flags & PF_REMOTE) {
    173      1.1   cgd 		while (isbackground(p, tp)) {
    174      1.1   cgd 			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
    175      1.1   cgd 			    (p->p_sigmask & sigmask(SIGTTIN)) ||
    176      1.1   cgd 			    p->p_pgrp->pg_jobc == 0 ||
    177  1.1.1.2  fvdl 			    p->p_flag & P_PPWAIT)
    178      1.1   cgd 				return (EIO);
    179      1.1   cgd 			pgsignal(p->p_pgrp, SIGTTIN, 1);
    180      1.1   cgd 			if (error = ttysleep(tp, (caddr_t)&lbolt,
    181      1.1   cgd 			    TTIPRI | PCATCH, ttybg, 0))
    182      1.1   cgd 				return (error);
    183      1.1   cgd 		}
    184  1.1.1.2  fvdl 		if (tp->t_canq.c_cc == 0) {
    185      1.1   cgd 			if (flag & IO_NDELAY)
    186      1.1   cgd 				return (EWOULDBLOCK);
    187  1.1.1.2  fvdl 			if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
    188      1.1   cgd 			    TTIPRI | PCATCH, ttyin, 0))
    189      1.1   cgd 				return (error);
    190      1.1   cgd 			goto again;
    191      1.1   cgd 		}
    192  1.1.1.2  fvdl 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
    193  1.1.1.2  fvdl 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
    194      1.1   cgd 				error = EFAULT;
    195      1.1   cgd 				break;
    196      1.1   cgd 			}
    197  1.1.1.2  fvdl 		if (tp->t_canq.c_cc == 1)
    198  1.1.1.2  fvdl 			(void) getc(&tp->t_canq);
    199  1.1.1.2  fvdl 		if (tp->t_canq.c_cc)
    200      1.1   cgd 			return (error);
    201      1.1   cgd 	} else
    202      1.1   cgd 		if (tp->t_oproc)
    203      1.1   cgd 			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
    204      1.1   cgd 	ptcwakeup(tp, FWRITE);
    205      1.1   cgd 	return (error);
    206      1.1   cgd }
    207      1.1   cgd 
    208      1.1   cgd /*
    209      1.1   cgd  * Write to pseudo-tty.
    210      1.1   cgd  * Wakeups of controlling tty will happen
    211      1.1   cgd  * indirectly, when tty driver calls ptsstart.
    212      1.1   cgd  */
    213      1.1   cgd ptswrite(dev, uio, flag)
    214      1.1   cgd 	dev_t dev;
    215      1.1   cgd 	struct uio *uio;
    216  1.1.1.2  fvdl 	int flag;
    217      1.1   cgd {
    218      1.1   cgd 	register struct tty *tp;
    219      1.1   cgd 
    220      1.1   cgd 	tp = &pt_tty[minor(dev)];
    221      1.1   cgd 	if (tp->t_oproc == 0)
    222      1.1   cgd 		return (EIO);
    223      1.1   cgd 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    224      1.1   cgd }
    225      1.1   cgd 
    226      1.1   cgd /*
    227      1.1   cgd  * Start output on pseudo-tty.
    228      1.1   cgd  * Wake up process selecting or sleeping for input from controlling tty.
    229      1.1   cgd  */
    230  1.1.1.2  fvdl void
    231      1.1   cgd ptsstart(tp)
    232      1.1   cgd 	struct tty *tp;
    233      1.1   cgd {
    234      1.1   cgd 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
    235      1.1   cgd 
    236      1.1   cgd 	if (tp->t_state & TS_TTSTOP)
    237      1.1   cgd 		return;
    238      1.1   cgd 	if (pti->pt_flags & PF_STOPPED) {
    239      1.1   cgd 		pti->pt_flags &= ~PF_STOPPED;
    240      1.1   cgd 		pti->pt_send = TIOCPKT_START;
    241      1.1   cgd 	}
    242      1.1   cgd 	ptcwakeup(tp, FREAD);
    243      1.1   cgd }
    244      1.1   cgd 
    245      1.1   cgd ptcwakeup(tp, flag)
    246      1.1   cgd 	struct tty *tp;
    247  1.1.1.2  fvdl 	int flag;
    248      1.1   cgd {
    249      1.1   cgd 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
    250      1.1   cgd 
    251      1.1   cgd 	if (flag & FREAD) {
    252  1.1.1.2  fvdl 		selwakeup(&pti->pt_selr);
    253  1.1.1.2  fvdl 		wakeup((caddr_t)&tp->t_outq.c_cf);
    254      1.1   cgd 	}
    255      1.1   cgd 	if (flag & FWRITE) {
    256  1.1.1.2  fvdl 		selwakeup(&pti->pt_selw);
    257  1.1.1.2  fvdl 		wakeup((caddr_t)&tp->t_rawq.c_cf);
    258      1.1   cgd 	}
    259      1.1   cgd }
    260      1.1   cgd 
    261      1.1   cgd /*ARGSUSED*/
    262      1.1   cgd #ifdef __STDC__
    263      1.1   cgd ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
    264      1.1   cgd #else
    265      1.1   cgd ptcopen(dev, flag, devtype, p)
    266      1.1   cgd 	dev_t dev;
    267      1.1   cgd 	int flag, devtype;
    268      1.1   cgd 	struct proc *p;
    269      1.1   cgd #endif
    270      1.1   cgd {
    271      1.1   cgd 	register struct tty *tp;
    272      1.1   cgd 	struct pt_ioctl *pti;
    273      1.1   cgd 
    274  1.1.1.2  fvdl 	if (minor(dev) >= npty)
    275      1.1   cgd 		return (ENXIO);
    276      1.1   cgd 	tp = &pt_tty[minor(dev)];
    277      1.1   cgd 	if (tp->t_oproc)
    278      1.1   cgd 		return (EIO);
    279      1.1   cgd 	tp->t_oproc = ptsstart;
    280  1.1.1.2  fvdl #ifdef sun4c
    281  1.1.1.2  fvdl 	tp->t_stop = ptsstop;
    282  1.1.1.2  fvdl #endif
    283      1.1   cgd 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
    284      1.1   cgd 	tp->t_lflag &= ~EXTPROC;
    285      1.1   cgd 	pti = &pt_ioctl[minor(dev)];
    286      1.1   cgd 	pti->pt_flags = 0;
    287      1.1   cgd 	pti->pt_send = 0;
    288      1.1   cgd 	pti->pt_ucntl = 0;
    289      1.1   cgd 	return (0);
    290      1.1   cgd }
    291      1.1   cgd 
    292      1.1   cgd ptcclose(dev)
    293      1.1   cgd 	dev_t dev;
    294      1.1   cgd {
    295      1.1   cgd 	register struct tty *tp;
    296      1.1   cgd 
    297      1.1   cgd 	tp = &pt_tty[minor(dev)];
    298      1.1   cgd 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
    299      1.1   cgd 	tp->t_state &= ~TS_CARR_ON;
    300      1.1   cgd 	tp->t_oproc = 0;		/* mark closed */
    301      1.1   cgd 	tp->t_session = 0;
    302  1.1.1.2  fvdl 	return (0);
    303      1.1   cgd }
    304      1.1   cgd 
    305      1.1   cgd ptcread(dev, uio, flag)
    306      1.1   cgd 	dev_t dev;
    307      1.1   cgd 	struct uio *uio;
    308  1.1.1.2  fvdl 	int flag;
    309      1.1   cgd {
    310      1.1   cgd 	register struct tty *tp = &pt_tty[minor(dev)];
    311      1.1   cgd 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
    312      1.1   cgd 	char buf[BUFSIZ];
    313      1.1   cgd 	int error = 0, cc;
    314      1.1   cgd 
    315      1.1   cgd 	/*
    316      1.1   cgd 	 * We want to block until the slave
    317      1.1   cgd 	 * is open, and there's something to read;
    318      1.1   cgd 	 * but if we lost the slave or we're NBIO,
    319      1.1   cgd 	 * then return the appropriate error instead.
    320      1.1   cgd 	 */
    321      1.1   cgd 	for (;;) {
    322      1.1   cgd 		if (tp->t_state&TS_ISOPEN) {
    323      1.1   cgd 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
    324      1.1   cgd 				error = ureadc((int)pti->pt_send, uio);
    325      1.1   cgd 				if (error)
    326      1.1   cgd 					return (error);
    327      1.1   cgd 				if (pti->pt_send & TIOCPKT_IOCTL) {
    328  1.1.1.2  fvdl 					cc = min(uio->uio_resid,
    329      1.1   cgd 						sizeof(tp->t_termios));
    330      1.1   cgd 					uiomove(&tp->t_termios, cc, uio);
    331      1.1   cgd 				}
    332      1.1   cgd 				pti->pt_send = 0;
    333      1.1   cgd 				return (0);
    334      1.1   cgd 			}
    335      1.1   cgd 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
    336      1.1   cgd 				error = ureadc((int)pti->pt_ucntl, uio);
    337      1.1   cgd 				if (error)
    338      1.1   cgd 					return (error);
    339      1.1   cgd 				pti->pt_ucntl = 0;
    340      1.1   cgd 				return (0);
    341      1.1   cgd 			}
    342  1.1.1.2  fvdl 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
    343      1.1   cgd 				break;
    344      1.1   cgd 		}
    345      1.1   cgd 		if ((tp->t_state&TS_CARR_ON) == 0)
    346      1.1   cgd 			return (0);	/* EOF */
    347      1.1   cgd 		if (flag & IO_NDELAY)
    348      1.1   cgd 			return (EWOULDBLOCK);
    349  1.1.1.2  fvdl 		if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
    350      1.1   cgd 		    ttyin, 0))
    351      1.1   cgd 			return (error);
    352      1.1   cgd 	}
    353      1.1   cgd 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
    354      1.1   cgd 		error = ureadc(0, uio);
    355      1.1   cgd 	while (uio->uio_resid > 0 && error == 0) {
    356  1.1.1.2  fvdl 		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
    357      1.1   cgd 		if (cc <= 0)
    358      1.1   cgd 			break;
    359      1.1   cgd 		error = uiomove(buf, cc, uio);
    360      1.1   cgd 	}
    361  1.1.1.2  fvdl 	if (tp->t_outq.c_cc <= tp->t_lowat) {
    362      1.1   cgd 		if (tp->t_state&TS_ASLEEP) {
    363      1.1   cgd 			tp->t_state &= ~TS_ASLEEP;
    364  1.1.1.2  fvdl 			wakeup((caddr_t)&tp->t_outq);
    365      1.1   cgd 		}
    366  1.1.1.2  fvdl 		selwakeup(&tp->t_wsel);
    367      1.1   cgd 	}
    368      1.1   cgd 	return (error);
    369      1.1   cgd }
    370      1.1   cgd 
    371  1.1.1.2  fvdl void
    372      1.1   cgd ptsstop(tp, flush)
    373      1.1   cgd 	register struct tty *tp;
    374      1.1   cgd 	int flush;
    375      1.1   cgd {
    376      1.1   cgd 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
    377      1.1   cgd 	int flag;
    378      1.1   cgd 
    379      1.1   cgd 	/* note: FLUSHREAD and FLUSHWRITE already ok */
    380      1.1   cgd 	if (flush == 0) {
    381      1.1   cgd 		flush = TIOCPKT_STOP;
    382      1.1   cgd 		pti->pt_flags |= PF_STOPPED;
    383      1.1   cgd 	} else
    384      1.1   cgd 		pti->pt_flags &= ~PF_STOPPED;
    385      1.1   cgd 	pti->pt_send |= flush;
    386      1.1   cgd 	/* change of perspective */
    387      1.1   cgd 	flag = 0;
    388      1.1   cgd 	if (flush & FREAD)
    389      1.1   cgd 		flag |= FWRITE;
    390      1.1   cgd 	if (flush & FWRITE)
    391      1.1   cgd 		flag |= FREAD;
    392      1.1   cgd 	ptcwakeup(tp, flag);
    393      1.1   cgd }
    394      1.1   cgd 
    395      1.1   cgd ptcselect(dev, rw, p)
    396      1.1   cgd 	dev_t dev;
    397      1.1   cgd 	int rw;
    398      1.1   cgd 	struct proc *p;
    399      1.1   cgd {
    400      1.1   cgd 	register struct tty *tp = &pt_tty[minor(dev)];
    401      1.1   cgd 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
    402      1.1   cgd 	int s;
    403      1.1   cgd 
    404      1.1   cgd 	if ((tp->t_state&TS_CARR_ON) == 0)
    405      1.1   cgd 		return (1);
    406      1.1   cgd 	switch (rw) {
    407      1.1   cgd 
    408      1.1   cgd 	case FREAD:
    409      1.1   cgd 		/*
    410      1.1   cgd 		 * Need to block timeouts (ttrstart).
    411      1.1   cgd 		 */
    412      1.1   cgd 		s = spltty();
    413      1.1   cgd 		if ((tp->t_state&TS_ISOPEN) &&
    414  1.1.1.2  fvdl 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
    415      1.1   cgd 			splx(s);
    416      1.1   cgd 			return (1);
    417      1.1   cgd 		}
    418      1.1   cgd 		splx(s);
    419      1.1   cgd 		/* FALLTHROUGH */
    420      1.1   cgd 
    421      1.1   cgd 	case 0:					/* exceptional */
    422      1.1   cgd 		if ((tp->t_state&TS_ISOPEN) &&
    423      1.1   cgd 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
    424      1.1   cgd 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
    425      1.1   cgd 			return (1);
    426  1.1.1.2  fvdl 		selrecord(p, &pti->pt_selr);
    427      1.1   cgd 		break;
    428      1.1   cgd 
    429      1.1   cgd 
    430      1.1   cgd 	case FWRITE:
    431      1.1   cgd 		if (tp->t_state&TS_ISOPEN) {
    432      1.1   cgd 			if (pti->pt_flags & PF_REMOTE) {
    433  1.1.1.2  fvdl 			    if (tp->t_canq.c_cc == 0)
    434      1.1   cgd 				return (1);
    435      1.1   cgd 			} else {
    436  1.1.1.2  fvdl 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
    437      1.1   cgd 				    return (1);
    438  1.1.1.2  fvdl 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
    439      1.1   cgd 				    return (1);
    440      1.1   cgd 			}
    441      1.1   cgd 		}
    442  1.1.1.2  fvdl 		selrecord(p, &pti->pt_selw);
    443      1.1   cgd 		break;
    444      1.1   cgd 
    445      1.1   cgd 	}
    446      1.1   cgd 	return (0);
    447      1.1   cgd }
    448      1.1   cgd 
    449      1.1   cgd ptcwrite(dev, uio, flag)
    450      1.1   cgd 	dev_t dev;
    451      1.1   cgd 	register struct uio *uio;
    452  1.1.1.2  fvdl 	int flag;
    453      1.1   cgd {
    454      1.1   cgd 	register struct tty *tp = &pt_tty[minor(dev)];
    455      1.1   cgd 	register u_char *cp;
    456      1.1   cgd 	register int cc = 0;
    457      1.1   cgd 	u_char locbuf[BUFSIZ];
    458      1.1   cgd 	int cnt = 0;
    459      1.1   cgd 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
    460      1.1   cgd 	int error = 0;
    461      1.1   cgd 
    462      1.1   cgd again:
    463      1.1   cgd 	if ((tp->t_state&TS_ISOPEN) == 0)
    464      1.1   cgd 		goto block;
    465      1.1   cgd 	if (pti->pt_flags & PF_REMOTE) {
    466  1.1.1.2  fvdl 		if (tp->t_canq.c_cc)
    467      1.1   cgd 			goto block;
    468  1.1.1.2  fvdl 		while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
    469      1.1   cgd 			if (cc == 0) {
    470      1.1   cgd 				cc = min(uio->uio_resid, BUFSIZ);
    471  1.1.1.2  fvdl 				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
    472      1.1   cgd 				cp = locbuf;
    473      1.1   cgd 				error = uiomove((caddr_t)cp, cc, uio);
    474      1.1   cgd 				if (error)
    475      1.1   cgd 					return (error);
    476      1.1   cgd 				/* check again for safety */
    477      1.1   cgd 				if ((tp->t_state&TS_ISOPEN) == 0)
    478      1.1   cgd 					return (EIO);
    479      1.1   cgd 			}
    480      1.1   cgd 			if (cc)
    481      1.1   cgd 				(void) b_to_q((char *)cp, cc, &tp->t_canq);
    482      1.1   cgd 			cc = 0;
    483      1.1   cgd 		}
    484  1.1.1.2  fvdl 		(void) putc(0, &tp->t_canq);
    485      1.1   cgd 		ttwakeup(tp);
    486  1.1.1.2  fvdl 		wakeup((caddr_t)&tp->t_canq);
    487      1.1   cgd 		return (0);
    488      1.1   cgd 	}
    489      1.1   cgd 	while (uio->uio_resid > 0) {
    490      1.1   cgd 		if (cc == 0) {
    491      1.1   cgd 			cc = min(uio->uio_resid, BUFSIZ);
    492      1.1   cgd 			cp = locbuf;
    493      1.1   cgd 			error = uiomove((caddr_t)cp, cc, uio);
    494      1.1   cgd 			if (error)
    495      1.1   cgd 				return (error);
    496      1.1   cgd 			/* check again for safety */
    497      1.1   cgd 			if ((tp->t_state&TS_ISOPEN) == 0)
    498      1.1   cgd 				return (EIO);
    499      1.1   cgd 		}
    500      1.1   cgd 		while (cc > 0) {
    501  1.1.1.2  fvdl 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
    502  1.1.1.2  fvdl 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
    503  1.1.1.2  fvdl 				wakeup((caddr_t)&tp->t_rawq);
    504      1.1   cgd 				goto block;
    505      1.1   cgd 			}
    506      1.1   cgd 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
    507      1.1   cgd 			cnt++;
    508      1.1   cgd 			cc--;
    509      1.1   cgd 		}
    510      1.1   cgd 		cc = 0;
    511      1.1   cgd 	}
    512      1.1   cgd 	return (0);
    513      1.1   cgd block:
    514      1.1   cgd 	/*
    515      1.1   cgd 	 * Come here to wait for slave to open, for space
    516      1.1   cgd 	 * in outq, or space in rawq.
    517      1.1   cgd 	 */
    518      1.1   cgd 	if ((tp->t_state&TS_CARR_ON) == 0)
    519      1.1   cgd 		return (EIO);
    520      1.1   cgd 	if (flag & IO_NDELAY) {
    521      1.1   cgd 		/* adjust for data copied in but not written */
    522      1.1   cgd 		uio->uio_resid += cc;
    523      1.1   cgd 		if (cnt == 0)
    524      1.1   cgd 			return (EWOULDBLOCK);
    525      1.1   cgd 		return (0);
    526      1.1   cgd 	}
    527  1.1.1.2  fvdl 	if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
    528      1.1   cgd 	    ttyout, 0)) {
    529      1.1   cgd 		/* adjust for data copied in but not written */
    530      1.1   cgd 		uio->uio_resid += cc;
    531      1.1   cgd 		return (error);
    532      1.1   cgd 	}
    533      1.1   cgd 	goto again;
    534      1.1   cgd }
    535      1.1   cgd 
    536      1.1   cgd /*ARGSUSED*/
    537  1.1.1.2  fvdl ptyioctl(dev, cmd, data, flag, p)
    538      1.1   cgd 	dev_t dev;
    539  1.1.1.3  fvdl 	u_long cmd;
    540  1.1.1.2  fvdl 	caddr_t data;
    541  1.1.1.2  fvdl 	int flag;
    542  1.1.1.2  fvdl 	struct proc *p;
    543      1.1   cgd {
    544      1.1   cgd 	register struct tty *tp = &pt_tty[minor(dev)];
    545      1.1   cgd 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
    546      1.1   cgd 	register u_char *cc = tp->t_cc;
    547      1.1   cgd 	int stop, error;
    548      1.1   cgd 
    549      1.1   cgd 	/*
    550      1.1   cgd 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
    551      1.1   cgd 	 * ttywflush(tp) will hang if there are characters in the outq.
    552      1.1   cgd 	 */
    553      1.1   cgd 	if (cmd == TIOCEXT) {
    554      1.1   cgd 		/*
    555      1.1   cgd 		 * When the EXTPROC bit is being toggled, we need
    556      1.1   cgd 		 * to send an TIOCPKT_IOCTL if the packet driver
    557      1.1   cgd 		 * is turned on.
    558      1.1   cgd 		 */
    559      1.1   cgd 		if (*(int *)data) {
    560      1.1   cgd 			if (pti->pt_flags & PF_PKT) {
    561      1.1   cgd 				pti->pt_send |= TIOCPKT_IOCTL;
    562      1.1   cgd 				ptcwakeup(tp, FREAD);
    563      1.1   cgd 			}
    564      1.1   cgd 			tp->t_lflag |= EXTPROC;
    565      1.1   cgd 		} else {
    566  1.1.1.3  fvdl 			if ((tp->t_lflag & EXTPROC) &&
    567      1.1   cgd 			    (pti->pt_flags & PF_PKT)) {
    568      1.1   cgd 				pti->pt_send |= TIOCPKT_IOCTL;
    569      1.1   cgd 				ptcwakeup(tp, FREAD);
    570      1.1   cgd 			}
    571      1.1   cgd 			tp->t_lflag &= ~EXTPROC;
    572      1.1   cgd 		}
    573      1.1   cgd 		return(0);
    574      1.1   cgd 	} else
    575      1.1   cgd 	if (cdevsw[major(dev)].d_open == ptcopen)
    576      1.1   cgd 		switch (cmd) {
    577      1.1   cgd 
    578      1.1   cgd 		case TIOCGPGRP:
    579      1.1   cgd 			/*
    580      1.1   cgd 			 * We aviod calling ttioctl on the controller since,
    581      1.1   cgd 			 * in that case, tp must be the controlling terminal.
    582      1.1   cgd 			 */
    583      1.1   cgd 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
    584      1.1   cgd 			return (0);
    585      1.1   cgd 
    586      1.1   cgd 		case TIOCPKT:
    587      1.1   cgd 			if (*(int *)data) {
    588      1.1   cgd 				if (pti->pt_flags & PF_UCNTL)
    589      1.1   cgd 					return (EINVAL);
    590      1.1   cgd 				pti->pt_flags |= PF_PKT;
    591      1.1   cgd 			} else
    592      1.1   cgd 				pti->pt_flags &= ~PF_PKT;
    593      1.1   cgd 			return (0);
    594      1.1   cgd 
    595      1.1   cgd 		case TIOCUCNTL:
    596      1.1   cgd 			if (*(int *)data) {
    597      1.1   cgd 				if (pti->pt_flags & PF_PKT)
    598      1.1   cgd 					return (EINVAL);
    599      1.1   cgd 				pti->pt_flags |= PF_UCNTL;
    600      1.1   cgd 			} else
    601      1.1   cgd 				pti->pt_flags &= ~PF_UCNTL;
    602      1.1   cgd 			return (0);
    603      1.1   cgd 
    604      1.1   cgd 		case TIOCREMOTE:
    605      1.1   cgd 			if (*(int *)data)
    606      1.1   cgd 				pti->pt_flags |= PF_REMOTE;
    607      1.1   cgd 			else
    608      1.1   cgd 				pti->pt_flags &= ~PF_REMOTE;
    609      1.1   cgd 			ttyflush(tp, FREAD|FWRITE);
    610      1.1   cgd 			return (0);
    611      1.1   cgd 
    612  1.1.1.2  fvdl #ifdef COMPAT_43
    613      1.1   cgd 		case TIOCSETP:
    614      1.1   cgd 		case TIOCSETN:
    615  1.1.1.2  fvdl #endif
    616      1.1   cgd 		case TIOCSETD:
    617      1.1   cgd 		case TIOCSETA:
    618      1.1   cgd 		case TIOCSETAW:
    619      1.1   cgd 		case TIOCSETAF:
    620  1.1.1.2  fvdl 			ndflush(&tp->t_outq, tp->t_outq.c_cc);
    621      1.1   cgd 			break;
    622      1.1   cgd 
    623      1.1   cgd 		case TIOCSIG:
    624      1.1   cgd 			if (*(unsigned int *)data >= NSIG)
    625      1.1   cgd 				return(EINVAL);
    626      1.1   cgd 			if ((tp->t_lflag&NOFLSH) == 0)
    627      1.1   cgd 				ttyflush(tp, FREAD|FWRITE);
    628      1.1   cgd 			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
    629      1.1   cgd 			if ((*(unsigned int *)data == SIGINFO) &&
    630      1.1   cgd 			    ((tp->t_lflag&NOKERNINFO) == 0))
    631      1.1   cgd 				ttyinfo(tp);
    632      1.1   cgd 			return(0);
    633      1.1   cgd 		}
    634  1.1.1.2  fvdl 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    635      1.1   cgd 	if (error < 0)
    636      1.1   cgd 		 error = ttioctl(tp, cmd, data, flag);
    637      1.1   cgd 	if (error < 0) {
    638      1.1   cgd 		if (pti->pt_flags & PF_UCNTL &&
    639      1.1   cgd 		    (cmd & ~0xff) == UIOCCMD(0)) {
    640      1.1   cgd 			if (cmd & 0xff) {
    641      1.1   cgd 				pti->pt_ucntl = (u_char)cmd;
    642      1.1   cgd 				ptcwakeup(tp, FREAD);
    643      1.1   cgd 			}
    644      1.1   cgd 			return (0);
    645      1.1   cgd 		}
    646      1.1   cgd 		error = ENOTTY;
    647      1.1   cgd 	}
    648      1.1   cgd 	/*
    649      1.1   cgd 	 * If external processing and packet mode send ioctl packet.
    650      1.1   cgd 	 */
    651      1.1   cgd 	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
    652      1.1   cgd 		switch(cmd) {
    653      1.1   cgd 		case TIOCSETA:
    654      1.1   cgd 		case TIOCSETAW:
    655      1.1   cgd 		case TIOCSETAF:
    656  1.1.1.2  fvdl #ifdef COMPAT_43
    657      1.1   cgd 		case TIOCSETP:
    658      1.1   cgd 		case TIOCSETN:
    659  1.1.1.2  fvdl #endif
    660  1.1.1.2  fvdl #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    661      1.1   cgd 		case TIOCSETC:
    662      1.1   cgd 		case TIOCSLTC:
    663      1.1   cgd 		case TIOCLBIS:
    664      1.1   cgd 		case TIOCLBIC:
    665      1.1   cgd 		case TIOCLSET:
    666      1.1   cgd #endif
    667      1.1   cgd 			pti->pt_send |= TIOCPKT_IOCTL;
    668  1.1.1.2  fvdl 			ptcwakeup(tp, FREAD);
    669      1.1   cgd 		default:
    670      1.1   cgd 			break;
    671      1.1   cgd 		}
    672      1.1   cgd 	}
    673      1.1   cgd 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
    674      1.1   cgd 		&& CCEQ(cc[VSTART], CTRL('q'));
    675      1.1   cgd 	if (pti->pt_flags & PF_NOSTOP) {
    676      1.1   cgd 		if (stop) {
    677      1.1   cgd 			pti->pt_send &= ~TIOCPKT_NOSTOP;
    678      1.1   cgd 			pti->pt_send |= TIOCPKT_DOSTOP;
    679      1.1   cgd 			pti->pt_flags &= ~PF_NOSTOP;
    680      1.1   cgd 			ptcwakeup(tp, FREAD);
    681      1.1   cgd 		}
    682      1.1   cgd 	} else {
    683      1.1   cgd 		if (!stop) {
    684      1.1   cgd 			pti->pt_send &= ~TIOCPKT_DOSTOP;
    685      1.1   cgd 			pti->pt_send |= TIOCPKT_NOSTOP;
    686      1.1   cgd 			pti->pt_flags |= PF_NOSTOP;
    687      1.1   cgd 			ptcwakeup(tp, FREAD);
    688      1.1   cgd 		}
    689      1.1   cgd 	}
    690      1.1   cgd 	return (error);
    691      1.1   cgd }
    692