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