-/* tty_pty.c 4.27 82/10/17 */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)tty_pty.c 7.3.1.1 (Berkeley) %G%
+ */
/*
* Pseudo-teletype Driver
#include "pty.h"
#if NPTY > 0
-#include "../h/param.h"
-#include "../h/systm.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 "dir.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "tsleep.h"
#if NPTY == 1
-#undef NPTY
+#undef NPTY
#define NPTY 32 /* crude XXX */
#endif
-#define BUFSIZ 100 /* Chunk size iomoved from user */
+#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)
dev_t dev;
{
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) {
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)
return (EBUSY);
tp->t_state |= TS_WOPEN;
sleep((caddr_t)&tp->t_rawq, TTIPRI);
}
- return ((*linesw[tp->t_line].l_open)(dev, tp));
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ ptcwakeup(tp, FREAD|FWRITE);
+ return (error);
}
ptsclose(dev)
tp = &pt_tty[minor(dev)];
(*linesw[tp->t_line].l_close)(tp);
ttyclose(tp);
+ ptcwakeup(tp, FREAD|FWRITE);
+ return (0);
}
ptsread(dev, uio)
again:
if (pti->pt_flags & PF_REMOTE) {
while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
- if (u.u_signal[SIGTTIN] == SIG_IGN ||
- u.u_signal[SIGTTIN] == SIG_HOLD ||
- /*
- (u.u_procp->p_flag&SDETACH) ||
- */
+ if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
+ (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
u.u_procp->p_flag&SVFORK)
return (EIO);
gsignal(u.u_procp->p_pgrp, SIGTTIN);
sleep((caddr_t)&lbolt, TTIPRI);
}
- if (tp->t_rawq.c_cc == 0) {
+ if (tp->t_canq.c_cc == 0) {
if (tp->t_state & TS_NBIO)
return (EWOULDBLOCK);
- sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ sleep((caddr_t)&tp->t_canq, TTIPRI);
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;
- }
+ ptcwakeup(tp, FWRITE);
return (error);
}
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);
+
+ 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));
}
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*/
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);
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 */
- flushtty(tp, FREAD|FWRITE);
+ (void)(*linesw[tp->t_line].l_modem)(tp, 0);
+ tp->t_state &= ~TS_CARR_ON;
tp->t_oproc = 0; /* mark closed */
+ return (0);
}
ptcread(dev, uio)
struct uio *uio;
{
register struct tty *tp = &pt_tty[minor(dev)];
- struct pt_ioctl *pti;
- int error = 0;
+ 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;
- 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);
+ 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 (EWOULDBLOCK);
sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
}
- while (tp->t_outq.c_cc && uio->uio_resid > 0)
- if (ureadc(getc(&tp->t_outq), uio) < 0) {
- error = EFAULT;
+ 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;
- }
- 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_READ, 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)
struct proc *p;
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);
}
+ 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 ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_RCOLL;
else
pti->pt_selr = u.u_procp;
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_flags & (RAW|CBREAK)) == 0)
+ return (1);
+ }
}
if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_WCOLL;
else
pti->pt_selw = u.u_procp;
break;
+
}
- splx(s);
return (0);
}
ptcwrite(dev, uio)
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;
+ register struct iovec *iov;
+ register char *cp;
+ register int cc = 0;
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) {
- 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_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iovcnt--;
+ uio->uio_iov++;
+ continue;
}
- (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 == 0) {
+ cc = MIN(iov->iov_len, BUFSIZ);
+ cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
+ cp = locbuf;
+ error = uiomove(cp, cc, UIO_WRITE, uio);
+ if (error)
+ return (error);
+ /* check again for safety */
+ if ((tp->t_state&TS_ISOPEN) == 0)
+ return (EIO);
+ }
+ if (cc)
+ (void) b_to_q(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_iovcnt > 0) {
+ iov = uio->uio_iov;
+ if (cc == 0) {
+ if (iov->iov_len == 0) {
+ uio->uio_iovcnt--;
+ uio->uio_iov++;
+ continue;
+ }
+ cc = MIN(iov->iov_len, BUFSIZ);
+ cp = locbuf;
+ error = uiomove(cp, cc, UIO_WRITE, uio);
+ if (error)
+ return (error);
+ /* check again for safety */
+ if ((tp->t_state&TS_ISOPEN) == 0)
+ return (EIO);
}
- while (cp < ce) {
- while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
+ while (cc > 0) {
+ if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
+ (tp->t_canq.c_cc > 0 ||
+ tp->t_flags & (RAW|CBREAK))) {
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 (pti->pt_flags & PF_NBIO) {
+ iov->iov_base -= cc;
+ iov->iov_len += cc;
+ uio->uio_resid += cc;
+ uio->uio_offset -= cc;
+ if (cnt == 0)
+ return (EWOULDBLOCK);
+ return (0);
+ }
+ sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
+ goto again;
}
/*ARGSUSED*/
{
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
- int error;
+ 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 (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 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;
else
pti->pt_flags &= ~PF_REMOTE;
- flushtty(tp, FREAD|FWRITE);
+ ttyflush(tp, FREAD|FWRITE);
return (0);
case FIONBIO:
pti->pt_flags &= ~PF_NBIO;
return (0);
+ case FIONREAD:
+ *(int *)data = tp->t_outq.c_cc;
+ return (0);
+
case TIOCSETP:
+ case TIOCSETN:
+ case TIOCSETD:
while (getc(&tp->t_outq) >= 0)
;
break;
}
- error = ttioctl(tp, cmd, data, dev);
- if (error < 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);
+ }
+ 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 = 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 = 0;
+ (void)(*linesw[tp->t_line].l_open)(dev, tp);
+ 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_un.t_chr.t_stopc == ('s'&037) &&
- tp->t_un.t_chr.t_startc == ('q'&037));
+ }
+ stop = (tp->t_flags & RAW) == 0 &&
+ tp->t_stopc == CTRL('s') && tp->t_startc == 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