+ /*
+ * 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 (pti->pt_flags & PF_UCNTL)
+ return (EINVAL);
+ pti->pt_flags |= PF_PKT;
+ } 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;
+ ttyflush(tp, FREAD|FWRITE);
+ return (0);
+
+ case FIONREAD:
+ *(int *)data = tp->t_outq.c_cc;
+ return (0);
+
+ 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);
+ }
+ 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;
+ }
+ /*
+ * 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_DOSTOP;
+ pti->pt_flags &= ~PF_NOSTOP;
+ ptcwakeup(tp, FREAD);
+ }
+ } else {
+ if (!stop) {
+ pti->pt_send &= ~TIOCPKT_DOSTOP;
+ pti->pt_send |= TIOCPKT_NOSTOP;
+ pti->pt_flags |= PF_NOSTOP;
+ ptcwakeup(tp, FREAD);
+ }
+ }
+ return (error);