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