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