-/* tty_pty.c 6.5 84/07/29 */
+/*
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ * @(#)tty_pty.c 7.19 (Berkeley) %G%
+ */
/*
* Pseudo-teletype Driver
#include "pty.h"
#if NPTY > 0
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/ioctl.h"
-#include "../h/tty.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/conf.h"
-#include "../h/file.h"
-#include "../h/proc.h"
-#include "../h/uio.h"
-#include "../h/kernel.h"
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "vnode.h"
+#include "tsleep.h"
#if NPTY == 1
-#undef NPTY
+#undef NPTY
#define NPTY 32 /* crude XXX */
#endif
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
/*
- * pts == /dev/tty[pP]?
- * ptc == /dev/ptp[pP]?
+ * pts == /dev/tty[pqrs]?
+ * ptc == /dev/pty[pqrs]?
*/
struct tty pt_tty[NPTY];
struct pt_ioctl {
int pt_flags;
- int pt_gensym;
struct proc *pt_selr, *pt_selw;
- int pt_send;
+ u_char pt_send;
+ u_char pt_ucntl;
+ struct clist pt_ioc;
} pt_ioctl[NPTY];
-
-#define PF_RCOLL 0x01
-#define PF_WCOLL 0x02
-#define PF_NBIO 0x04
-#define PF_PKT 0x08 /* packet mode */
-#define PF_STOPPED 0x10 /* user told stopped */
-#define PF_REMOTE 0x20 /* remote and flow controlled input */
-#define PF_NOSTOP 0x40
+int npty = NPTY; /* for pstat -t */
+
+#define PF_RCOLL 0x0001
+#define PF_WCOLL 0x0002
+#define PF_NBIO 0x0004
+#define PF_PKT 0x0008 /* packet mode */
+#define PF_STOPPED 0x0010 /* user told stopped */
+#define PF_REMOTE 0x0020 /* remote and flow controlled input */
+#define PF_NOSTOP 0x0040
+#define PF_UCNTL 0x0080 /* user control mode */
+#define PF_TIOC 0x0100 /* transparent control mode */
+#define PF_LIOC 0x0200 /* transparent control locked */
+#define PF_WIOC 0x0400 /* waiting for PF_LIOC to clear */
+#define PF_BLOCK 0x0800 /* block writes to slave */
+#define PF_OWAIT 0x1000 /* waiting for PF_BLOCK to clear */
/*ARGSUSED*/
-ptsopen(dev, flag)
+ptsopen(dev, flag, devtype, p)
dev_t dev;
+ struct proc *p;
{
register struct tty *tp;
+ int error;
+#ifdef lint
+ npty = npty;
+#endif
if (minor(dev) >= NPTY)
return (ENXIO);
tp = &pt_tty[minor(dev)];
if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
ttychars(tp); /* Set up default chars */
- tp->t_ispeed = tp->t_ospeed = EXTB;
- tp->t_flags = 0; /* No features (nor raw mode) */
- } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ ttsetwater(tp); /* would be done in xxparam() */
+ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
return (EBUSY);
if (tp->t_oproc) /* Ctrlr still around. */
tp->t_state |= TS_CARR_ON;
while ((tp->t_state & TS_CARR_ON) == 0) {
tp->t_state |= TS_WOPEN;
- sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ if (flag&FNDELAY)
+ break;
+ if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0))
+ return (error);
}
- return ((*linesw[tp->t_line].l_open)(dev, tp));
+ error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
+ ptcwakeup(tp, FREAD|FWRITE);
+ return (error);
}
ptsclose(dev)
tp = &pt_tty[minor(dev)];
(*linesw[tp->t_line].l_close)(tp);
ttyclose(tp);
- ptcwakeup(tp);
+ ptcwakeup(tp, FREAD|FWRITE);
+ return (0);
}
-ptsread(dev, uio)
+ptsread(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
+ struct proc *p = curproc;
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
again:
if (pti->pt_flags & PF_REMOTE) {
- while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
-#define bit(a) (1<<(a-1))
- if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
- (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
- /*
- (u.u_procp->p_flag&SDETACH) ||
- */
- u.u_procp->p_flag&SVFORK)
+ while (isbackground(p, tp)) {
+ if ((p->p_sigignore & sigmask(SIGTTIN)) ||
+ (p->p_sigmask & sigmask(SIGTTIN)) ||
+ p->p_pgrp->pg_jobc == 0 ||
+ p->p_flag&SPPWAIT)
return (EIO);
- gsignal(u.u_procp->p_pgrp, SIGTTIN);
- sleep((caddr_t)&lbolt, TTIPRI);
+ pgsignal(p->p_pgrp, SIGTTIN, 1);
+ if (error = ttysleep(tp, (caddr_t)&lbolt,
+ TTIPRI | PCATCH, ttybg, 0))
+ return (error);
}
-#undef bit
- if (tp->t_rawq.c_cc == 0) {
- if (tp->t_state & TS_NBIO)
+ if (tp->t_canq.c_cc == 0) {
+ if (flag & IO_NDELAY)
return (EWOULDBLOCK);
- sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
+ TTIPRI | PCATCH, ttyin, 0))
+ return (error);
goto again;
}
- while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
- if (ureadc(getc(&tp->t_rawq), uio) < 0) {
+ while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
+ if (ureadc(getc(&tp->t_canq), uio) < 0) {
error = EFAULT;
break;
}
- if (tp->t_rawq.c_cc == 1)
- (void) getc(&tp->t_rawq);
- if (tp->t_rawq.c_cc)
+ if (tp->t_canq.c_cc == 1)
+ (void) getc(&tp->t_canq);
+ if (tp->t_canq.c_cc)
return (error);
} else
if (tp->t_oproc)
- error = (*linesw[tp->t_line].l_read)(tp, uio);
- wakeup((caddr_t)&tp->t_rawq.c_cf);
- if (pti->pt_selw) {
- selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
- pti->pt_selw = 0;
- pti->pt_flags &= ~PF_WCOLL;
- }
+ error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
+ ptcwakeup(tp, FWRITE);
return (error);
}
* Wakeups of controlling tty will happen
* indirectly, when tty driver calls ptsstart.
*/
-ptswrite(dev, uio)
+ptswrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
- register struct tty *tp;
+ register struct tty *tp = &pt_tty[minor(dev)];
+ register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
- tp = &pt_tty[minor(dev)];
if (tp->t_oproc == 0)
return (EIO);
- return ((*linesw[tp->t_line].l_write)(tp, uio));
+
+ while (pti->pt_flags & PF_BLOCK) {
+ pti->pt_flags |= PF_OWAIT;
+ sleep((caddr_t)pti + 1, TTOPRI);
+ }
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}
/*
pti->pt_flags &= ~PF_STOPPED;
pti->pt_send = TIOCPKT_START;
}
- ptcwakeup(tp);
+ ptcwakeup(tp, FREAD);
}
-ptcwakeup(tp)
+ptcwakeup(tp, flag)
struct tty *tp;
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
- if (pti->pt_selr) {
- selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
- pti->pt_selr = 0;
- pti->pt_flags &= ~PF_RCOLL;
+ if (flag & FREAD) {
+ if (pti->pt_selr) {
+ selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
+ pti->pt_selr = 0;
+ pti->pt_flags &= ~PF_RCOLL;
+ }
+ wakeup((caddr_t)&tp->t_outq.c_cf);
+ }
+ if (flag & FWRITE) {
+ if (pti->pt_selw) {
+ selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
+ pti->pt_selw = 0;
+ pti->pt_flags &= ~PF_WCOLL;
+ }
+ wakeup((caddr_t)&tp->t_rawq.c_cf);
}
- wakeup((caddr_t)&tp->t_outq.c_cf);
}
/*ARGSUSED*/
-ptcopen(dev, flag)
+#ifdef __STDC__
+ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
+#else
+ptcopen(dev, flag, devtype, p)
dev_t dev;
- int flag;
+ int flag, devtype;
+ struct proc *p;
+#endif
{
register struct tty *tp;
struct pt_ioctl *pti;
if (tp->t_oproc)
return (EIO);
tp->t_oproc = ptsstart;
- if (tp->t_state & TS_WOPEN)
- wakeup((caddr_t)&tp->t_rawq);
- tp->t_state |= TS_CARR_ON;
+ (void)(*linesw[tp->t_line].l_modem)(tp, 1);
+ tp->t_lflag &= ~EXTPROC;
pti = &pt_ioctl[minor(dev)];
pti->pt_flags = 0;
pti->pt_send = 0;
+ pti->pt_ucntl = 0;
return (0);
}
register struct tty *tp;
tp = &pt_tty[minor(dev)];
- if (tp->t_state & TS_ISOPEN)
- gsignal(tp->t_pgrp, SIGHUP);
- tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */
- ttyflush(tp, FREAD|FWRITE);
+ (void)(*linesw[tp->t_line].l_modem)(tp, 0);
+ tp->t_state &= ~TS_CARR_ON;
tp->t_oproc = 0; /* mark closed */
+ tp->t_session = 0;
+ return (0);
}
-ptcread(dev, uio)
+ptcread(dev, uio, flag)
dev_t dev;
struct uio *uio;
{
register struct tty *tp = &pt_tty[minor(dev)];
- struct pt_ioctl *pti;
+ struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
char buf[BUFSIZ];
int error = 0, cc;
- if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
- return (EIO);
- pti = &pt_ioctl[minor(dev)];
- if (pti->pt_flags & PF_PKT) {
- if (pti->pt_send) {
- error = ureadc(pti->pt_send, uio);
- if (error)
+ /*
+ * We want to block until the slave
+ * is open, and there's something to read;
+ * but if we lost the slave or we're NBIO,
+ * then return the appropriate error instead.
+ */
+ for (;;) {
+ if (tp->t_state&TS_ISOPEN) {
+ if (pti->pt_flags&PF_PKT && pti->pt_send) {
+ error = ureadc((int)pti->pt_send, uio);
+ if (error)
+ return (error);
+ if (pti->pt_send & TIOCPKT_IOCTL) {
+ cc = MIN(uio->uio_resid,
+ sizeof(tp->t_termios));
+ uiomove(&tp->t_termios, cc, uio);
+ }
+ pti->pt_send = 0;
+ return (0);
+ }
+ if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
+ error = ureadc((int)pti->pt_ucntl, uio);
+ if (error)
+ return (error);
+ pti->pt_ucntl = 0;
+ return (0);
+ }
+ if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) {
+ if (uio->uio_resid < pti->pt_ioc.c_cc + 1)
+ return (E2BIG);
+ error = ureadc(TIOCPKT_TIOC, uio);
+ while (error == 0 && pti->pt_ioc.c_cc > 0) {
+ cc = q_to_b(&pti->pt_ioc, buf,
+ MIN(pti->pt_ioc.c_cc, BUFSIZ));
+ if (cc <= 0) /* impossible? */
+ break;
+ error = uiomove(buf, cc, UIO_READ, uio);
+ }
return (error);
- pti->pt_send = 0;
- return (0);
+ }
+ if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
+ break;
}
- error = ureadc(0, uio);
- }
- while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
if ((tp->t_state&TS_CARR_ON) == 0)
- return (EIO);
- if (pti->pt_flags&PF_NBIO)
+ return (0); /* EOF */
+ if (flag & IO_NDELAY)
return (EWOULDBLOCK);
- sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
+ if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
+ ttyin, 0))
+ return (error);
}
+ if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC))
+ error = ureadc(0, uio);
while (uio->uio_resid > 0 && error == 0) {
cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
if (cc <= 0)
break;
- error = uiomove(buf, cc, UIO_READ, uio);
- }
- if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
- if (tp->t_state&TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup((caddr_t)&tp->t_outq);
- }
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
+ error = uiomove(buf, cc, uio);
}
+ if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK))
+ ptswake(tp);
return (error);
}
+ptswake(tp)
+ register struct tty *tp;
+{
+ if (tp->t_state&TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+}
+
ptsstop(tp, flush)
register struct tty *tp;
int flush;
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
+ int flag;
/* note: FLUSHREAD and FLUSHWRITE already ok */
if (flush == 0) {
flush = TIOCPKT_STOP;
pti->pt_flags |= PF_STOPPED;
- } else {
+ } else
pti->pt_flags &= ~PF_STOPPED;
- }
pti->pt_send |= flush;
- ptcwakeup(tp);
+ /* change of perspective */
+ flag = 0;
+ if (flush & FREAD)
+ flag |= FWRITE;
+ if (flush & FWRITE)
+ flag |= FREAD;
+ ptcwakeup(tp, flag);
}
-ptcselect(dev, rw)
+ptcselect(dev, rw, p)
dev_t dev;
int rw;
+ struct proc *p;
{
register struct tty *tp = &pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
- struct proc *p;
+ struct proc *prev;
int s;
- if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
+ if ((tp->t_state&TS_CARR_ON) == 0)
return (1);
- s = spl5();
switch (rw) {
case FREAD:
- if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
+ /*
+ * Need to block timeouts (ttrstart).
+ */
+ s = spltty();
+ if ((tp->t_state&TS_ISOPEN) &&
+ tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
splx(s);
return (1);
}
- if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
+ splx(s);
+ /* FALLTHROUGH */
+
+ case 0: /* exceptional */
+ if ((tp->t_state&TS_ISOPEN) &&
+ (pti->pt_flags&PF_PKT && pti->pt_send ||
+ pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc ||
+ pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
+ return (1);
+ if ((prev = pti->pt_selr) && prev->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_RCOLL;
else
- pti->pt_selr = u.u_procp;
+ pti->pt_selr = p;
break;
+
case FWRITE:
- if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
- splx(s);
- return (1);
+ if (tp->t_state&TS_ISOPEN) {
+ if (pti->pt_flags & PF_REMOTE) {
+ if (tp->t_canq.c_cc == 0)
+ return (1);
+ } else {
+ if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
+ return (1);
+ if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
+ return (1);
+ }
}
- if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
+ if ((prev = pti->pt_selw) && prev->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_WCOLL;
else
- pti->pt_selw = u.u_procp;
+ pti->pt_selw = p;
break;
+
}
- splx(s);
return (0);
}
-ptcwrite(dev, uio)
+ptcwrite(dev, uio, flag)
dev_t dev;
- struct uio *uio;
+ register struct uio *uio;
{
register struct tty *tp = &pt_tty[minor(dev)];
- register char *cp, *ce;
- register int cc;
- char locbuf[BUFSIZ];
+ register u_char *cp;
+ register int cc = 0;
+ u_char locbuf[BUFSIZ];
int cnt = 0;
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
- if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
- return (EIO);
- do {
- register struct iovec *iov;
-
- if (uio->uio_iovcnt == 0)
- break;
- iov = uio->uio_iov;
- if (iov->iov_len == 0) {
- while (pti->pt_flags&PF_REMOTE && tp->t_rawq.c_cc != 0)
- sleep((caddr_t)&tp->t_rawq.c_cf, TTIPRI);
- if (pti->pt_flags&PF_REMOTE) {
- (void) putc(0, &tp->t_rawq);
- wakeup((caddr_t)&tp->t_rawq);
- }
- uio->uio_iovcnt--;
- uio->uio_iov++;
- if (uio->uio_iovcnt < 0)
- panic("ptcwrite");
- continue;
- }
- cc = MIN(iov->iov_len, BUFSIZ);
- cp = locbuf;
- error = uiomove(cp, cc, UIO_WRITE, uio);
- if (error)
- break;
- ce = cp + cc;
again:
- if (pti->pt_flags & PF_REMOTE) {
- if (tp->t_rawq.c_cc) {
- if (pti->pt_flags & PF_NBIO) {
- iov->iov_base -= ce - cp;
- iov->iov_len += ce - cp;
- uio->uio_resid += ce - cp;
- uio->uio_offset -= ce - cp;
- return (EWOULDBLOCK);
- }
- sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
- goto again;
+ if ((tp->t_state&TS_ISOPEN) == 0)
+ goto block;
+ if (pti->pt_flags & PF_REMOTE) {
+ if (tp->t_canq.c_cc)
+ goto block;
+ while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
+ if (cc == 0) {
+ cc = min(uio->uio_resid, BUFSIZ);
+ cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
+ cp = locbuf;
+ error = uiomove((caddr_t)cp, cc, uio);
+ if (error)
+ return (error);
+ /* check again for safety */
+ if ((tp->t_state&TS_ISOPEN) == 0)
+ return (EIO);
}
- (void) b_to_q(cp, cc, &tp->t_rawq);
- (void) putc(0, &tp->t_rawq);
- wakeup((caddr_t)&tp->t_rawq);
- return (0);
+ if (cc)
+ (void) b_to_q((char *)cp, cc, &tp->t_canq);
+ cc = 0;
+ }
+ (void) putc(0, &tp->t_canq);
+ ttwakeup(tp);
+ wakeup((caddr_t)&tp->t_canq);
+ return (0);
+ }
+ while (uio->uio_resid > 0) {
+ if (cc == 0) {
+ cc = min(uio->uio_resid, BUFSIZ);
+ cp = locbuf;
+ error = uiomove((caddr_t)cp, cc, uio);
+ if (error)
+ return (error);
+ /* check again for safety */
+ if ((tp->t_state&TS_ISOPEN) == 0)
+ return (EIO);
}
- while (cp < ce) {
+ while (cc > 0) {
if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
- (tp->t_canq.c_cc > 0)) {
+ (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
wakeup((caddr_t)&tp->t_rawq);
- if (tp->t_state & TS_NBIO) {
- iov->iov_base -= ce - cp;
- iov->iov_len += ce - cp;
- uio->uio_resid += ce - cp;
- uio->uio_offset -= ce - cp;
- if (cnt == 0)
- return (EWOULDBLOCK);
- return (0);
- }
- /* Better than just flushing it! */
- /* Wait for something to be read */
- sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
- goto again;
+ goto block;
}
(*linesw[tp->t_line].l_rint)(*cp++, tp);
cnt++;
+ cc--;
}
- } while (uio->uio_resid);
- return (error);
+ cc = 0;
+ }
+ return (0);
+block:
+ /*
+ * Come here to wait for slave to open, for space
+ * in outq, or space in rawq.
+ */
+ if ((tp->t_state&TS_CARR_ON) == 0)
+ return (EIO);
+ if (flag & IO_NDELAY) {
+ /* adjust for data copied in but not written */
+ uio->uio_resid += cc;
+ if (cnt == 0)
+ return (EWOULDBLOCK);
+ return (0);
+ }
+ if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
+ ttyout, 0)) {
+ /* adjust for data copied in but not written */
+ uio->uio_resid += cc;
+ return (error);
+ }
+ goto again;
}
/*ARGSUSED*/
{
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
- int error;
+ register u_char *cc = tp->t_cc;
+ int stop, error;
+ extern ttyinput();
- /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
- if (cdevsw[major(dev)].d_open == ptcopen)
+ /*
+ * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
+ * ttywflush(tp) will hang if there are characters in the outq.
+ */
+ if (cmd == TIOCEXT) {
+ /*
+ * When the EXTPROC bit is being toggled, we need
+ * to send an TIOCPKT_IOCTL if the packet driver
+ * is turned on.
+ */
+ if (*(int *)data) {
+ if (pti->pt_flags & PF_PKT) {
+ pti->pt_send |= TIOCPKT_IOCTL;
+ ptcwakeup(tp);
+ }
+ tp->t_lflag |= EXTPROC;
+ } else {
+ if ((tp->t_state & EXTPROC) &&
+ (pti->pt_flags & PF_PKT)) {
+ pti->pt_send |= TIOCPKT_IOCTL;
+ ptcwakeup(tp);
+ }
+ tp->t_lflag &= ~EXTPROC;
+ }
+ return(0);
+ } else
+ if (cdevsw[major(dev)].d_open == ptcopen) {
+ if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) {
+ if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc)
+ return (EINVAL);
+ (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
+ wakeup((caddr_t)&pti->pt_ioc);
+ return (0);
+ }
switch (cmd) {
+ case TIOCGPGRP:
+ /*
+ * We aviod calling ttioctl on the controller since,
+ * in that case, tp must be the controlling terminal.
+ */
+ *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
+ return (0);
+
case TIOCPKT:
- if (*(int *)data)
+ if (*(int *)data) {
+ if (pti->pt_flags & PF_UCNTL)
+ return (EINVAL);
pti->pt_flags |= PF_PKT;
- else
+ } else
pti->pt_flags &= ~PF_PKT;
return (0);
+ case TIOCUCNTL:
+ if (*(int *)data) {
+ if (pti->pt_flags & PF_PKT)
+ return (EINVAL);
+ pti->pt_flags |= PF_UCNTL;
+ } else
+ pti->pt_flags &= ~PF_UCNTL;
+ return (0);
+
+ case TIOCTIOC:
+ if (*(int *)data) {
+ if (pti->pt_flags & PF_UCNTL)
+ return (EINVAL);
+ pti->pt_flags |= PF_TIOC;
+ } else {
+ pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC);
+ while (pti->pt_ioc.c_cc)
+ (void) getc(&pti->pt_ioc);
+ wakeup((caddr_t)&pti->pt_ioc);
+ }
+ return (0);
+
+ case TIOCBLK:
+ if (*(int *)data)
+ pti->pt_flags |= PF_BLOCK;
+ else {
+ if (pti->pt_flags & PF_OWAIT)
+ wakeup((caddr_t)pti + 1);
+ pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT);
+ ptswake(tp);
+ }
+ return (0);
+
case TIOCREMOTE:
if (*(int *)data)
pti->pt_flags |= PF_REMOTE;
ttyflush(tp, FREAD|FWRITE);
return (0);
- case FIONBIO:
- if (*(int *)data)
- pti->pt_flags |= PF_NBIO;
- else
- pti->pt_flags &= ~PF_NBIO;
+ case FIONREAD:
+ *(int *)data = tp->t_outq.c_cc;
return (0);
- case TIOCSETP:
+ case TIOCSETP:
+ case TIOCSETN:
+ case TIOCSETD:
+ case TIOCSETA:
+ case TIOCSETAW:
+ case TIOCSETAF:
while (getc(&tp->t_outq) >= 0)
;
break;
+
+ case TIOCSIG:
+ if (*(unsigned int *)data >= NSIG)
+ return(EINVAL);
+ if ((tp->t_lflag&NOFLSH) == 0)
+ ttyflush(tp, FREAD|FWRITE);
+ pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
+ if ((*(unsigned int *)data == SIGINFO) &&
+ ((tp->t_lflag&NOKERNINFO) == 0))
+ ttyinfo(tp);
+ return(0);
+ }
+ } else if (pti->pt_flags & PF_TIOC) {
+ while (pti->pt_flags & PF_LIOC) {
+ pti->pt_flags |= PF_WIOC;
+ switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) {
+ case TS_OK:
+ continue;
+ case TS_SIG:
+ case TS_TIME:
+ return (EBUSY);
+ }
+ }
+ pti->pt_flags |= PF_LIOC | PF_BLOCK;
+ while (pti->pt_ioc.c_cc)
+ (void) getc(&pti->pt_ioc);
+ (void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc);
+ if (cmd & IOC_IN)
+ (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
+ ptcwakeup(tp, FREAD);
+ switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) {
+ case TS_SIG:
+ case TS_TIME:
+ while (pti->pt_ioc.c_cc)
+ (void) getc(&pti->pt_ioc);
+ if (pti->pt_flags & PF_WIOC)
+ wakeup((caddr_t)&pti->pt_flags);
+ if (pti->pt_flags & PF_OWAIT)
+ wakeup((caddr_t)pti + 1);
+ pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+ ptswake(tp);
+ return (EBUSY);
+ case TS_OK:
+ break;
+ }
+ if (pti->pt_ioc.c_cc == 0) {
+ if (pti->pt_flags & PF_WIOC)
+ wakeup((caddr_t)&pti->pt_flags);
+ if (pti->pt_flags & PF_OWAIT)
+ wakeup((caddr_t)pti + 1);
+ pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+ ptswake(tp);
+ goto doioctl;
+ }
+ if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error)
+ error = EINVAL;
+ if (error == 0 && cmd & IOC_OUT) {
+ if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc)
+ error = EINVAL;
+ else
+ (void) q_to_b(&pti->pt_ioc, data,
+ pti->pt_ioc.c_cc);
}
- error = ttioctl(tp, cmd, data, dev);
+ while (pti->pt_ioc.c_cc)
+ (void) getc(&pti->pt_ioc);
+ if (pti->pt_flags & PF_WIOC)
+ wakeup((caddr_t)&pti->pt_flags);
+ if (pti->pt_flags & PF_OWAIT)
+ wakeup((caddr_t)pti + 1);
+ pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+ ptswake(tp);
+ return (error);
+ }
+
+ doioctl:
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error < 0)
+ error = ttioctl(tp, cmd, data, flag);
+ /*
+ * Since we use the tty queues internally,
+ * pty's can't be switched to disciplines which overwrite
+ * the queues. We can't tell anything about the discipline
+ * from here...
+ *
+ * Nb: this is not really good enough, the line disc open routine
+ * may have done anything at all, no guarantees that close
+ * will fix it. This also has the effect of losing the
+ * previous discipline, which an error on a TIOCSETD shouldn't
+ * do... Sometime it should be done via an explicit check
+ * for TIOCSETD, then check to see what linesw[new_number].l_rint
+ * really is.
+ */
+ if (linesw[tp->t_line].l_rint != ttyinput) {
+ (*linesw[tp->t_line].l_close)(tp);
+ tp->t_line = TTYDISC;
+ (void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
+ error = ENOTTY;
+ }
+
+ if (error < 0) {
+ if (pti->pt_flags & PF_UCNTL &&
+ (cmd & ~0xff) == UIOCCMD(0)) {
+ if (cmd & 0xff) {
+ pti->pt_ucntl = (u_char)cmd;
+ ptcwakeup(tp, FREAD);
+ }
+ return (0);
+ }
error = ENOTTY;
- { int stop = (tp->t_stopc == ('s'&037) &&
- tp->t_startc == ('q'&037));
+ }
+ /*
+ * If external processing and packet mode send ioctl packet.
+ */
+ if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
+ switch(cmd) {
+ case TIOCSETA:
+ case TIOCSETAW:
+ case TIOCSETAF:
+ case TIOCSETP:
+ case TIOCSETN:
+#ifdef COMPAT_43
+ case TIOCSETC:
+ case TIOCSLTC:
+ case TIOCLBIS:
+ case TIOCLBIC:
+ case TIOCLSET:
+#endif
+ pti->pt_send |= TIOCPKT_IOCTL;
+ default:
+ break;
+ }
+ }
+ stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
+ && CCEQ(cc[VSTART], CTRL('q'));
if (pti->pt_flags & PF_NOSTOP) {
if (stop) {
- pti->pt_send &= TIOCPKT_NOSTOP;
+ pti->pt_send &= ~TIOCPKT_NOSTOP;
pti->pt_send |= TIOCPKT_DOSTOP;
pti->pt_flags &= ~PF_NOSTOP;
- ptcwakeup(tp);
+ ptcwakeup(tp, FREAD);
}
} else {
- if (stop == 0) {
+ if (!stop) {
pti->pt_send &= ~TIOCPKT_DOSTOP;
pti->pt_send |= TIOCPKT_NOSTOP;
pti->pt_flags |= PF_NOSTOP;
- ptcwakeup(tp);
+ ptcwakeup(tp, FREAD);
}
}
- }
return (error);
}
#endif