pty.c revision 2807
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 * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)tty_pty.c 8.2 (Berkeley) 9/23/93 342807Sbde * $Id: tty_pty.c,v 1.3 1994/08/02 07:42:51 davidg Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes/* 381541Srgrimes * Pseudo-teletype Driver 391541Srgrimes * (Actually two drivers, requiring two entries in 'cdevsw') 401541Srgrimes */ 411541Srgrimes#include "pty.h" /* XXX */ 421541Srgrimes 431541Srgrimes#include <sys/param.h> 441541Srgrimes#include <sys/systm.h> 451541Srgrimes#include <sys/ioctl.h> 461541Srgrimes#include <sys/proc.h> 471541Srgrimes#include <sys/tty.h> 481541Srgrimes#include <sys/conf.h> 491541Srgrimes#include <sys/file.h> 501541Srgrimes#include <sys/uio.h> 511541Srgrimes#include <sys/kernel.h> 521541Srgrimes#include <sys/vnode.h> 531541Srgrimes 541541Srgrimes#if NPTY == 1 551541Srgrimes#undef NPTY 561541Srgrimes#define NPTY 32 /* crude XXX */ 571541Srgrimes#endif 581541Srgrimes 591541Srgrimes#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 601541Srgrimes 611541Srgrimes/* 621541Srgrimes * pts == /dev/tty[pqrs]? 631541Srgrimes * ptc == /dev/pty[pqrs]? 641541Srgrimes */ 651541Srgrimesstruct tty pt_tty[NPTY]; /* XXX */ 661541Srgrimesstruct pt_ioctl { 671541Srgrimes int pt_flags; 681541Srgrimes struct selinfo pt_selr, pt_selw; 691541Srgrimes u_char pt_send; 701541Srgrimes u_char pt_ucntl; 711541Srgrimes} pt_ioctl[NPTY]; /* XXX */ 721541Srgrimesint npty = NPTY; /* for pstat -t */ 731541Srgrimes 741541Srgrimes#define PF_PKT 0x08 /* packet mode */ 751541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 761541Srgrimes#define PF_REMOTE 0x20 /* remote and flow controlled input */ 771541Srgrimes#define PF_NOSTOP 0x40 781541Srgrimes#define PF_UCNTL 0x80 /* user control mode */ 791541Srgrimes 801549Srgrimesvoid ptsstop __P((struct tty *, int)); 811549Srgrimesvoid ptcwakeup __P((struct tty *, int)); 821541Srgrimes 831541Srgrimes/* 841541Srgrimes * Establish n (or default if n is 1) ptys in the system. 851541Srgrimes * 861541Srgrimes * XXX cdevsw & pstat require the array `pty[]' to be an array 871541Srgrimes */ 881541Srgrimesvoid 891541Srgrimesptyattach(n) 901541Srgrimes int n; 911541Srgrimes{ 921541Srgrimes#ifdef notyet 931541Srgrimes char *mem; 941541Srgrimes register u_long ntb; 951541Srgrimes#define DEFAULT_NPTY 32 961541Srgrimes 971541Srgrimes /* maybe should allow 0 => none? */ 981541Srgrimes if (n <= 1) 991541Srgrimes n = DEFAULT_NPTY; 1001541Srgrimes ntb = n * sizeof(struct tty); 1011541Srgrimes mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), 1021541Srgrimes M_DEVBUF, M_WAITOK); 1031541Srgrimes pt_tty = (struct tty *)mem; 1041541Srgrimes mem = (char *)ALIGN(mem + ntb); 1051541Srgrimes pt_ioctl = (struct pt_ioctl *)mem; 1061541Srgrimes npty = n; 1071541Srgrimes#endif 1081541Srgrimes} 1091541Srgrimes 1101541Srgrimes/*ARGSUSED*/ 1111549Srgrimesint 1121541Srgrimesptsopen(dev, flag, devtype, p) 1131541Srgrimes dev_t dev; 1141541Srgrimes int flag, devtype; 1151541Srgrimes struct proc *p; 1161541Srgrimes{ 1171541Srgrimes register struct tty *tp; 1181541Srgrimes int error; 1191541Srgrimes 1201541Srgrimes if (minor(dev) >= npty) 1211541Srgrimes return (ENXIO); 1221541Srgrimes tp = &pt_tty[minor(dev)]; 1231541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 1241541Srgrimes tp->t_state |= TS_WOPEN; 1251541Srgrimes ttychars(tp); /* Set up default chars */ 1261541Srgrimes tp->t_iflag = TTYDEF_IFLAG; 1271541Srgrimes tp->t_oflag = TTYDEF_OFLAG; 1281541Srgrimes tp->t_lflag = TTYDEF_LFLAG; 1291541Srgrimes tp->t_cflag = TTYDEF_CFLAG; 1301541Srgrimes tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 1311541Srgrimes ttsetwater(tp); /* would be done in xxparam() */ 1321541Srgrimes } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 1331541Srgrimes return (EBUSY); 1341541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 1351541Srgrimes tp->t_state |= TS_CARR_ON; 1361541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1371541Srgrimes tp->t_state |= TS_WOPEN; 1381541Srgrimes if (flag&FNONBLOCK) 1391541Srgrimes break; 1401541Srgrimes if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 1411541Srgrimes ttopen, 0)) 1421541Srgrimes return (error); 1431541Srgrimes } 1441541Srgrimes error = (*linesw[tp->t_line].l_open)(dev, tp); 1451541Srgrimes ptcwakeup(tp, FREAD|FWRITE); 1461541Srgrimes return (error); 1471541Srgrimes} 1481541Srgrimes 1491549Srgrimesint 1501541Srgrimesptsclose(dev, flag, mode, p) 1511541Srgrimes dev_t dev; 1521541Srgrimes int flag, mode; 1531541Srgrimes struct proc *p; 1541541Srgrimes{ 1551541Srgrimes register struct tty *tp; 1561541Srgrimes int err; 1571541Srgrimes 1581541Srgrimes tp = &pt_tty[minor(dev)]; 1591541Srgrimes err = (*linesw[tp->t_line].l_close)(tp, flag); 1601541Srgrimes err |= ttyclose(tp); 1611541Srgrimes ptcwakeup(tp, FREAD|FWRITE); 1621541Srgrimes return (err); 1631541Srgrimes} 1641541Srgrimes 1651549Srgrimesint 1661541Srgrimesptsread(dev, uio, flag) 1671541Srgrimes dev_t dev; 1681541Srgrimes struct uio *uio; 1691541Srgrimes int flag; 1701541Srgrimes{ 1711541Srgrimes struct proc *p = curproc; 1721541Srgrimes register struct tty *tp = &pt_tty[minor(dev)]; 1731541Srgrimes register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 1741541Srgrimes int error = 0; 1751541Srgrimes 1761541Srgrimesagain: 1771541Srgrimes if (pti->pt_flags & PF_REMOTE) { 1781541Srgrimes while (isbackground(p, tp)) { 1791541Srgrimes if ((p->p_sigignore & sigmask(SIGTTIN)) || 1801541Srgrimes (p->p_sigmask & sigmask(SIGTTIN)) || 1811541Srgrimes p->p_pgrp->pg_jobc == 0 || 1821541Srgrimes p->p_flag & P_PPWAIT) 1831541Srgrimes return (EIO); 1841541Srgrimes pgsignal(p->p_pgrp, SIGTTIN, 1); 1851541Srgrimes if (error = ttysleep(tp, (caddr_t)&lbolt, 1861541Srgrimes TTIPRI | PCATCH, ttybg, 0)) 1871541Srgrimes return (error); 1881541Srgrimes } 1891541Srgrimes if (tp->t_canq.c_cc == 0) { 1901541Srgrimes if (flag & IO_NDELAY) 1911541Srgrimes return (EWOULDBLOCK); 1921541Srgrimes if (error = ttysleep(tp, (caddr_t)&tp->t_canq, 1931541Srgrimes TTIPRI | PCATCH, ttyin, 0)) 1941541Srgrimes return (error); 1951541Srgrimes goto again; 1961541Srgrimes } 1971541Srgrimes while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 1981541Srgrimes if (ureadc(getc(&tp->t_canq), uio) < 0) { 1991541Srgrimes error = EFAULT; 2001541Srgrimes break; 2011541Srgrimes } 2021541Srgrimes if (tp->t_canq.c_cc == 1) 2031541Srgrimes (void) getc(&tp->t_canq); 2041541Srgrimes if (tp->t_canq.c_cc) 2051541Srgrimes return (error); 2061541Srgrimes } else 2071541Srgrimes if (tp->t_oproc) 2081541Srgrimes error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 2091541Srgrimes ptcwakeup(tp, FWRITE); 2101541Srgrimes return (error); 2111541Srgrimes} 2121541Srgrimes 2131541Srgrimes/* 2141541Srgrimes * Write to pseudo-tty. 2151541Srgrimes * Wakeups of controlling tty will happen 2161541Srgrimes * indirectly, when tty driver calls ptsstart. 2171541Srgrimes */ 2181549Srgrimesint 2191541Srgrimesptswrite(dev, uio, flag) 2201541Srgrimes dev_t dev; 2211541Srgrimes struct uio *uio; 2221541Srgrimes int flag; 2231541Srgrimes{ 2241541Srgrimes register struct tty *tp; 2251541Srgrimes 2261541Srgrimes tp = &pt_tty[minor(dev)]; 2271541Srgrimes if (tp->t_oproc == 0) 2281541Srgrimes return (EIO); 2291541Srgrimes return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 2301541Srgrimes} 2311541Srgrimes 2321541Srgrimes/* 2331541Srgrimes * Start output on pseudo-tty. 2341541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2351541Srgrimes */ 2361541Srgrimesvoid 2371541Srgrimesptsstart(tp) 2381541Srgrimes struct tty *tp; 2391541Srgrimes{ 2401541Srgrimes register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2411541Srgrimes 2421541Srgrimes if (tp->t_state & TS_TTSTOP) 2431541Srgrimes return; 2441541Srgrimes if (pti->pt_flags & PF_STOPPED) { 2451541Srgrimes pti->pt_flags &= ~PF_STOPPED; 2461541Srgrimes pti->pt_send = TIOCPKT_START; 2471541Srgrimes } 2481541Srgrimes ptcwakeup(tp, FREAD); 2491541Srgrimes} 2501541Srgrimes 2511549Srgrimesvoid 2521541Srgrimesptcwakeup(tp, flag) 2531541Srgrimes struct tty *tp; 2541541Srgrimes int flag; 2551541Srgrimes{ 2561541Srgrimes struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2571541Srgrimes 2581541Srgrimes if (flag & FREAD) { 2591541Srgrimes selwakeup(&pti->pt_selr); 2601541Srgrimes wakeup((caddr_t)&tp->t_outq.c_cf); 2611541Srgrimes } 2621541Srgrimes if (flag & FWRITE) { 2631541Srgrimes selwakeup(&pti->pt_selw); 2641541Srgrimes wakeup((caddr_t)&tp->t_rawq.c_cf); 2651541Srgrimes } 2661541Srgrimes} 2671541Srgrimes 2681541Srgrimes/*ARGSUSED*/ 2691541Srgrimes#ifdef __STDC__ 2701549Srgrimesint 2711541Srgrimesptcopen(dev_t dev, int flag, int devtype, struct proc *p) 2721541Srgrimes#else 2731549Srgrimesint 2741541Srgrimesptcopen(dev, flag, devtype, p) 2751541Srgrimes dev_t dev; 2761541Srgrimes int flag, devtype; 2771541Srgrimes struct proc *p; 2781541Srgrimes#endif 2791541Srgrimes{ 2801541Srgrimes register struct tty *tp; 2811541Srgrimes struct pt_ioctl *pti; 2821541Srgrimes 2831541Srgrimes if (minor(dev) >= npty) 2841541Srgrimes return (ENXIO); 2851541Srgrimes tp = &pt_tty[minor(dev)]; 2861541Srgrimes if (tp->t_oproc) 2871541Srgrimes return (EIO); 2881541Srgrimes tp->t_oproc = ptsstart; 2891541Srgrimes#ifdef sun4c 2901541Srgrimes tp->t_stop = ptsstop; 2911541Srgrimes#endif 2921541Srgrimes (void)(*linesw[tp->t_line].l_modem)(tp, 1); 2931541Srgrimes tp->t_lflag &= ~EXTPROC; 2941541Srgrimes pti = &pt_ioctl[minor(dev)]; 2951541Srgrimes pti->pt_flags = 0; 2961541Srgrimes pti->pt_send = 0; 2971541Srgrimes pti->pt_ucntl = 0; 2981541Srgrimes return (0); 2991541Srgrimes} 3001541Srgrimes 3011549Srgrimesint 3021541Srgrimesptcclose(dev) 3031541Srgrimes dev_t dev; 3041541Srgrimes{ 3051541Srgrimes register struct tty *tp; 3061541Srgrimes 3071541Srgrimes tp = &pt_tty[minor(dev)]; 3081541Srgrimes (void)(*linesw[tp->t_line].l_modem)(tp, 0); 3091541Srgrimes tp->t_state &= ~TS_CARR_ON; 3101541Srgrimes tp->t_oproc = 0; /* mark closed */ 3111541Srgrimes tp->t_session = 0; 3121541Srgrimes return (0); 3131541Srgrimes} 3141541Srgrimes 3151549Srgrimesint 3161541Srgrimesptcread(dev, uio, flag) 3171541Srgrimes dev_t dev; 3181541Srgrimes struct uio *uio; 3191541Srgrimes int flag; 3201541Srgrimes{ 3211541Srgrimes register struct tty *tp = &pt_tty[minor(dev)]; 3221541Srgrimes struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3231541Srgrimes char buf[BUFSIZ]; 3241541Srgrimes int error = 0, cc; 3251541Srgrimes 3261541Srgrimes /* 3271541Srgrimes * We want to block until the slave 3281541Srgrimes * is open, and there's something to read; 3291541Srgrimes * but if we lost the slave or we're NBIO, 3301541Srgrimes * then return the appropriate error instead. 3311541Srgrimes */ 3321541Srgrimes for (;;) { 3331541Srgrimes if (tp->t_state&TS_ISOPEN) { 3341541Srgrimes if (pti->pt_flags&PF_PKT && pti->pt_send) { 3351541Srgrimes error = ureadc((int)pti->pt_send, uio); 3361541Srgrimes if (error) 3371541Srgrimes return (error); 3381541Srgrimes if (pti->pt_send & TIOCPKT_IOCTL) { 3391541Srgrimes cc = min(uio->uio_resid, 3401541Srgrimes sizeof(tp->t_termios)); 3412807Sbde uiomove((caddr_t)&tp->t_termios, cc, 3422807Sbde uio); 3431541Srgrimes } 3441541Srgrimes pti->pt_send = 0; 3451541Srgrimes return (0); 3461541Srgrimes } 3471541Srgrimes if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 3481541Srgrimes error = ureadc((int)pti->pt_ucntl, uio); 3491541Srgrimes if (error) 3501541Srgrimes return (error); 3511541Srgrimes pti->pt_ucntl = 0; 3521541Srgrimes return (0); 3531541Srgrimes } 3541541Srgrimes if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 3551541Srgrimes break; 3561541Srgrimes } 3571541Srgrimes if ((tp->t_state&TS_CARR_ON) == 0) 3581541Srgrimes return (0); /* EOF */ 3591541Srgrimes if (flag & IO_NDELAY) 3601541Srgrimes return (EWOULDBLOCK); 3611541Srgrimes if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH, 3621541Srgrimes ttyin, 0)) 3631541Srgrimes return (error); 3641541Srgrimes } 3651541Srgrimes if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 3661541Srgrimes error = ureadc(0, uio); 3671541Srgrimes while (uio->uio_resid > 0 && error == 0) { 3681541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 3691541Srgrimes if (cc <= 0) 3701541Srgrimes break; 3711541Srgrimes error = uiomove(buf, cc, uio); 3721541Srgrimes } 3731541Srgrimes if (tp->t_outq.c_cc <= tp->t_lowat) { 3741541Srgrimes if (tp->t_state&TS_ASLEEP) { 3751541Srgrimes tp->t_state &= ~TS_ASLEEP; 3761541Srgrimes wakeup((caddr_t)&tp->t_outq); 3771541Srgrimes } 3781541Srgrimes selwakeup(&tp->t_wsel); 3791541Srgrimes } 3801541Srgrimes return (error); 3811541Srgrimes} 3821541Srgrimes 3831541Srgrimesvoid 3841541Srgrimesptsstop(tp, flush) 3851541Srgrimes register struct tty *tp; 3861541Srgrimes int flush; 3871541Srgrimes{ 3881541Srgrimes struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 3891541Srgrimes int flag; 3901541Srgrimes 3911541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 3921541Srgrimes if (flush == 0) { 3931541Srgrimes flush = TIOCPKT_STOP; 3941541Srgrimes pti->pt_flags |= PF_STOPPED; 3951541Srgrimes } else 3961541Srgrimes pti->pt_flags &= ~PF_STOPPED; 3971541Srgrimes pti->pt_send |= flush; 3981541Srgrimes /* change of perspective */ 3991541Srgrimes flag = 0; 4001541Srgrimes if (flush & FREAD) 4011541Srgrimes flag |= FWRITE; 4021541Srgrimes if (flush & FWRITE) 4031541Srgrimes flag |= FREAD; 4041541Srgrimes ptcwakeup(tp, flag); 4051541Srgrimes} 4061541Srgrimes 4071549Srgrimesint 4081541Srgrimesptcselect(dev, rw, p) 4091541Srgrimes dev_t dev; 4101541Srgrimes int rw; 4111541Srgrimes struct proc *p; 4121541Srgrimes{ 4131541Srgrimes register struct tty *tp = &pt_tty[minor(dev)]; 4141541Srgrimes struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4151541Srgrimes int s; 4161541Srgrimes 4171541Srgrimes if ((tp->t_state&TS_CARR_ON) == 0) 4181541Srgrimes return (1); 4191541Srgrimes switch (rw) { 4201541Srgrimes 4211541Srgrimes case FREAD: 4221541Srgrimes /* 4231541Srgrimes * Need to block timeouts (ttrstart). 4241541Srgrimes */ 4251541Srgrimes s = spltty(); 4261541Srgrimes if ((tp->t_state&TS_ISOPEN) && 4271541Srgrimes tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 4281541Srgrimes splx(s); 4291541Srgrimes return (1); 4301541Srgrimes } 4311541Srgrimes splx(s); 4321541Srgrimes /* FALLTHROUGH */ 4331541Srgrimes 4341541Srgrimes case 0: /* exceptional */ 4351541Srgrimes if ((tp->t_state&TS_ISOPEN) && 4361541Srgrimes (pti->pt_flags&PF_PKT && pti->pt_send || 4371541Srgrimes pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) 4381541Srgrimes return (1); 4391541Srgrimes selrecord(p, &pti->pt_selr); 4401541Srgrimes break; 4411541Srgrimes 4421541Srgrimes 4431541Srgrimes case FWRITE: 4441541Srgrimes if (tp->t_state&TS_ISOPEN) { 4451541Srgrimes if (pti->pt_flags & PF_REMOTE) { 4461541Srgrimes if (tp->t_canq.c_cc == 0) 4471541Srgrimes return (1); 4481541Srgrimes } else { 4491541Srgrimes if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 4501541Srgrimes return (1); 4511541Srgrimes if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 4521541Srgrimes return (1); 4531541Srgrimes } 4541541Srgrimes } 4551541Srgrimes selrecord(p, &pti->pt_selw); 4561541Srgrimes break; 4571541Srgrimes 4581541Srgrimes } 4591541Srgrimes return (0); 4601541Srgrimes} 4611541Srgrimes 4621549Srgrimesint 4631541Srgrimesptcwrite(dev, uio, flag) 4641541Srgrimes dev_t dev; 4651541Srgrimes register struct uio *uio; 4661541Srgrimes int flag; 4671541Srgrimes{ 4681541Srgrimes register struct tty *tp = &pt_tty[minor(dev)]; 4691549Srgrimes register u_char *cp = 0; 4701541Srgrimes register int cc = 0; 4711541Srgrimes u_char locbuf[BUFSIZ]; 4721541Srgrimes int cnt = 0; 4731541Srgrimes struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4741541Srgrimes int error = 0; 4751541Srgrimes 4761541Srgrimesagain: 4771541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4781541Srgrimes goto block; 4791541Srgrimes if (pti->pt_flags & PF_REMOTE) { 4801541Srgrimes if (tp->t_canq.c_cc) 4811541Srgrimes goto block; 4821541Srgrimes while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 4831541Srgrimes if (cc == 0) { 4841541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 4851541Srgrimes cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); 4861541Srgrimes cp = locbuf; 4871541Srgrimes error = uiomove((caddr_t)cp, cc, uio); 4881541Srgrimes if (error) 4891541Srgrimes return (error); 4901541Srgrimes /* check again for safety */ 4911541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4921541Srgrimes return (EIO); 4931541Srgrimes } 4941541Srgrimes if (cc) 4951541Srgrimes (void) b_to_q((char *)cp, cc, &tp->t_canq); 4961541Srgrimes cc = 0; 4971541Srgrimes } 4981541Srgrimes (void) putc(0, &tp->t_canq); 4991541Srgrimes ttwakeup(tp); 5001541Srgrimes wakeup((caddr_t)&tp->t_canq); 5011541Srgrimes return (0); 5021541Srgrimes } 5031541Srgrimes while (uio->uio_resid > 0) { 5041541Srgrimes if (cc == 0) { 5051541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 5061541Srgrimes cp = locbuf; 5071541Srgrimes error = uiomove((caddr_t)cp, cc, uio); 5081541Srgrimes if (error) 5091541Srgrimes return (error); 5101541Srgrimes /* check again for safety */ 5111541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 5121541Srgrimes return (EIO); 5131541Srgrimes } 5141541Srgrimes while (cc > 0) { 5151541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 5161541Srgrimes (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 5171541Srgrimes wakeup((caddr_t)&tp->t_rawq); 5181541Srgrimes goto block; 5191541Srgrimes } 5201541Srgrimes (*linesw[tp->t_line].l_rint)(*cp++, tp); 5211541Srgrimes cnt++; 5221541Srgrimes cc--; 5231541Srgrimes } 5241541Srgrimes cc = 0; 5251541Srgrimes } 5261541Srgrimes return (0); 5271541Srgrimesblock: 5281541Srgrimes /* 5291541Srgrimes * Come here to wait for slave to open, for space 5301541Srgrimes * in outq, or space in rawq. 5311541Srgrimes */ 5321541Srgrimes if ((tp->t_state&TS_CARR_ON) == 0) 5331541Srgrimes return (EIO); 5341541Srgrimes if (flag & IO_NDELAY) { 5351541Srgrimes /* adjust for data copied in but not written */ 5361541Srgrimes uio->uio_resid += cc; 5371541Srgrimes if (cnt == 0) 5381541Srgrimes return (EWOULDBLOCK); 5391541Srgrimes return (0); 5401541Srgrimes } 5411541Srgrimes if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH, 5421541Srgrimes ttyout, 0)) { 5431541Srgrimes /* adjust for data copied in but not written */ 5441541Srgrimes uio->uio_resid += cc; 5451541Srgrimes return (error); 5461541Srgrimes } 5471541Srgrimes goto again; 5481541Srgrimes} 5491541Srgrimes 5501541Srgrimes/*ARGSUSED*/ 5511549Srgrimesint 5521541Srgrimesptyioctl(dev, cmd, data, flag, p) 5531541Srgrimes dev_t dev; 5541541Srgrimes int cmd; 5551541Srgrimes caddr_t data; 5561541Srgrimes int flag; 5571541Srgrimes struct proc *p; 5581541Srgrimes{ 5591541Srgrimes register struct tty *tp = &pt_tty[minor(dev)]; 5601541Srgrimes register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 5611541Srgrimes register u_char *cc = tp->t_cc; 5621541Srgrimes int stop, error; 5631541Srgrimes 5641541Srgrimes /* 5651541Srgrimes * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 5661541Srgrimes * ttywflush(tp) will hang if there are characters in the outq. 5671541Srgrimes */ 5681541Srgrimes if (cmd == TIOCEXT) { 5691541Srgrimes /* 5701541Srgrimes * When the EXTPROC bit is being toggled, we need 5711541Srgrimes * to send an TIOCPKT_IOCTL if the packet driver 5721541Srgrimes * is turned on. 5731541Srgrimes */ 5741541Srgrimes if (*(int *)data) { 5751541Srgrimes if (pti->pt_flags & PF_PKT) { 5761541Srgrimes pti->pt_send |= TIOCPKT_IOCTL; 5771541Srgrimes ptcwakeup(tp, FREAD); 5781541Srgrimes } 5791541Srgrimes tp->t_lflag |= EXTPROC; 5801541Srgrimes } else { 5811541Srgrimes if ((tp->t_state & EXTPROC) && 5821541Srgrimes (pti->pt_flags & PF_PKT)) { 5831541Srgrimes pti->pt_send |= TIOCPKT_IOCTL; 5841541Srgrimes ptcwakeup(tp, FREAD); 5851541Srgrimes } 5861541Srgrimes tp->t_lflag &= ~EXTPROC; 5871541Srgrimes } 5881541Srgrimes return(0); 5891541Srgrimes } else 5901541Srgrimes if (cdevsw[major(dev)].d_open == ptcopen) 5911541Srgrimes switch (cmd) { 5921541Srgrimes 5931541Srgrimes case TIOCGPGRP: 5941541Srgrimes /* 5951541Srgrimes * We aviod calling ttioctl on the controller since, 5961541Srgrimes * in that case, tp must be the controlling terminal. 5971541Srgrimes */ 5981541Srgrimes *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 5991541Srgrimes return (0); 6001541Srgrimes 6011541Srgrimes case TIOCPKT: 6021541Srgrimes if (*(int *)data) { 6031541Srgrimes if (pti->pt_flags & PF_UCNTL) 6041541Srgrimes return (EINVAL); 6051541Srgrimes pti->pt_flags |= PF_PKT; 6061541Srgrimes } else 6071541Srgrimes pti->pt_flags &= ~PF_PKT; 6081541Srgrimes return (0); 6091541Srgrimes 6101541Srgrimes case TIOCUCNTL: 6111541Srgrimes if (*(int *)data) { 6121541Srgrimes if (pti->pt_flags & PF_PKT) 6131541Srgrimes return (EINVAL); 6141541Srgrimes pti->pt_flags |= PF_UCNTL; 6151541Srgrimes } else 6161541Srgrimes pti->pt_flags &= ~PF_UCNTL; 6171541Srgrimes return (0); 6181541Srgrimes 6191541Srgrimes case TIOCREMOTE: 6201541Srgrimes if (*(int *)data) 6211541Srgrimes pti->pt_flags |= PF_REMOTE; 6221541Srgrimes else 6231541Srgrimes pti->pt_flags &= ~PF_REMOTE; 6241541Srgrimes ttyflush(tp, FREAD|FWRITE); 6251541Srgrimes return (0); 6261541Srgrimes 6271541Srgrimes#ifdef COMPAT_43 6281541Srgrimes case TIOCSETP: 6291541Srgrimes case TIOCSETN: 6301541Srgrimes#endif 6311541Srgrimes case TIOCSETD: 6321541Srgrimes case TIOCSETA: 6331541Srgrimes case TIOCSETAW: 6341541Srgrimes case TIOCSETAF: 6351541Srgrimes ndflush(&tp->t_outq, tp->t_outq.c_cc); 6361541Srgrimes break; 6371541Srgrimes 6381541Srgrimes case TIOCSIG: 6391541Srgrimes if (*(unsigned int *)data >= NSIG) 6401541Srgrimes return(EINVAL); 6411541Srgrimes if ((tp->t_lflag&NOFLSH) == 0) 6421541Srgrimes ttyflush(tp, FREAD|FWRITE); 6431541Srgrimes pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 6441541Srgrimes if ((*(unsigned int *)data == SIGINFO) && 6451541Srgrimes ((tp->t_lflag&NOKERNINFO) == 0)) 6461541Srgrimes ttyinfo(tp); 6471541Srgrimes return(0); 6481541Srgrimes } 6491541Srgrimes error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 6501541Srgrimes if (error < 0) 6511541Srgrimes error = ttioctl(tp, cmd, data, flag); 6521541Srgrimes if (error < 0) { 6531541Srgrimes if (pti->pt_flags & PF_UCNTL && 6541541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 6551541Srgrimes if (cmd & 0xff) { 6561541Srgrimes pti->pt_ucntl = (u_char)cmd; 6571541Srgrimes ptcwakeup(tp, FREAD); 6581541Srgrimes } 6591541Srgrimes return (0); 6601541Srgrimes } 6611541Srgrimes error = ENOTTY; 6621541Srgrimes } 6631541Srgrimes /* 6641541Srgrimes * If external processing and packet mode send ioctl packet. 6651541Srgrimes */ 6661541Srgrimes if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 6671541Srgrimes switch(cmd) { 6681541Srgrimes case TIOCSETA: 6691541Srgrimes case TIOCSETAW: 6701541Srgrimes case TIOCSETAF: 6711541Srgrimes#ifdef COMPAT_43 6721541Srgrimes case TIOCSETP: 6731541Srgrimes case TIOCSETN: 6741541Srgrimes#endif 6751541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 6761541Srgrimes case TIOCSETC: 6771541Srgrimes case TIOCSLTC: 6781541Srgrimes case TIOCLBIS: 6791541Srgrimes case TIOCLBIC: 6801541Srgrimes case TIOCLSET: 6811541Srgrimes#endif 6821541Srgrimes pti->pt_send |= TIOCPKT_IOCTL; 6831541Srgrimes ptcwakeup(tp, FREAD); 6841541Srgrimes default: 6851541Srgrimes break; 6861541Srgrimes } 6871541Srgrimes } 6881541Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 6891541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 6901541Srgrimes if (pti->pt_flags & PF_NOSTOP) { 6911541Srgrimes if (stop) { 6921541Srgrimes pti->pt_send &= ~TIOCPKT_NOSTOP; 6931541Srgrimes pti->pt_send |= TIOCPKT_DOSTOP; 6941541Srgrimes pti->pt_flags &= ~PF_NOSTOP; 6951541Srgrimes ptcwakeup(tp, FREAD); 6961541Srgrimes } 6971541Srgrimes } else { 6981541Srgrimes if (!stop) { 6991541Srgrimes pti->pt_send &= ~TIOCPKT_DOSTOP; 7001541Srgrimes pti->pt_send |= TIOCPKT_NOSTOP; 7011541Srgrimes pti->pt_flags |= PF_NOSTOP; 7021541Srgrimes ptcwakeup(tp, FREAD); 7031541Srgrimes } 7041541Srgrimes } 7051541Srgrimes return (error); 7061541Srgrimes} 707