Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
6a5ca8a0 | 6 | * @(#)tty_pty.c 7.3.1.1 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
be4367b3 | 8 | |
45372428 MT |
9 | /* |
10 | * Pseudo-teletype Driver | |
11 | * (Actually two drivers, requiring two entries in 'cdevsw') | |
45372428 | 12 | */ |
647d645f MT |
13 | #include "pty.h" |
14 | ||
f12183e4 | 15 | #if NPTY > 0 |
94368568 JB |
16 | #include "param.h" |
17 | #include "systm.h" | |
18 | #include "ioctl.h" | |
19 | #include "tty.h" | |
20 | #include "dir.h" | |
21 | #include "user.h" | |
22 | #include "conf.h" | |
23 | #include "file.h" | |
24 | #include "proc.h" | |
25 | #include "uio.h" | |
26 | #include "kernel.h" | |
6a5ca8a0 | 27 | #include "tsleep.h" |
941944c9 | 28 | |
b3c8737d | 29 | #if NPTY == 1 |
5bb90914 | 30 | #undef NPTY |
c91c01fe | 31 | #define NPTY 32 /* crude XXX */ |
b3c8737d | 32 | #endif |
45372428 | 33 | |
2bb0bef9 | 34 | #define BUFSIZ 100 /* Chunk size iomoved to/from user */ |
e1d74936 | 35 | |
45372428 | 36 | /* |
5bb90914 JB |
37 | * pts == /dev/tty[pqrs]? |
38 | * ptc == /dev/pty[pqrs]? | |
45372428 | 39 | */ |
e1d74936 BJ |
40 | struct tty pt_tty[NPTY]; |
41 | struct pt_ioctl { | |
1a954a11 | 42 | int pt_flags; |
1a954a11 | 43 | struct proc *pt_selr, *pt_selw; |
5bb90914 JB |
44 | u_char pt_send; |
45 | u_char pt_ucntl; | |
6a5ca8a0 | 46 | struct clist pt_ioc; |
e1d74936 | 47 | } pt_ioctl[NPTY]; |
5bb90914 | 48 | int npty = NPTY; /* for pstat -t */ |
45372428 | 49 | |
6a5ca8a0 KM |
50 | #define PF_RCOLL 0x0001 |
51 | #define PF_WCOLL 0x0002 | |
52 | #define PF_NBIO 0x0004 | |
53 | #define PF_PKT 0x0008 /* packet mode */ | |
54 | #define PF_STOPPED 0x0010 /* user told stopped */ | |
55 | #define PF_REMOTE 0x0020 /* remote and flow controlled input */ | |
56 | #define PF_NOSTOP 0x0040 | |
57 | #define PF_UCNTL 0x0080 /* user control mode */ | |
58 | #define PF_TIOC 0x0100 /* transparent control mode */ | |
59 | #define PF_LIOC 0x0200 /* transparent control locked */ | |
60 | #define PF_WIOC 0x0400 /* waiting for PF_LIOC to clear */ | |
61 | #define PF_BLOCK 0x0800 /* block writes to slave */ | |
62 | #define PF_OWAIT 0x1000 /* waiting for PF_BLOCK to clear */ | |
45372428 MT |
63 | |
64 | /*ARGSUSED*/ | |
65 | ptsopen(dev, flag) | |
73c77d38 | 66 | dev_t dev; |
e1d74936 | 67 | { |
45372428 | 68 | register struct tty *tp; |
5bb90914 | 69 | int error; |
45372428 | 70 | |
5bb90914 JB |
71 | #ifdef lint |
72 | npty = npty; | |
73 | #endif | |
f21c8fb8 BJ |
74 | if (minor(dev) >= NPTY) |
75 | return (ENXIO); | |
45372428 | 76 | tp = &pt_tty[minor(dev)]; |
941944c9 | 77 | if ((tp->t_state & TS_ISOPEN) == 0) { |
bdda6b91 | 78 | ttychars(tp); /* Set up default chars */ |
d2f24af0 | 79 | tp->t_ispeed = tp->t_ospeed = EXTB; |
bdda6b91 | 80 | tp->t_flags = 0; /* No features (nor raw mode) */ |
f21c8fb8 BJ |
81 | } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) |
82 | return (EBUSY); | |
e1d74936 | 83 | if (tp->t_oproc) /* Ctrlr still around. */ |
941944c9 BJ |
84 | tp->t_state |= TS_CARR_ON; |
85 | while ((tp->t_state & TS_CARR_ON) == 0) { | |
86 | tp->t_state |= TS_WOPEN; | |
45372428 MT |
87 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
88 | } | |
5bb90914 JB |
89 | error = (*linesw[tp->t_line].l_open)(dev, tp); |
90 | ptcwakeup(tp, FREAD|FWRITE); | |
91 | return (error); | |
45372428 MT |
92 | } |
93 | ||
94 | ptsclose(dev) | |
73c77d38 | 95 | dev_t dev; |
941944c9 | 96 | { |
45372428 MT |
97 | register struct tty *tp; |
98 | ||
99 | tp = &pt_tty[minor(dev)]; | |
100 | (*linesw[tp->t_line].l_close)(tp); | |
4b39cb77 | 101 | ttyclose(tp); |
5bb90914 | 102 | ptcwakeup(tp, FREAD|FWRITE); |
6a5ca8a0 | 103 | return (0); |
45372428 MT |
104 | } |
105 | ||
ae9a0a69 | 106 | ptsread(dev, uio) |
73c77d38 | 107 | dev_t dev; |
ae9a0a69 | 108 | struct uio *uio; |
e1d74936 | 109 | { |
defdbcd1 BJ |
110 | register struct tty *tp = &pt_tty[minor(dev)]; |
111 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
840510a3 | 112 | int error = 0; |
defdbcd1 BJ |
113 | |
114 | again: | |
115 | if (pti->pt_flags & PF_REMOTE) { | |
116 | while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { | |
5bb90914 JB |
117 | if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || |
118 | (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || | |
defdbcd1 | 119 | u.u_procp->p_flag&SVFORK) |
840510a3 | 120 | return (EIO); |
defdbcd1 BJ |
121 | gsignal(u.u_procp->p_pgrp, SIGTTIN); |
122 | sleep((caddr_t)&lbolt, TTIPRI); | |
941944c9 | 123 | } |
5bb90914 | 124 | if (tp->t_canq.c_cc == 0) { |
840510a3 BJ |
125 | if (tp->t_state & TS_NBIO) |
126 | return (EWOULDBLOCK); | |
5bb90914 | 127 | sleep((caddr_t)&tp->t_canq, TTIPRI); |
defdbcd1 BJ |
128 | goto again; |
129 | } | |
5bb90914 JB |
130 | while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) |
131 | if (ureadc(getc(&tp->t_canq), uio) < 0) { | |
840510a3 | 132 | error = EFAULT; |
ae9a0a69 BJ |
133 | break; |
134 | } | |
5bb90914 JB |
135 | if (tp->t_canq.c_cc == 1) |
136 | (void) getc(&tp->t_canq); | |
137 | if (tp->t_canq.c_cc) | |
840510a3 | 138 | return (error); |
defdbcd1 BJ |
139 | } else |
140 | if (tp->t_oproc) | |
840510a3 | 141 | error = (*linesw[tp->t_line].l_read)(tp, uio); |
5bb90914 | 142 | ptcwakeup(tp, FWRITE); |
840510a3 | 143 | return (error); |
45372428 MT |
144 | } |
145 | ||
941944c9 BJ |
146 | /* |
147 | * Write to pseudo-tty. | |
148 | * Wakeups of controlling tty will happen | |
149 | * indirectly, when tty driver calls ptsstart. | |
150 | */ | |
ae9a0a69 | 151 | ptswrite(dev, uio) |
73c77d38 | 152 | dev_t dev; |
ae9a0a69 | 153 | struct uio *uio; |
e1d74936 | 154 | { |
6a5ca8a0 KM |
155 | register struct tty *tp = &pt_tty[minor(dev)]; |
156 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
45372428 | 157 | |
840510a3 BJ |
158 | if (tp->t_oproc == 0) |
159 | return (EIO); | |
6a5ca8a0 KM |
160 | |
161 | while (pti->pt_flags & PF_BLOCK) { | |
162 | pti->pt_flags |= PF_OWAIT; | |
163 | sleep((caddr_t)pti + 1, TTOPRI); | |
164 | } | |
165 | ||
840510a3 | 166 | return ((*linesw[tp->t_line].l_write)(tp, uio)); |
45372428 MT |
167 | } |
168 | ||
941944c9 BJ |
169 | /* |
170 | * Start output on pseudo-tty. | |
171 | * Wake up process selecting or sleeping for input from controlling tty. | |
172 | */ | |
45372428 | 173 | ptsstart(tp) |
e1d74936 BJ |
174 | struct tty *tp; |
175 | { | |
1e6d24b1 | 176 | register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; |
e1d74936 | 177 | |
941944c9 | 178 | if (tp->t_state & TS_TTSTOP) |
45372428 | 179 | return; |
1e6d24b1 BJ |
180 | if (pti->pt_flags & PF_STOPPED) { |
181 | pti->pt_flags &= ~PF_STOPPED; | |
182 | pti->pt_send = TIOCPKT_START; | |
183 | } | |
5bb90914 | 184 | ptcwakeup(tp, FREAD); |
d427b3b2 BJ |
185 | } |
186 | ||
5bb90914 | 187 | ptcwakeup(tp, flag) |
d427b3b2 BJ |
188 | struct tty *tp; |
189 | { | |
190 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
191 | ||
5bb90914 JB |
192 | if (flag & FREAD) { |
193 | if (pti->pt_selr) { | |
194 | selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); | |
195 | pti->pt_selr = 0; | |
196 | pti->pt_flags &= ~PF_RCOLL; | |
197 | } | |
198 | wakeup((caddr_t)&tp->t_outq.c_cf); | |
199 | } | |
200 | if (flag & FWRITE) { | |
201 | if (pti->pt_selw) { | |
202 | selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); | |
203 | pti->pt_selw = 0; | |
204 | pti->pt_flags &= ~PF_WCOLL; | |
205 | } | |
206 | wakeup((caddr_t)&tp->t_rawq.c_cf); | |
e1d74936 | 207 | } |
45372428 MT |
208 | } |
209 | ||
210 | /*ARGSUSED*/ | |
211 | ptcopen(dev, flag) | |
e1d74936 BJ |
212 | dev_t dev; |
213 | int flag; | |
214 | { | |
45372428 | 215 | register struct tty *tp; |
1a954a11 | 216 | struct pt_ioctl *pti; |
45372428 | 217 | |
f21c8fb8 BJ |
218 | if (minor(dev) >= NPTY) |
219 | return (ENXIO); | |
45372428 | 220 | tp = &pt_tty[minor(dev)]; |
f21c8fb8 BJ |
221 | if (tp->t_oproc) |
222 | return (EIO); | |
e1d74936 | 223 | tp->t_oproc = ptsstart; |
f2f3b49b | 224 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); |
1a954a11 BJ |
225 | pti = &pt_ioctl[minor(dev)]; |
226 | pti->pt_flags = 0; | |
227 | pti->pt_send = 0; | |
5bb90914 | 228 | pti->pt_ucntl = 0; |
f21c8fb8 | 229 | return (0); |
45372428 MT |
230 | } |
231 | ||
232 | ptcclose(dev) | |
e1d74936 BJ |
233 | dev_t dev; |
234 | { | |
45372428 MT |
235 | register struct tty *tp; |
236 | ||
237 | tp = &pt_tty[minor(dev)]; | |
f2f3b49b | 238 | (void)(*linesw[tp->t_line].l_modem)(tp, 0); |
d3be7d55 | 239 | tp->t_state &= ~TS_CARR_ON; |
e1d74936 | 240 | tp->t_oproc = 0; /* mark closed */ |
6a5ca8a0 | 241 | return (0); |
45372428 MT |
242 | } |
243 | ||
ae9a0a69 | 244 | ptcread(dev, uio) |
1a954a11 | 245 | dev_t dev; |
ae9a0a69 | 246 | struct uio *uio; |
e1d74936 | 247 | { |
840510a3 | 248 | register struct tty *tp = &pt_tty[minor(dev)]; |
5bb90914 | 249 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
2bb0bef9 SL |
250 | char buf[BUFSIZ]; |
251 | int error = 0, cc; | |
45372428 | 252 | |
5bb90914 JB |
253 | /* |
254 | * We want to block until the slave | |
255 | * is open, and there's something to read; | |
256 | * but if we lost the slave or we're NBIO, | |
257 | * then return the appropriate error instead. | |
258 | */ | |
259 | for (;;) { | |
260 | if (tp->t_state&TS_ISOPEN) { | |
261 | if (pti->pt_flags&PF_PKT && pti->pt_send) { | |
8011f5df | 262 | error = ureadc((int)pti->pt_send, uio); |
5bb90914 JB |
263 | if (error) |
264 | return (error); | |
265 | pti->pt_send = 0; | |
266 | return (0); | |
267 | } | |
268 | if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { | |
8011f5df | 269 | error = ureadc((int)pti->pt_ucntl, uio); |
5bb90914 JB |
270 | if (error) |
271 | return (error); | |
272 | pti->pt_ucntl = 0; | |
273 | return (0); | |
274 | } | |
6a5ca8a0 KM |
275 | if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) { |
276 | if (uio->uio_resid < pti->pt_ioc.c_cc + 1) | |
277 | return (E2BIG); | |
278 | error = ureadc(TIOCPKT_TIOC, uio); | |
279 | while (error == 0 && pti->pt_ioc.c_cc > 0) { | |
280 | cc = q_to_b(&pti->pt_ioc, buf, | |
281 | MIN(pti->pt_ioc.c_cc, BUFSIZ)); | |
282 | if (cc <= 0) /* impossible? */ | |
283 | break; | |
284 | error = uiomove(buf, cc, UIO_READ, uio); | |
285 | } | |
286 | return (error); | |
287 | } | |
5bb90914 JB |
288 | if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) |
289 | break; | |
1a954a11 | 290 | } |
2bb0bef9 SL |
291 | if ((tp->t_state&TS_CARR_ON) == 0) |
292 | return (EIO); | |
840510a3 BJ |
293 | if (pti->pt_flags&PF_NBIO) |
294 | return (EWOULDBLOCK); | |
45372428 | 295 | sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); |
8b8271ac | 296 | } |
6a5ca8a0 | 297 | if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC)) |
5bb90914 | 298 | error = ureadc(0, uio); |
2bb0bef9 SL |
299 | while (uio->uio_resid > 0 && error == 0) { |
300 | cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); | |
301 | if (cc <= 0) | |
ae9a0a69 | 302 | break; |
2bb0bef9 SL |
303 | error = uiomove(buf, cc, UIO_READ, uio); |
304 | } | |
6a5ca8a0 KM |
305 | if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK)) |
306 | ptswake(tp); | |
840510a3 | 307 | return (error); |
45372428 MT |
308 | } |
309 | ||
6a5ca8a0 KM |
310 | ptswake(tp) |
311 | register struct tty *tp; | |
312 | { | |
313 | if (tp->t_state&TS_ASLEEP) { | |
314 | tp->t_state &= ~TS_ASLEEP; | |
315 | wakeup((caddr_t)&tp->t_outq); | |
316 | } | |
317 | if (tp->t_wsel) { | |
318 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
319 | tp->t_wsel = 0; | |
320 | tp->t_state &= ~TS_WCOLL; | |
321 | } | |
322 | } | |
323 | ||
1a954a11 BJ |
324 | ptsstop(tp, flush) |
325 | register struct tty *tp; | |
326 | int flush; | |
327 | { | |
328 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
5bb90914 | 329 | int flag; |
1a954a11 | 330 | |
1e6d24b1 BJ |
331 | /* note: FLUSHREAD and FLUSHWRITE already ok */ |
332 | if (flush == 0) { | |
333 | flush = TIOCPKT_STOP; | |
334 | pti->pt_flags |= PF_STOPPED; | |
5bb90914 | 335 | } else |
1e6d24b1 | 336 | pti->pt_flags &= ~PF_STOPPED; |
0a2bd708 | 337 | pti->pt_send |= flush; |
5bb90914 JB |
338 | /* change of perspective */ |
339 | flag = 0; | |
340 | if (flush & FREAD) | |
341 | flag |= FWRITE; | |
342 | if (flush & FWRITE) | |
343 | flag |= FREAD; | |
9d2a90b1 | 344 | ptcwakeup(tp, flag); |
1a954a11 BJ |
345 | } |
346 | ||
941944c9 | 347 | ptcselect(dev, rw) |
e1d74936 | 348 | dev_t dev; |
941944c9 | 349 | int rw; |
e1d74936 BJ |
350 | { |
351 | register struct tty *tp = &pt_tty[minor(dev)]; | |
defdbcd1 | 352 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
e1d74936 | 353 | struct proc *p; |
d427b3b2 | 354 | int s; |
e1d74936 | 355 | |
5bb90914 | 356 | if ((tp->t_state&TS_CARR_ON) == 0) |
e1d74936 | 357 | return (1); |
941944c9 BJ |
358 | switch (rw) { |
359 | ||
360 | case FREAD: | |
892f2f35 MK |
361 | /* |
362 | * Need to block timeouts (ttrstart). | |
363 | */ | |
364 | s = spltty(); | |
7cbd29e4 MK |
365 | if ((tp->t_state&TS_ISOPEN) && |
366 | tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { | |
367 | splx(s); | |
368 | return (1); | |
369 | } | |
892f2f35 | 370 | splx(s); |
7cbd29e4 MK |
371 | /* FALLTHROUGH */ |
372 | ||
373 | case 0: /* exceptional */ | |
5bb90914 JB |
374 | if ((tp->t_state&TS_ISOPEN) && |
375 | (pti->pt_flags&PF_PKT && pti->pt_send || | |
6a5ca8a0 | 376 | pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc || |
892f2f35 | 377 | pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) |
941944c9 | 378 | return (1); |
1a954a11 BJ |
379 | if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) |
380 | pti->pt_flags |= PF_RCOLL; | |
941944c9 | 381 | else |
1a954a11 | 382 | pti->pt_selr = u.u_procp; |
d427b3b2 | 383 | break; |
941944c9 | 384 | |
7cbd29e4 | 385 | |
941944c9 | 386 | case FWRITE: |
892f2f35 MK |
387 | if (tp->t_state&TS_ISOPEN) { |
388 | if (pti->pt_flags & PF_REMOTE) { | |
389 | if (tp->t_canq.c_cc == 0) | |
390 | return (1); | |
391 | } else { | |
392 | if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) | |
393 | return (1); | |
394 | if (tp->t_canq.c_cc == 0 && | |
aec7dd3b | 395 | (tp->t_flags & (RAW|CBREAK)) == 0) |
892f2f35 MK |
396 | return (1); |
397 | } | |
d427b3b2 | 398 | } |
1a954a11 BJ |
399 | if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) |
400 | pti->pt_flags |= PF_WCOLL; | |
941944c9 | 401 | else |
1a954a11 | 402 | pti->pt_selw = u.u_procp; |
d427b3b2 | 403 | break; |
7cbd29e4 | 404 | |
941944c9 | 405 | } |
d427b3b2 | 406 | return (0); |
e1d74936 BJ |
407 | } |
408 | ||
ae9a0a69 | 409 | ptcwrite(dev, uio) |
941944c9 | 410 | dev_t dev; |
5bb90914 | 411 | register struct uio *uio; |
e1d74936 | 412 | { |
840510a3 | 413 | register struct tty *tp = &pt_tty[minor(dev)]; |
5bb90914 JB |
414 | register struct iovec *iov; |
415 | register char *cp; | |
416 | register int cc = 0; | |
45372428 | 417 | char locbuf[BUFSIZ]; |
941944c9 | 418 | int cnt = 0; |
defdbcd1 | 419 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
840510a3 | 420 | int error = 0; |
45372428 | 421 | |
defdbcd1 | 422 | again: |
5bb90914 JB |
423 | if ((tp->t_state&TS_ISOPEN) == 0) |
424 | goto block; | |
9d2a90b1 | 425 | if (pti->pt_flags & PF_REMOTE) { |
5bb90914 JB |
426 | if (tp->t_canq.c_cc) |
427 | goto block; | |
9d2a90b1 JB |
428 | while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { |
429 | iov = uio->uio_iov; | |
430 | if (iov->iov_len == 0) { | |
431 | uio->uio_iovcnt--; | |
432 | uio->uio_iov++; | |
433 | continue; | |
434 | } | |
435 | if (cc == 0) { | |
436 | cc = MIN(iov->iov_len, BUFSIZ); | |
437 | cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); | |
438 | cp = locbuf; | |
439 | error = uiomove(cp, cc, UIO_WRITE, uio); | |
440 | if (error) | |
441 | return (error); | |
442 | /* check again for safety */ | |
443 | if ((tp->t_state&TS_ISOPEN) == 0) | |
444 | return (EIO); | |
445 | } | |
446 | if (cc) | |
447 | (void) b_to_q(cp, cc, &tp->t_canq); | |
448 | cc = 0; | |
defdbcd1 | 449 | } |
5bb90914 JB |
450 | (void) putc(0, &tp->t_canq); |
451 | ttwakeup(tp); | |
452 | wakeup((caddr_t)&tp->t_canq); | |
453 | return (0); | |
454 | } | |
455 | while (uio->uio_iovcnt > 0) { | |
456 | iov = uio->uio_iov; | |
457 | if (cc == 0) { | |
458 | if (iov->iov_len == 0) { | |
459 | uio->uio_iovcnt--; | |
460 | uio->uio_iov++; | |
461 | continue; | |
45372428 | 462 | } |
5bb90914 JB |
463 | cc = MIN(iov->iov_len, BUFSIZ); |
464 | cp = locbuf; | |
465 | error = uiomove(cp, cc, UIO_WRITE, uio); | |
466 | if (error) | |
467 | return (error); | |
468 | /* check again for safety */ | |
469 | if ((tp->t_state&TS_ISOPEN) == 0) | |
470 | return (EIO); | |
471 | } | |
9d2a90b1 JB |
472 | while (cc > 0) { |
473 | if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && | |
892f2f35 MK |
474 | (tp->t_canq.c_cc > 0 || |
475 | tp->t_flags & (RAW|CBREAK))) { | |
9d2a90b1 JB |
476 | wakeup((caddr_t)&tp->t_rawq); |
477 | goto block; | |
478 | } | |
36612a8f | 479 | (*linesw[tp->t_line].l_rint)(*cp++, tp); |
941944c9 | 480 | cnt++; |
9d2a90b1 | 481 | cc--; |
45372428 | 482 | } |
5bb90914 JB |
483 | cc = 0; |
484 | } | |
485 | return (0); | |
486 | block: | |
487 | /* | |
9d2a90b1 JB |
488 | * Come here to wait for slave to open, for space |
489 | * in outq, or space in rawq. | |
5bb90914 JB |
490 | */ |
491 | if ((tp->t_state&TS_CARR_ON) == 0) | |
492 | return (EIO); | |
493 | if (pti->pt_flags & PF_NBIO) { | |
5bb90914 JB |
494 | iov->iov_base -= cc; |
495 | iov->iov_len += cc; | |
496 | uio->uio_resid += cc; | |
497 | uio->uio_offset -= cc; | |
9d2a90b1 JB |
498 | if (cnt == 0) |
499 | return (EWOULDBLOCK); | |
5bb90914 JB |
500 | return (0); |
501 | } | |
502 | sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); | |
503 | goto again; | |
45372428 MT |
504 | } |
505 | ||
45372428 | 506 | /*ARGSUSED*/ |
4b72e2f9 SL |
507 | ptyioctl(dev, cmd, data, flag) |
508 | caddr_t data; | |
e1d74936 BJ |
509 | dev_t dev; |
510 | { | |
0a2bd708 BJ |
511 | register struct tty *tp = &pt_tty[minor(dev)]; |
512 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
5bb90914 | 513 | int stop, error; |
f2f3b49b | 514 | extern ttyinput(); |
45372428 | 515 | |
f2f3b49b MK |
516 | /* |
517 | * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. | |
518 | * ttywflush(tp) will hang if there are characters in the outq. | |
519 | */ | |
6a5ca8a0 KM |
520 | if (cdevsw[major(dev)].d_open == ptcopen) { |
521 | if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) { | |
522 | if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc) | |
523 | return (EINVAL); | |
524 | (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc); | |
525 | wakeup((caddr_t)&pti->pt_ioc); | |
526 | return (0); | |
527 | } | |
4b72e2f9 SL |
528 | switch (cmd) { |
529 | ||
530 | case TIOCPKT: | |
5bb90914 JB |
531 | if (*(int *)data) { |
532 | if (pti->pt_flags & PF_UCNTL) | |
533 | return (EINVAL); | |
1a954a11 | 534 | pti->pt_flags |= PF_PKT; |
5bb90914 | 535 | } else |
1a954a11 | 536 | pti->pt_flags &= ~PF_PKT; |
f21c8fb8 | 537 | return (0); |
4b72e2f9 | 538 | |
5bb90914 JB |
539 | case TIOCUCNTL: |
540 | if (*(int *)data) { | |
541 | if (pti->pt_flags & PF_PKT) | |
542 | return (EINVAL); | |
543 | pti->pt_flags |= PF_UCNTL; | |
544 | } else | |
545 | pti->pt_flags &= ~PF_UCNTL; | |
546 | return (0); | |
547 | ||
6a5ca8a0 KM |
548 | case TIOCTIOC: |
549 | if (*(int *)data) { | |
550 | if (pti->pt_flags & PF_UCNTL) | |
551 | return (EINVAL); | |
552 | pti->pt_flags |= PF_TIOC; | |
553 | } else { | |
554 | pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC); | |
555 | while (pti->pt_ioc.c_cc) | |
556 | (void) getc(&pti->pt_ioc); | |
557 | wakeup((caddr_t)&pti->pt_ioc); | |
558 | } | |
559 | return (0); | |
560 | ||
561 | case TIOCBLK: | |
562 | if (*(int *)data) | |
563 | pti->pt_flags |= PF_BLOCK; | |
564 | else { | |
565 | if (pti->pt_flags & PF_OWAIT) | |
566 | wakeup((caddr_t)pti + 1); | |
567 | pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT); | |
568 | ptswake(tp); | |
569 | } | |
570 | return (0); | |
571 | ||
4b72e2f9 SL |
572 | case TIOCREMOTE: |
573 | if (*(int *)data) | |
defdbcd1 BJ |
574 | pti->pt_flags |= PF_REMOTE; |
575 | else | |
576 | pti->pt_flags &= ~PF_REMOTE; | |
88a7a62a | 577 | ttyflush(tp, FREAD|FWRITE); |
f21c8fb8 | 578 | return (0); |
4b72e2f9 SL |
579 | |
580 | case FIONBIO: | |
581 | if (*(int *)data) | |
1a954a11 | 582 | pti->pt_flags |= PF_NBIO; |
8b8271ac | 583 | else |
1a954a11 | 584 | pti->pt_flags &= ~PF_NBIO; |
f21c8fb8 | 585 | return (0); |
4b72e2f9 | 586 | |
6a5ca8a0 KM |
587 | case FIONREAD: |
588 | *(int *)data = tp->t_outq.c_cc; | |
589 | return (0); | |
590 | ||
4b72e2f9 | 591 | case TIOCSETP: |
f2f3b49b MK |
592 | case TIOCSETN: |
593 | case TIOCSETD: | |
4b72e2f9 SL |
594 | while (getc(&tp->t_outq) >= 0) |
595 | ; | |
596 | break; | |
8b8271ac | 597 | } |
6a5ca8a0 KM |
598 | } else if (pti->pt_flags & PF_TIOC) { |
599 | while (pti->pt_flags & PF_LIOC) { | |
600 | pti->pt_flags |= PF_WIOC; | |
601 | switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) { | |
602 | case TS_OK: | |
603 | continue; | |
604 | case TS_SIG: | |
605 | case TS_TIME: | |
606 | return (EBUSY); | |
607 | } | |
608 | } | |
609 | pti->pt_flags |= PF_LIOC | PF_BLOCK; | |
610 | while (pti->pt_ioc.c_cc) | |
611 | (void) getc(&pti->pt_ioc); | |
612 | (void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc); | |
613 | if (cmd & IOC_IN) | |
614 | (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc); | |
615 | ptcwakeup(tp, FREAD); | |
616 | switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) { | |
617 | case TS_SIG: | |
618 | case TS_TIME: | |
619 | while (pti->pt_ioc.c_cc) | |
620 | (void) getc(&pti->pt_ioc); | |
621 | if (pti->pt_flags & PF_WIOC) | |
622 | wakeup((caddr_t)&pti->pt_flags); | |
623 | if (pti->pt_flags & PF_OWAIT) | |
624 | wakeup((caddr_t)pti + 1); | |
625 | pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); | |
626 | ptswake(tp); | |
627 | return (EBUSY); | |
628 | case TS_OK: | |
629 | break; | |
630 | } | |
631 | if (pti->pt_ioc.c_cc == 0) { | |
632 | if (pti->pt_flags & PF_WIOC) | |
633 | wakeup((caddr_t)&pti->pt_flags); | |
634 | if (pti->pt_flags & PF_OWAIT) | |
635 | wakeup((caddr_t)pti + 1); | |
636 | pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); | |
637 | ptswake(tp); | |
638 | goto doioctl; | |
639 | } | |
640 | if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error) | |
641 | error = EINVAL; | |
642 | if (error == 0 && cmd & IOC_OUT) { | |
643 | if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc) | |
644 | error = EINVAL; | |
645 | else | |
646 | (void) q_to_b(&pti->pt_ioc, data, | |
647 | pti->pt_ioc.c_cc); | |
648 | } | |
649 | while (pti->pt_ioc.c_cc) | |
650 | (void) getc(&pti->pt_ioc); | |
651 | if (pti->pt_flags & PF_WIOC) | |
652 | wakeup((caddr_t)&pti->pt_flags); | |
653 | if (pti->pt_flags & PF_OWAIT) | |
654 | wakeup((caddr_t)pti + 1); | |
655 | pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); | |
656 | ptswake(tp); | |
657 | return (error); | |
658 | } | |
659 | ||
660 | doioctl: | |
477d62ec | 661 | error = ttioctl(tp, cmd, data, flag); |
f2f3b49b MK |
662 | /* |
663 | * Since we use the tty queues internally, | |
664 | * pty's can't be switched to disciplines which overwrite | |
665 | * the queues. We can't tell anything about the discipline | |
666 | * from here... | |
6a5ca8a0 KM |
667 | * |
668 | * Nb: this is not really good enough, the line disc open routine | |
669 | * may have done anything at all, no guarantees that close | |
670 | * will fix it. This also has the effect of losing the | |
671 | * previous discipline, which an error on a TIOCSETD shouldn't | |
672 | * do... Sometime it should be done via an explicit check | |
673 | * for TIOCSETD, then check to see what linesw[new_number].l_rint | |
674 | * really is. | |
f2f3b49b MK |
675 | */ |
676 | if (linesw[tp->t_line].l_rint != ttyinput) { | |
677 | (*linesw[tp->t_line].l_close)(tp); | |
678 | tp->t_line = 0; | |
679 | (void)(*linesw[tp->t_line].l_open)(dev, tp); | |
680 | error = ENOTTY; | |
681 | } | |
6a5ca8a0 | 682 | |
5bb90914 JB |
683 | if (error < 0) { |
684 | if (pti->pt_flags & PF_UCNTL && | |
97d7430f | 685 | (cmd & ~0xff) == UIOCCMD(0)) { |
5bb90914 JB |
686 | if (cmd & 0xff) { |
687 | pti->pt_ucntl = (u_char)cmd; | |
688 | ptcwakeup(tp, FREAD); | |
689 | } | |
690 | return (0); | |
691 | } | |
f21c8fb8 | 692 | error = ENOTTY; |
5bb90914 JB |
693 | } |
694 | stop = (tp->t_flags & RAW) == 0 && | |
c16520ef | 695 | tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q'); |
0a2bd708 BJ |
696 | if (pti->pt_flags & PF_NOSTOP) { |
697 | if (stop) { | |
b31eb1ff | 698 | pti->pt_send &= ~TIOCPKT_NOSTOP; |
0a2bd708 BJ |
699 | pti->pt_send |= TIOCPKT_DOSTOP; |
700 | pti->pt_flags &= ~PF_NOSTOP; | |
5bb90914 | 701 | ptcwakeup(tp, FREAD); |
0a2bd708 BJ |
702 | } |
703 | } else { | |
5bb90914 | 704 | if (!stop) { |
0a2bd708 BJ |
705 | pti->pt_send &= ~TIOCPKT_DOSTOP; |
706 | pti->pt_send |= TIOCPKT_NOSTOP; | |
707 | pti->pt_flags |= PF_NOSTOP; | |
5bb90914 | 708 | ptcwakeup(tp, FREAD); |
0a2bd708 BJ |
709 | } |
710 | } | |
f21c8fb8 | 711 | return (error); |
45372428 | 712 | } |
4f07e6e5 | 713 | #endif |