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