Commit | Line | Data |
---|---|---|
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 |
29 | struct tty pt_tty[NPTY]; |
30 | struct 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*/ | |
46 | ptsopen(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 | ||
72 | ptsclose(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 | ||
82 | ptsread(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 | ||
88 | again: | |
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 | 131 | ptswrite(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 | 145 | ptsstart(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 | ||
159 | ptcwakeup(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*/ | |
173 | ptcopen(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 | ||
198 | ptcclose(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 | ||
211 | ptcread(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 |
251 | ptsstop(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 | 268 | ptcselect(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 | 308 | ptcwrite(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 |
328 | again: |
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*/ |
365 | ptyioctl(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 |