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