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