nulldev and nullioctl return values
[unix-history] / usr / src / sys / kern / tty_pty.c
CommitLineData
840510a3 1/* tty_pty.c 4.26 82/10/13 */
be4367b3 2
45372428
MT
3/*
4 * Pseudo-teletype Driver
5 * (Actually two drivers, requiring two entries in 'cdevsw')
45372428 6 */
647d645f
MT
7#include "pty.h"
8
f12183e4 9#if NPTY > 0
45372428
MT
10#include "../h/param.h"
11#include "../h/systm.h"
12#include "../h/tty.h"
13#include "../h/dir.h"
14#include "../h/user.h"
15#include "../h/conf.h"
bdda6b91 16#include "../h/file.h"
e1d74936 17#include "../h/proc.h"
ae9a0a69 18#include "../h/uio.h"
7ba3a9ca 19#include "../h/kernel.h"
941944c9 20
b3c8737d 21#if NPTY == 1
c91c01fe
BJ
22#undef NPTY
23#define NPTY 32 /* crude XXX */
b3c8737d 24#endif
45372428 25
bdda6b91 26#define BUFSIZ 100 /* Chunk size iomoved from user */
e1d74936 27
45372428 28/*
e1d74936
BJ
29 * pts == /dev/tty[pP]?
30 * ptc == /dev/ptp[pP]?
45372428 31 */
e1d74936
BJ
32struct tty pt_tty[NPTY];
33struct pt_ioctl {
1a954a11
BJ
34 int pt_flags;
35 int pt_gensym;
36 struct proc *pt_selr, *pt_selw;
37 int pt_send;
e1d74936 38} pt_ioctl[NPTY];
45372428 39
1a954a11
BJ
40#define PF_RCOLL 0x01
41#define PF_WCOLL 0x02
42#define PF_NBIO 0x04
43#define PF_PKT 0x08 /* packet mode */
1e6d24b1 44#define PF_STOPPED 0x10 /* user told stopped */
defdbcd1 45#define PF_REMOTE 0x20 /* remote and flow controlled input */
0a2bd708 46#define PF_NOSTOP 0x40
45372428
MT
47
48/*ARGSUSED*/
49ptsopen(dev, flag)
73c77d38 50 dev_t dev;
e1d74936 51{
45372428
MT
52 register struct tty *tp;
53
e1d74936 54 if (minor(dev) >= NPTY) {
45372428
MT
55 u.u_error = ENXIO;
56 return;
57 }
58 tp = &pt_tty[minor(dev)];
941944c9 59 if ((tp->t_state & TS_ISOPEN) == 0) {
bdda6b91
BJ
60 ttychars(tp); /* Set up default chars */
61 tp->t_flags = 0; /* No features (nor raw mode) */
941944c9 62 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
45372428
MT
63 u.u_error = EBUSY;
64 return;
65 }
e1d74936 66 if (tp->t_oproc) /* Ctrlr still around. */
941944c9
BJ
67 tp->t_state |= TS_CARR_ON;
68 while ((tp->t_state & TS_CARR_ON) == 0) {
69 tp->t_state |= TS_WOPEN;
45372428
MT
70 sleep((caddr_t)&tp->t_rawq, TTIPRI);
71 }
72 (*linesw[tp->t_line].l_open)(dev, tp);
73}
74
75ptsclose(dev)
73c77d38 76 dev_t dev;
941944c9 77{
45372428
MT
78 register struct tty *tp;
79
80 tp = &pt_tty[minor(dev)];
81 (*linesw[tp->t_line].l_close)(tp);
4b39cb77 82 ttyclose(tp);
45372428
MT
83}
84
ae9a0a69 85ptsread(dev, uio)
73c77d38 86 dev_t dev;
ae9a0a69 87 struct uio *uio;
e1d74936 88{
defdbcd1
BJ
89 register struct tty *tp = &pt_tty[minor(dev)];
90 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 91 int error = 0;
defdbcd1
BJ
92
93again:
94 if (pti->pt_flags & PF_REMOTE) {
95 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
96 if (u.u_signal[SIGTTIN] == SIG_IGN ||
97 u.u_signal[SIGTTIN] == SIG_HOLD ||
98 /*
99 (u.u_procp->p_flag&SDETACH) ||
100 */
101 u.u_procp->p_flag&SVFORK)
840510a3 102 return (EIO);
defdbcd1
BJ
103 gsignal(u.u_procp->p_pgrp, SIGTTIN);
104 sleep((caddr_t)&lbolt, TTIPRI);
941944c9 105 }
defdbcd1 106 if (tp->t_rawq.c_cc == 0) {
840510a3
BJ
107 if (tp->t_state & TS_NBIO)
108 return (EWOULDBLOCK);
defdbcd1
BJ
109 sleep((caddr_t)&tp->t_rawq, TTIPRI);
110 goto again;
111 }
ae9a0a69
BJ
112 while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
113 if (ureadc(getc(&tp->t_rawq), uio) < 0) {
840510a3 114 error = EFAULT;
ae9a0a69
BJ
115 break;
116 }
defdbcd1
BJ
117 if (tp->t_rawq.c_cc == 1)
118 (void) getc(&tp->t_rawq);
119 if (tp->t_rawq.c_cc)
840510a3 120 return (error);
defdbcd1
BJ
121 } else
122 if (tp->t_oproc)
840510a3 123 error = (*linesw[tp->t_line].l_read)(tp, uio);
defdbcd1
BJ
124 wakeup((caddr_t)&tp->t_rawq.c_cf);
125 if (pti->pt_selw) {
126 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
127 pti->pt_selw = 0;
128 pti->pt_flags &= ~PF_WCOLL;
45372428 129 }
840510a3 130 return (error);
45372428
MT
131}
132
941944c9
BJ
133/*
134 * Write to pseudo-tty.
135 * Wakeups of controlling tty will happen
136 * indirectly, when tty driver calls ptsstart.
137 */
ae9a0a69 138ptswrite(dev, uio)
73c77d38 139 dev_t dev;
ae9a0a69 140 struct uio *uio;
e1d74936 141{
45372428
MT
142 register struct tty *tp;
143
144 tp = &pt_tty[minor(dev)];
840510a3
BJ
145 if (tp->t_oproc == 0)
146 return (EIO);
147 return ((*linesw[tp->t_line].l_write)(tp, uio));
45372428
MT
148}
149
941944c9
BJ
150/*
151 * Start output on pseudo-tty.
152 * Wake up process selecting or sleeping for input from controlling tty.
153 */
45372428 154ptsstart(tp)
e1d74936
BJ
155 struct tty *tp;
156{
1e6d24b1 157 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
e1d74936 158
941944c9 159 if (tp->t_state & TS_TTSTOP)
45372428 160 return;
1e6d24b1
BJ
161 if (pti->pt_flags & PF_STOPPED) {
162 pti->pt_flags &= ~PF_STOPPED;
163 pti->pt_send = TIOCPKT_START;
164 }
d427b3b2
BJ
165 ptcwakeup(tp);
166}
167
168ptcwakeup(tp)
169 struct tty *tp;
170{
171 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
172
1a954a11
BJ
173 if (pti->pt_selr) {
174 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
175 pti->pt_selr = 0;
176 pti->pt_flags &= ~PF_RCOLL;
e1d74936 177 }
45372428
MT
178 wakeup((caddr_t)&tp->t_outq.c_cf);
179}
180
181/*ARGSUSED*/
182ptcopen(dev, flag)
e1d74936
BJ
183 dev_t dev;
184 int flag;
185{
45372428 186 register struct tty *tp;
1a954a11 187 struct pt_ioctl *pti;
45372428 188
e1d74936 189 if (minor(dev) >= NPTY) {
45372428
MT
190 u.u_error = ENXIO;
191 return;
192 }
193 tp = &pt_tty[minor(dev)];
e1d74936 194 if (tp->t_oproc) {
45372428
MT
195 u.u_error = EIO;
196 return;
197 }
e1d74936 198 tp->t_oproc = ptsstart;
941944c9 199 if (tp->t_state & TS_WOPEN)
45372428 200 wakeup((caddr_t)&tp->t_rawq);
941944c9 201 tp->t_state |= TS_CARR_ON;
1a954a11
BJ
202 pti = &pt_ioctl[minor(dev)];
203 pti->pt_flags = 0;
204 pti->pt_send = 0;
45372428
MT
205}
206
207ptcclose(dev)
e1d74936
BJ
208 dev_t dev;
209{
45372428
MT
210 register struct tty *tp;
211
212 tp = &pt_tty[minor(dev)];
941944c9 213 if (tp->t_state & TS_ISOPEN)
45372428 214 gsignal(tp->t_pgrp, SIGHUP);
941944c9 215 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */
e1d74936
BJ
216 flushtty(tp, FREAD|FWRITE);
217 tp->t_oproc = 0; /* mark closed */
45372428
MT
218}
219
ae9a0a69 220ptcread(dev, uio)
1a954a11 221 dev_t dev;
ae9a0a69 222 struct uio *uio;
e1d74936 223{
840510a3 224 register struct tty *tp = &pt_tty[minor(dev)];
1a954a11 225 struct pt_ioctl *pti;
840510a3 226 int error = 0;
45372428 227
941944c9 228 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
45372428 229 return;
1a954a11
BJ
230 pti = &pt_ioctl[minor(dev)];
231 if (pti->pt_flags & PF_PKT) {
232 if (pti->pt_send) {
840510a3
BJ
233 error = ureadc(pti->pt_send, uio);
234 if (error)
235 return (error);
1a954a11 236 pti->pt_send = 0;
840510a3 237 return (0);
1a954a11 238 }
840510a3 239 error = ureadc(0, uio);
1a954a11 240 }
8b8271ac 241 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
840510a3
BJ
242 if (pti->pt_flags&PF_NBIO)
243 return (EWOULDBLOCK);
45372428 244 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
8b8271ac 245 }
ae9a0a69
BJ
246 while (tp->t_outq.c_cc && uio->uio_resid > 0)
247 if (ureadc(getc(&tp->t_outq), uio) < 0) {
840510a3 248 error = EFAULT;
ae9a0a69
BJ
249 break;
250 }
941944c9
BJ
251 if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
252 if (tp->t_state&TS_ASLEEP) {
253 tp->t_state &= ~TS_ASLEEP;
254 wakeup((caddr_t)&tp->t_outq);
255 }
256 if (tp->t_wsel) {
257 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
258 tp->t_wsel = 0;
259 tp->t_state &= ~TS_WCOLL;
260 }
45372428 261 }
840510a3 262 return (error);
45372428
MT
263}
264
1a954a11
BJ
265ptsstop(tp, flush)
266 register struct tty *tp;
267 int flush;
268{
269 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
270
1e6d24b1
BJ
271 /* note: FLUSHREAD and FLUSHWRITE already ok */
272 if (flush == 0) {
273 flush = TIOCPKT_STOP;
274 pti->pt_flags |= PF_STOPPED;
275 } else {
276 pti->pt_flags &= ~PF_STOPPED;
277 }
0a2bd708 278 pti->pt_send |= flush;
d427b3b2 279 ptcwakeup(tp);
1a954a11
BJ
280}
281
941944c9 282ptcselect(dev, rw)
e1d74936 283 dev_t dev;
941944c9 284 int rw;
e1d74936
BJ
285{
286 register struct tty *tp = &pt_tty[minor(dev)];
defdbcd1 287 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e1d74936 288 struct proc *p;
d427b3b2 289 int s;
e1d74936 290
941944c9 291 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
e1d74936 292 return (1);
d427b3b2 293 s = spl5();
941944c9
BJ
294 switch (rw) {
295
296 case FREAD:
d427b3b2
BJ
297 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
298 splx(s);
941944c9 299 return (1);
d427b3b2 300 }
1a954a11
BJ
301 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
302 pti->pt_flags |= PF_RCOLL;
941944c9 303 else
1a954a11 304 pti->pt_selr = u.u_procp;
d427b3b2 305 break;
941944c9
BJ
306
307 case FWRITE:
defdbcd1 308 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
d427b3b2 309 splx(s);
941944c9 310 return (1);
d427b3b2 311 }
1a954a11
BJ
312 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
313 pti->pt_flags |= PF_WCOLL;
941944c9 314 else
1a954a11 315 pti->pt_selw = u.u_procp;
d427b3b2 316 break;
941944c9 317 }
d427b3b2
BJ
318 splx(s);
319 return (0);
e1d74936
BJ
320}
321
ae9a0a69 322ptcwrite(dev, uio)
941944c9 323 dev_t dev;
ae9a0a69 324 struct uio *uio;
e1d74936 325{
840510a3 326 register struct tty *tp = &pt_tty[minor(dev)];
45372428
MT
327 register char *cp, *ce;
328 register int cc;
329 char locbuf[BUFSIZ];
941944c9 330 int cnt = 0;
defdbcd1 331 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 332 int error = 0;
45372428 333
941944c9 334 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
840510a3 335 return (EIO);
defdbcd1 336 do {
ae9a0a69
BJ
337 register struct iovec *iov;
338
339 if (uio->uio_iovcnt == 0)
340 break;
341 iov = uio->uio_iov;
342 if (iov->iov_len == 0) {
343 uio->uio_iovcnt--;
344 uio->uio_iov++;
345 if (uio->uio_iovcnt < 0)
346 panic("ptcwrite");
347 continue;
348 }
349 cc = MIN(iov->iov_len, BUFSIZ);
45372428 350 cp = locbuf;
840510a3
BJ
351 error = uiomove(cp, cc, UIO_WRITE, uio);
352 if (error)
45372428
MT
353 break;
354 ce = cp + cc;
defdbcd1
BJ
355again:
356 if (pti->pt_flags & PF_REMOTE) {
357 if (tp->t_rawq.c_cc) {
358 if (pti->pt_flags & PF_NBIO) {
ae9a0a69
BJ
359 iov->iov_base -= ce - cp;
360 iov->iov_len += ce - cp;
361 uio->uio_resid += ce - cp;
362 uio->uio_offset -= ce - cp;
840510a3 363 return (EWOULDBLOCK);
defdbcd1
BJ
364 }
365 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
366 goto again;
367 }
668cc26d
SL
368 (void) b_to_q(cp, cc, &tp->t_rawq);
369 (void) putc(0, &tp->t_rawq);
defdbcd1 370 wakeup((caddr_t)&tp->t_rawq);
840510a3 371 return (0);
defdbcd1 372 }
e1d74936
BJ
373 while (cp < ce) {
374 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
45372428 375 wakeup((caddr_t)&tp->t_rawq);
941944c9 376 if (tp->t_state & TS_NBIO) {
ae9a0a69
BJ
377 iov->iov_base -= ce - cp;
378 iov->iov_len += ce - cp;
379 uio->uio_resid += ce - cp;
380 uio->uio_offset -= ce - cp;
941944c9 381 if (cnt == 0)
840510a3
BJ
382 return (EWOULDBLOCK);
383 return (0);
941944c9 384 }
45372428
MT
385 /* Better than just flushing it! */
386 /* Wait for something to be read */
387 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
defdbcd1 388 goto again;
45372428 389 }
36612a8f 390 (*linesw[tp->t_line].l_rint)(*cp++, tp);
941944c9 391 cnt++;
45372428 392 }
ae9a0a69 393 } while (uio->uio_resid);
840510a3 394 return (error);
45372428
MT
395}
396
45372428 397/*ARGSUSED*/
4b72e2f9
SL
398ptyioctl(dev, cmd, data, flag)
399 caddr_t data;
e1d74936
BJ
400 dev_t dev;
401{
0a2bd708
BJ
402 register struct tty *tp = &pt_tty[minor(dev)];
403 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
45372428 404
e1d74936 405 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4b72e2f9
SL
406 if (cdevsw[major(dev)].d_open == ptcopen)
407 switch (cmd) {
408
409 case TIOCPKT:
410 if (*(int *)data)
1a954a11
BJ
411 pti->pt_flags |= PF_PKT;
412 else
413 pti->pt_flags &= ~PF_PKT;
414 return;
4b72e2f9
SL
415
416 case TIOCREMOTE:
417 if (*(int *)data)
defdbcd1
BJ
418 pti->pt_flags |= PF_REMOTE;
419 else
420 pti->pt_flags &= ~PF_REMOTE;
421 flushtty(tp, FREAD|FWRITE);
422 return;
4b72e2f9
SL
423
424 case FIONBIO:
425 if (*(int *)data)
1a954a11 426 pti->pt_flags |= PF_NBIO;
8b8271ac 427 else
1a954a11 428 pti->pt_flags &= ~PF_NBIO;
8b8271ac 429 return;
4b72e2f9
SL
430
431 case TIOCSETP:
432 while (getc(&tp->t_outq) >= 0)
433 ;
434 break;
8b8271ac 435 }
4b72e2f9 436 if (ttioctl(tp, cmd, data, dev) == 0)
45372428 437 u.u_error = ENOTTY;
0a2bd708
BJ
438 { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
439 tp->t_un.t_chr.t_startc == ('q'&037));
440 if (pti->pt_flags & PF_NOSTOP) {
441 if (stop) {
442 pti->pt_send &= TIOCPKT_NOSTOP;
443 pti->pt_send |= TIOCPKT_DOSTOP;
444 pti->pt_flags &= ~PF_NOSTOP;
445 ptcwakeup(tp);
446 }
447 } else {
448 if (stop == 0) {
449 pti->pt_send &= ~TIOCPKT_DOSTOP;
450 pti->pt_send |= TIOCPKT_NOSTOP;
451 pti->pt_flags |= PF_NOSTOP;
452 ptcwakeup(tp);
453 }
454 }
455 }
45372428 456}
4f07e6e5 457#endif