KTRACE code
[unix-history] / usr / src / sys / kern / tty_pty.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
e9fe78f8 6 * @(#)tty_pty.c 7.5 (Berkeley) %G%
da7c5cc6 7 */
be4367b3 8
45372428
MT
9/*
10 * Pseudo-teletype Driver
11 * (Actually two drivers, requiring two entries in 'cdevsw')
45372428 12 */
647d645f
MT
13#include "pty.h"
14
f12183e4 15#if NPTY > 0
94368568
JB
16#include "param.h"
17#include "systm.h"
18#include "ioctl.h"
19#include "tty.h"
20#include "dir.h"
21#include "user.h"
22#include "conf.h"
23#include "file.h"
24#include "proc.h"
25#include "uio.h"
26#include "kernel.h"
6a5ca8a0 27#include "tsleep.h"
941944c9 28
b3c8737d 29#if NPTY == 1
5bb90914 30#undef NPTY
c91c01fe 31#define NPTY 32 /* crude XXX */
b3c8737d 32#endif
45372428 33
2bb0bef9 34#define BUFSIZ 100 /* Chunk size iomoved to/from user */
e1d74936 35
45372428 36/*
5bb90914
JB
37 * pts == /dev/tty[pqrs]?
38 * ptc == /dev/pty[pqrs]?
45372428 39 */
e1d74936
BJ
40struct tty pt_tty[NPTY];
41struct pt_ioctl {
1a954a11 42 int pt_flags;
1a954a11 43 struct proc *pt_selr, *pt_selw;
5bb90914
JB
44 u_char pt_send;
45 u_char pt_ucntl;
6a5ca8a0 46 struct clist pt_ioc;
e1d74936 47} pt_ioctl[NPTY];
5bb90914 48int npty = NPTY; /* for pstat -t */
45372428 49
e9fe78f8
MT
50int ptydebug = 0;
51
6a5ca8a0
KM
52#define PF_RCOLL 0x0001
53#define PF_WCOLL 0x0002
54#define PF_NBIO 0x0004
55#define PF_PKT 0x0008 /* packet mode */
56#define PF_STOPPED 0x0010 /* user told stopped */
57#define PF_REMOTE 0x0020 /* remote and flow controlled input */
58#define PF_NOSTOP 0x0040
59#define PF_UCNTL 0x0080 /* user control mode */
60#define PF_TIOC 0x0100 /* transparent control mode */
61#define PF_LIOC 0x0200 /* transparent control locked */
62#define PF_WIOC 0x0400 /* waiting for PF_LIOC to clear */
63#define PF_BLOCK 0x0800 /* block writes to slave */
64#define PF_OWAIT 0x1000 /* waiting for PF_BLOCK to clear */
45372428
MT
65
66/*ARGSUSED*/
67ptsopen(dev, flag)
73c77d38 68 dev_t dev;
e1d74936 69{
45372428 70 register struct tty *tp;
5bb90914 71 int error;
45372428 72
5bb90914
JB
73#ifdef lint
74 npty = npty;
75#endif
f21c8fb8
BJ
76 if (minor(dev) >= NPTY)
77 return (ENXIO);
45372428 78 tp = &pt_tty[minor(dev)];
941944c9 79 if ((tp->t_state & TS_ISOPEN) == 0) {
bdda6b91 80 ttychars(tp); /* Set up default chars */
e39f9ea6
MT
81 tp->t_iflag = TTYDEF_IFLAG;
82 tp->t_oflag = TTYDEF_OFLAG;
83 tp->t_lflag = TTYDEF_LFLAG;
84 tp->t_cflag = TTYDEF_CFLAG;
85 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
86 ttsetwater(tp); /* would be done in xxparam() */
f21c8fb8
BJ
87 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
88 return (EBUSY);
e1d74936 89 if (tp->t_oproc) /* Ctrlr still around. */
941944c9
BJ
90 tp->t_state |= TS_CARR_ON;
91 while ((tp->t_state & TS_CARR_ON) == 0) {
92 tp->t_state |= TS_WOPEN;
e9fe78f8
MT
93 if (flag&FNDELAY)
94 break;
45372428
MT
95 sleep((caddr_t)&tp->t_rawq, TTIPRI);
96 }
e9fe78f8 97 error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
5bb90914
JB
98 ptcwakeup(tp, FREAD|FWRITE);
99 return (error);
45372428
MT
100}
101
102ptsclose(dev)
73c77d38 103 dev_t dev;
941944c9 104{
45372428
MT
105 register struct tty *tp;
106
107 tp = &pt_tty[minor(dev)];
108 (*linesw[tp->t_line].l_close)(tp);
4b39cb77 109 ttyclose(tp);
5bb90914 110 ptcwakeup(tp, FREAD|FWRITE);
6a5ca8a0 111 return (0);
45372428
MT
112}
113
e9fe78f8 114ptsread(dev, uio, flag)
73c77d38 115 dev_t dev;
ae9a0a69 116 struct uio *uio;
e1d74936 117{
defdbcd1
BJ
118 register struct tty *tp = &pt_tty[minor(dev)];
119 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 120 int error = 0;
defdbcd1
BJ
121
122again:
123 if (pti->pt_flags & PF_REMOTE) {
e39f9ea6
MT
124 while (tp == u.u_ttyp &&
125 u.u_procp->p_pgrp->pg_id != tp->t_pgid){
5bb90914
JB
126 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
127 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
e39f9ea6 128 !u.u_procp->p_pgrp->pg_jobc ||
defdbcd1 129 u.u_procp->p_flag&SVFORK)
840510a3 130 return (EIO);
e39f9ea6 131 pgsignal(u.u_procp->p_pgrp, SIGTTIN);
defdbcd1 132 sleep((caddr_t)&lbolt, TTIPRI);
941944c9 133 }
5bb90914 134 if (tp->t_canq.c_cc == 0) {
e9fe78f8 135 if (flag & FNDELAY)
840510a3 136 return (EWOULDBLOCK);
5bb90914 137 sleep((caddr_t)&tp->t_canq, TTIPRI);
defdbcd1
BJ
138 goto again;
139 }
5bb90914
JB
140 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
141 if (ureadc(getc(&tp->t_canq), uio) < 0) {
840510a3 142 error = EFAULT;
ae9a0a69
BJ
143 break;
144 }
5bb90914
JB
145 if (tp->t_canq.c_cc == 1)
146 (void) getc(&tp->t_canq);
147 if (tp->t_canq.c_cc)
840510a3 148 return (error);
defdbcd1
BJ
149 } else
150 if (tp->t_oproc)
e9fe78f8 151 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
5bb90914 152 ptcwakeup(tp, FWRITE);
840510a3 153 return (error);
45372428
MT
154}
155
941944c9
BJ
156/*
157 * Write to pseudo-tty.
158 * Wakeups of controlling tty will happen
159 * indirectly, when tty driver calls ptsstart.
160 */
e9fe78f8 161ptswrite(dev, uio, flag)
73c77d38 162 dev_t dev;
ae9a0a69 163 struct uio *uio;
e1d74936 164{
6a5ca8a0
KM
165 register struct tty *tp = &pt_tty[minor(dev)];
166 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
45372428 167
840510a3
BJ
168 if (tp->t_oproc == 0)
169 return (EIO);
6a5ca8a0
KM
170
171 while (pti->pt_flags & PF_BLOCK) {
172 pti->pt_flags |= PF_OWAIT;
173 sleep((caddr_t)pti + 1, TTOPRI);
174 }
175
e9fe78f8 176 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
45372428
MT
177}
178
941944c9
BJ
179/*
180 * Start output on pseudo-tty.
181 * Wake up process selecting or sleeping for input from controlling tty.
182 */
45372428 183ptsstart(tp)
e1d74936
BJ
184 struct tty *tp;
185{
1e6d24b1 186 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
e1d74936 187
941944c9 188 if (tp->t_state & TS_TTSTOP)
45372428 189 return;
1e6d24b1
BJ
190 if (pti->pt_flags & PF_STOPPED) {
191 pti->pt_flags &= ~PF_STOPPED;
192 pti->pt_send = TIOCPKT_START;
193 }
5bb90914 194 ptcwakeup(tp, FREAD);
d427b3b2
BJ
195}
196
5bb90914 197ptcwakeup(tp, flag)
d427b3b2
BJ
198 struct tty *tp;
199{
200 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
201
5bb90914
JB
202 if (flag & FREAD) {
203 if (pti->pt_selr) {
204 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
205 pti->pt_selr = 0;
206 pti->pt_flags &= ~PF_RCOLL;
207 }
208 wakeup((caddr_t)&tp->t_outq.c_cf);
209 }
210 if (flag & FWRITE) {
211 if (pti->pt_selw) {
212 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
213 pti->pt_selw = 0;
214 pti->pt_flags &= ~PF_WCOLL;
215 }
e9fe78f8 216if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid);
5bb90914 217 wakeup((caddr_t)&tp->t_rawq.c_cf);
e1d74936 218 }
45372428
MT
219}
220
221/*ARGSUSED*/
222ptcopen(dev, flag)
e1d74936
BJ
223 dev_t dev;
224 int flag;
225{
45372428 226 register struct tty *tp;
1a954a11 227 struct pt_ioctl *pti;
45372428 228
f21c8fb8
BJ
229 if (minor(dev) >= NPTY)
230 return (ENXIO);
45372428 231 tp = &pt_tty[minor(dev)];
f21c8fb8
BJ
232 if (tp->t_oproc)
233 return (EIO);
e1d74936 234 tp->t_oproc = ptsstart;
f2f3b49b 235 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1a954a11
BJ
236 pti = &pt_ioctl[minor(dev)];
237 pti->pt_flags = 0;
238 pti->pt_send = 0;
5bb90914 239 pti->pt_ucntl = 0;
f21c8fb8 240 return (0);
45372428
MT
241}
242
243ptcclose(dev)
e1d74936
BJ
244 dev_t dev;
245{
45372428
MT
246 register struct tty *tp;
247
248 tp = &pt_tty[minor(dev)];
f2f3b49b 249 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
d3be7d55 250 tp->t_state &= ~TS_CARR_ON;
e1d74936 251 tp->t_oproc = 0; /* mark closed */
6a5ca8a0 252 return (0);
45372428
MT
253}
254
e9fe78f8 255ptcread(dev, uio, flag)
1a954a11 256 dev_t dev;
ae9a0a69 257 struct uio *uio;
e1d74936 258{
840510a3 259 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914 260 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2bb0bef9
SL
261 char buf[BUFSIZ];
262 int error = 0, cc;
45372428 263
5bb90914
JB
264 /*
265 * We want to block until the slave
266 * is open, and there's something to read;
267 * but if we lost the slave or we're NBIO,
268 * then return the appropriate error instead.
269 */
270 for (;;) {
271 if (tp->t_state&TS_ISOPEN) {
272 if (pti->pt_flags&PF_PKT && pti->pt_send) {
8011f5df 273 error = ureadc((int)pti->pt_send, uio);
5bb90914
JB
274 if (error)
275 return (error);
276 pti->pt_send = 0;
277 return (0);
278 }
279 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
8011f5df 280 error = ureadc((int)pti->pt_ucntl, uio);
5bb90914
JB
281 if (error)
282 return (error);
283 pti->pt_ucntl = 0;
284 return (0);
285 }
6a5ca8a0
KM
286 if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) {
287 if (uio->uio_resid < pti->pt_ioc.c_cc + 1)
288 return (E2BIG);
289 error = ureadc(TIOCPKT_TIOC, uio);
290 while (error == 0 && pti->pt_ioc.c_cc > 0) {
291 cc = q_to_b(&pti->pt_ioc, buf,
292 MIN(pti->pt_ioc.c_cc, BUFSIZ));
293 if (cc <= 0) /* impossible? */
294 break;
295 error = uiomove(buf, cc, UIO_READ, uio);
296 }
297 return (error);
298 }
5bb90914
JB
299 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
300 break;
1a954a11 301 }
2bb0bef9 302 if ((tp->t_state&TS_CARR_ON) == 0)
e9fe78f8
MT
303 return (0); /* EOF */
304 if (flag&FNDELAY)
840510a3 305 return (EWOULDBLOCK);
e9fe78f8 306if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid);
45372428 307 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
8b8271ac 308 }
6a5ca8a0 309 if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC))
5bb90914 310 error = ureadc(0, uio);
2bb0bef9
SL
311 while (uio->uio_resid > 0 && error == 0) {
312 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
313 if (cc <= 0)
ae9a0a69 314 break;
2bb0bef9
SL
315 error = uiomove(buf, cc, UIO_READ, uio);
316 }
6a5ca8a0
KM
317 if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK))
318 ptswake(tp);
840510a3 319 return (error);
45372428
MT
320}
321
6a5ca8a0
KM
322ptswake(tp)
323 register struct tty *tp;
324{
325 if (tp->t_state&TS_ASLEEP) {
326 tp->t_state &= ~TS_ASLEEP;
327 wakeup((caddr_t)&tp->t_outq);
328 }
329 if (tp->t_wsel) {
330 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
331 tp->t_wsel = 0;
332 tp->t_state &= ~TS_WCOLL;
333 }
334}
335
1a954a11
BJ
336ptsstop(tp, flush)
337 register struct tty *tp;
338 int flush;
339{
340 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
5bb90914 341 int flag;
1a954a11 342
1e6d24b1
BJ
343 /* note: FLUSHREAD and FLUSHWRITE already ok */
344 if (flush == 0) {
345 flush = TIOCPKT_STOP;
346 pti->pt_flags |= PF_STOPPED;
5bb90914 347 } else
1e6d24b1 348 pti->pt_flags &= ~PF_STOPPED;
0a2bd708 349 pti->pt_send |= flush;
5bb90914
JB
350 /* change of perspective */
351 flag = 0;
352 if (flush & FREAD)
353 flag |= FWRITE;
354 if (flush & FWRITE)
355 flag |= FREAD;
9d2a90b1 356 ptcwakeup(tp, flag);
1a954a11
BJ
357}
358
941944c9 359ptcselect(dev, rw)
e1d74936 360 dev_t dev;
941944c9 361 int rw;
e1d74936
BJ
362{
363 register struct tty *tp = &pt_tty[minor(dev)];
defdbcd1 364 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e1d74936 365 struct proc *p;
d427b3b2 366 int s;
e1d74936 367
5bb90914 368 if ((tp->t_state&TS_CARR_ON) == 0)
e1d74936 369 return (1);
941944c9
BJ
370 switch (rw) {
371
372 case FREAD:
892f2f35
MK
373 /*
374 * Need to block timeouts (ttrstart).
375 */
376 s = spltty();
7cbd29e4
MK
377 if ((tp->t_state&TS_ISOPEN) &&
378 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
379 splx(s);
380 return (1);
381 }
892f2f35 382 splx(s);
7cbd29e4
MK
383 /* FALLTHROUGH */
384
385 case 0: /* exceptional */
5bb90914
JB
386 if ((tp->t_state&TS_ISOPEN) &&
387 (pti->pt_flags&PF_PKT && pti->pt_send ||
6a5ca8a0 388 pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc ||
892f2f35 389 pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
941944c9 390 return (1);
1a954a11
BJ
391 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
392 pti->pt_flags |= PF_RCOLL;
941944c9 393 else
1a954a11 394 pti->pt_selr = u.u_procp;
d427b3b2 395 break;
941944c9 396
7cbd29e4 397
941944c9 398 case FWRITE:
892f2f35
MK
399 if (tp->t_state&TS_ISOPEN) {
400 if (pti->pt_flags & PF_REMOTE) {
401 if (tp->t_canq.c_cc == 0)
402 return (1);
403 } else {
404 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
405 return (1);
e39f9ea6 406 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
892f2f35
MK
407 return (1);
408 }
d427b3b2 409 }
1a954a11
BJ
410 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
411 pti->pt_flags |= PF_WCOLL;
941944c9 412 else
1a954a11 413 pti->pt_selw = u.u_procp;
d427b3b2 414 break;
7cbd29e4 415
941944c9 416 }
d427b3b2 417 return (0);
e1d74936
BJ
418}
419
e9fe78f8 420ptcwrite(dev, uio, flag)
941944c9 421 dev_t dev;
5bb90914 422 register struct uio *uio;
e1d74936 423{
840510a3 424 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914
JB
425 register struct iovec *iov;
426 register char *cp;
427 register int cc = 0;
45372428 428 char locbuf[BUFSIZ];
941944c9 429 int cnt = 0;
defdbcd1 430 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 431 int error = 0;
45372428 432
defdbcd1 433again:
5bb90914
JB
434 if ((tp->t_state&TS_ISOPEN) == 0)
435 goto block;
9d2a90b1 436 if (pti->pt_flags & PF_REMOTE) {
5bb90914
JB
437 if (tp->t_canq.c_cc)
438 goto block;
9d2a90b1
JB
439 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
440 iov = uio->uio_iov;
441 if (iov->iov_len == 0) {
442 uio->uio_iovcnt--;
443 uio->uio_iov++;
444 continue;
445 }
446 if (cc == 0) {
447 cc = MIN(iov->iov_len, BUFSIZ);
448 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
449 cp = locbuf;
450 error = uiomove(cp, cc, UIO_WRITE, uio);
451 if (error)
452 return (error);
453 /* check again for safety */
454 if ((tp->t_state&TS_ISOPEN) == 0)
455 return (EIO);
456 }
457 if (cc)
458 (void) b_to_q(cp, cc, &tp->t_canq);
459 cc = 0;
defdbcd1 460 }
5bb90914
JB
461 (void) putc(0, &tp->t_canq);
462 ttwakeup(tp);
463 wakeup((caddr_t)&tp->t_canq);
464 return (0);
465 }
466 while (uio->uio_iovcnt > 0) {
467 iov = uio->uio_iov;
468 if (cc == 0) {
469 if (iov->iov_len == 0) {
470 uio->uio_iovcnt--;
471 uio->uio_iov++;
472 continue;
45372428 473 }
5bb90914
JB
474 cc = MIN(iov->iov_len, BUFSIZ);
475 cp = locbuf;
476 error = uiomove(cp, cc, UIO_WRITE, uio);
477 if (error)
478 return (error);
479 /* check again for safety */
480 if ((tp->t_state&TS_ISOPEN) == 0)
481 return (EIO);
482 }
9d2a90b1
JB
483 while (cc > 0) {
484 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
e39f9ea6 485 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
9d2a90b1
JB
486 wakeup((caddr_t)&tp->t_rawq);
487 goto block;
488 }
e9fe78f8 489 (*linesw[tp->t_line].l_rint)(*cp++&0377, tp);
941944c9 490 cnt++;
9d2a90b1 491 cc--;
45372428 492 }
5bb90914
JB
493 cc = 0;
494 }
495 return (0);
496block:
497 /*
9d2a90b1
JB
498 * Come here to wait for slave to open, for space
499 * in outq, or space in rawq.
5bb90914
JB
500 */
501 if ((tp->t_state&TS_CARR_ON) == 0)
502 return (EIO);
e9fe78f8 503 if ((pti->pt_flags & PF_NBIO) || (flag & FNDELAY)) {
5bb90914
JB
504 iov->iov_base -= cc;
505 iov->iov_len += cc;
506 uio->uio_resid += cc;
507 uio->uio_offset -= cc;
9d2a90b1
JB
508 if (cnt == 0)
509 return (EWOULDBLOCK);
5bb90914
JB
510 return (0);
511 }
e9fe78f8 512if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid);
5bb90914
JB
513 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
514 goto again;
45372428
MT
515}
516
45372428 517/*ARGSUSED*/
4b72e2f9
SL
518ptyioctl(dev, cmd, data, flag)
519 caddr_t data;
e1d74936
BJ
520 dev_t dev;
521{
0a2bd708
BJ
522 register struct tty *tp = &pt_tty[minor(dev)];
523 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e39f9ea6 524 register u_char *cc = tp->t_cc;
5bb90914 525 int stop, error;
f2f3b49b 526 extern ttyinput();
45372428 527
f2f3b49b
MK
528 /*
529 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
530 * ttywflush(tp) will hang if there are characters in the outq.
531 */
6a5ca8a0
KM
532 if (cdevsw[major(dev)].d_open == ptcopen) {
533 if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) {
534 if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc)
535 return (EINVAL);
536 (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
537 wakeup((caddr_t)&pti->pt_ioc);
538 return (0);
539 }
4b72e2f9
SL
540 switch (cmd) {
541
542 case TIOCPKT:
5bb90914
JB
543 if (*(int *)data) {
544 if (pti->pt_flags & PF_UCNTL)
545 return (EINVAL);
1a954a11 546 pti->pt_flags |= PF_PKT;
5bb90914 547 } else
1a954a11 548 pti->pt_flags &= ~PF_PKT;
f21c8fb8 549 return (0);
4b72e2f9 550
5bb90914
JB
551 case TIOCUCNTL:
552 if (*(int *)data) {
553 if (pti->pt_flags & PF_PKT)
554 return (EINVAL);
555 pti->pt_flags |= PF_UCNTL;
556 } else
557 pti->pt_flags &= ~PF_UCNTL;
558 return (0);
559
6a5ca8a0
KM
560 case TIOCTIOC:
561 if (*(int *)data) {
562 if (pti->pt_flags & PF_UCNTL)
563 return (EINVAL);
564 pti->pt_flags |= PF_TIOC;
565 } else {
566 pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC);
567 while (pti->pt_ioc.c_cc)
568 (void) getc(&pti->pt_ioc);
569 wakeup((caddr_t)&pti->pt_ioc);
570 }
571 return (0);
572
573 case TIOCBLK:
574 if (*(int *)data)
575 pti->pt_flags |= PF_BLOCK;
576 else {
577 if (pti->pt_flags & PF_OWAIT)
578 wakeup((caddr_t)pti + 1);
579 pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT);
580 ptswake(tp);
581 }
582 return (0);
583
4b72e2f9
SL
584 case TIOCREMOTE:
585 if (*(int *)data)
defdbcd1
BJ
586 pti->pt_flags |= PF_REMOTE;
587 else
588 pti->pt_flags &= ~PF_REMOTE;
88a7a62a 589 ttyflush(tp, FREAD|FWRITE);
f21c8fb8 590 return (0);
4b72e2f9
SL
591
592 case FIONBIO:
593 if (*(int *)data)
1a954a11 594 pti->pt_flags |= PF_NBIO;
8b8271ac 595 else
1a954a11 596 pti->pt_flags &= ~PF_NBIO;
f21c8fb8 597 return (0);
4b72e2f9 598
6a5ca8a0
KM
599 case FIONREAD:
600 *(int *)data = tp->t_outq.c_cc;
601 return (0);
602
e39f9ea6 603 case TIOCSETP:
f2f3b49b
MK
604 case TIOCSETN:
605 case TIOCSETD:
e39f9ea6
MT
606 case TIOCSETA:
607 case TIOCSETAW:
608 case TIOCSETAF:
609 case TIOCSETAS:
610 case TIOCSETAWS:
611 case TIOCSETAFS:
4b72e2f9
SL
612 while (getc(&tp->t_outq) >= 0)
613 ;
614 break;
8b8271ac 615 }
6a5ca8a0
KM
616 } else if (pti->pt_flags & PF_TIOC) {
617 while (pti->pt_flags & PF_LIOC) {
618 pti->pt_flags |= PF_WIOC;
619 switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) {
620 case TS_OK:
621 continue;
622 case TS_SIG:
623 case TS_TIME:
624 return (EBUSY);
625 }
626 }
627 pti->pt_flags |= PF_LIOC | PF_BLOCK;
628 while (pti->pt_ioc.c_cc)
629 (void) getc(&pti->pt_ioc);
630 (void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc);
631 if (cmd & IOC_IN)
632 (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
633 ptcwakeup(tp, FREAD);
634 switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) {
635 case TS_SIG:
636 case TS_TIME:
637 while (pti->pt_ioc.c_cc)
638 (void) getc(&pti->pt_ioc);
639 if (pti->pt_flags & PF_WIOC)
640 wakeup((caddr_t)&pti->pt_flags);
641 if (pti->pt_flags & PF_OWAIT)
642 wakeup((caddr_t)pti + 1);
643 pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
644 ptswake(tp);
645 return (EBUSY);
646 case TS_OK:
647 break;
648 }
649 if (pti->pt_ioc.c_cc == 0) {
650 if (pti->pt_flags & PF_WIOC)
651 wakeup((caddr_t)&pti->pt_flags);
652 if (pti->pt_flags & PF_OWAIT)
653 wakeup((caddr_t)pti + 1);
654 pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
655 ptswake(tp);
656 goto doioctl;
657 }
658 if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error)
659 error = EINVAL;
660 if (error == 0 && cmd & IOC_OUT) {
661 if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc)
662 error = EINVAL;
663 else
664 (void) q_to_b(&pti->pt_ioc, data,
665 pti->pt_ioc.c_cc);
666 }
667 while (pti->pt_ioc.c_cc)
668 (void) getc(&pti->pt_ioc);
669 if (pti->pt_flags & PF_WIOC)
670 wakeup((caddr_t)&pti->pt_flags);
671 if (pti->pt_flags & PF_OWAIT)
672 wakeup((caddr_t)pti + 1);
673 pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
674 ptswake(tp);
675 return (error);
676 }
677
678 doioctl:
e39f9ea6
MT
679 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
680 if (error < 0)
681 error = ttioctl(tp, cmd, data, flag);
f2f3b49b
MK
682 /*
683 * Since we use the tty queues internally,
684 * pty's can't be switched to disciplines which overwrite
685 * the queues. We can't tell anything about the discipline
686 * from here...
6a5ca8a0
KM
687 *
688 * Nb: this is not really good enough, the line disc open routine
689 * may have done anything at all, no guarantees that close
690 * will fix it. This also has the effect of losing the
691 * previous discipline, which an error on a TIOCSETD shouldn't
692 * do... Sometime it should be done via an explicit check
693 * for TIOCSETD, then check to see what linesw[new_number].l_rint
694 * really is.
f2f3b49b
MK
695 */
696 if (linesw[tp->t_line].l_rint != ttyinput) {
697 (*linesw[tp->t_line].l_close)(tp);
698 tp->t_line = 0;
e9fe78f8 699 (void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
f2f3b49b
MK
700 error = ENOTTY;
701 }
6a5ca8a0 702
5bb90914
JB
703 if (error < 0) {
704 if (pti->pt_flags & PF_UCNTL &&
97d7430f 705 (cmd & ~0xff) == UIOCCMD(0)) {
5bb90914
JB
706 if (cmd & 0xff) {
707 pti->pt_ucntl = (u_char)cmd;
708 ptcwakeup(tp, FREAD);
709 }
710 return (0);
711 }
f21c8fb8 712 error = ENOTTY;
5bb90914 713 }
e39f9ea6
MT
714 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
715 && CCEQ(cc[VSTART], CTRL('q'));
0a2bd708
BJ
716 if (pti->pt_flags & PF_NOSTOP) {
717 if (stop) {
b31eb1ff 718 pti->pt_send &= ~TIOCPKT_NOSTOP;
0a2bd708
BJ
719 pti->pt_send |= TIOCPKT_DOSTOP;
720 pti->pt_flags &= ~PF_NOSTOP;
5bb90914 721 ptcwakeup(tp, FREAD);
0a2bd708
BJ
722 }
723 } else {
5bb90914 724 if (!stop) {
0a2bd708
BJ
725 pti->pt_send &= ~TIOCPKT_DOSTOP;
726 pti->pt_send |= TIOCPKT_NOSTOP;
727 pti->pt_flags |= PF_NOSTOP;
5bb90914 728 ptcwakeup(tp, FREAD);
0a2bd708
BJ
729 }
730 }
f21c8fb8 731 return (error);
45372428 732}
4f07e6e5 733#endif