1 /* tty_pty.c 4.24 82/08/22 */ 2 3 /* 4 * Pseudo-teletype Driver 5 * (Actually two drivers, requiring two entries in 'cdevsw') 6 */ 7 #include "pty.h" 8 9 #if NPTY > 0 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/file.h" 17 #include "../h/proc.h" 18 #include "../h/uio.h" 19 20 #if NPTY == 1 21 #undef NPTY 22 #define NPTY 32 /* crude XXX */ 23 #endif 24 25 #define BUFSIZ 100 /* Chunk size iomoved from user */ 26 27 /* 28 * pts == /dev/tty[pP]? 29 * ptc == /dev/ptp[pP]? 30 */ 31 struct tty pt_tty[NPTY]; 32 struct pt_ioctl { 33 int pt_flags; 34 int pt_gensym; 35 struct proc *pt_selr, *pt_selw; 36 int pt_send; 37 } pt_ioctl[NPTY]; 38 39 #define PF_RCOLL 0x01 40 #define PF_WCOLL 0x02 41 #define PF_NBIO 0x04 42 #define PF_PKT 0x08 /* packet mode */ 43 #define PF_STOPPED 0x10 /* user told stopped */ 44 #define PF_REMOTE 0x20 /* remote and flow controlled input */ 45 #define PF_NOSTOP 0x40 46 47 /*ARGSUSED*/ 48 ptsopen(dev, flag) 49 dev_t dev; 50 { 51 register struct tty *tp; 52 53 if (minor(dev) >= NPTY) { 54 u.u_error = ENXIO; 55 return; 56 } 57 tp = &pt_tty[minor(dev)]; 58 if ((tp->t_state & TS_ISOPEN) == 0) { 59 ttychars(tp); /* Set up default chars */ 60 tp->t_flags = 0; /* No features (nor raw mode) */ 61 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 62 u.u_error = EBUSY; 63 return; 64 } 65 if (tp->t_oproc) /* Ctrlr still around. */ 66 tp->t_state |= TS_CARR_ON; 67 while ((tp->t_state & TS_CARR_ON) == 0) { 68 tp->t_state |= TS_WOPEN; 69 sleep((caddr_t)&tp->t_rawq, TTIPRI); 70 } 71 (*linesw[tp->t_line].l_open)(dev, tp); 72 } 73 74 ptsclose(dev) 75 dev_t dev; 76 { 77 register struct tty *tp; 78 79 tp = &pt_tty[minor(dev)]; 80 (*linesw[tp->t_line].l_close)(tp); 81 ttyclose(tp); 82 } 83 84 ptsread(dev, uio) 85 dev_t dev; 86 struct uio *uio; 87 { 88 register struct tty *tp = &pt_tty[minor(dev)]; 89 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 90 91 again: 92 if (pti->pt_flags & PF_REMOTE) { 93 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 94 if (u.u_signal[SIGTTIN] == SIG_IGN || 95 u.u_signal[SIGTTIN] == SIG_HOLD || 96 /* 97 (u.u_procp->p_flag&SDETACH) || 98 */ 99 u.u_procp->p_flag&SVFORK) 100 return; 101 gsignal(u.u_procp->p_pgrp, SIGTTIN); 102 sleep((caddr_t)&lbolt, TTIPRI); 103 } 104 if (tp->t_rawq.c_cc == 0) { 105 if (tp->t_state & TS_NBIO) { 106 u.u_error = EWOULDBLOCK; 107 return; 108 } 109 sleep((caddr_t)&tp->t_rawq, TTIPRI); 110 goto again; 111 } 112 while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 113 if (ureadc(getc(&tp->t_rawq), uio) < 0) { 114 u.u_error = EFAULT; 115 break; 116 } 117 if (tp->t_rawq.c_cc == 1) 118 (void) getc(&tp->t_rawq); 119 if (tp->t_rawq.c_cc) 120 return; 121 } else 122 if (tp->t_oproc) 123 (*linesw[tp->t_line].l_read)(tp, uio); 124 wakeup((caddr_t)&tp->t_rawq.c_cf); 125 if (pti->pt_selw) { 126 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 127 pti->pt_selw = 0; 128 pti->pt_flags &= ~PF_WCOLL; 129 } 130 } 131 132 /* 133 * Write to pseudo-tty. 134 * Wakeups of controlling tty will happen 135 * indirectly, when tty driver calls ptsstart. 136 */ 137 ptswrite(dev, uio) 138 dev_t dev; 139 struct uio *uio; 140 { 141 register struct tty *tp; 142 143 tp = &pt_tty[minor(dev)]; 144 if (tp->t_oproc) 145 (*linesw[tp->t_line].l_write)(tp, uio); 146 } 147 148 /* 149 * Start output on pseudo-tty. 150 * Wake up process selecting or sleeping for input from controlling tty. 151 */ 152 ptsstart(tp) 153 struct tty *tp; 154 { 155 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 156 157 if (tp->t_state & TS_TTSTOP) 158 return; 159 if (pti->pt_flags & PF_STOPPED) { 160 pti->pt_flags &= ~PF_STOPPED; 161 pti->pt_send = TIOCPKT_START; 162 } 163 ptcwakeup(tp); 164 } 165 166 ptcwakeup(tp) 167 struct tty *tp; 168 { 169 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 170 171 if (pti->pt_selr) { 172 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 173 pti->pt_selr = 0; 174 pti->pt_flags &= ~PF_RCOLL; 175 } 176 wakeup((caddr_t)&tp->t_outq.c_cf); 177 } 178 179 /*ARGSUSED*/ 180 ptcopen(dev, flag) 181 dev_t dev; 182 int flag; 183 { 184 register struct tty *tp; 185 struct pt_ioctl *pti; 186 187 if (minor(dev) >= NPTY) { 188 u.u_error = ENXIO; 189 return; 190 } 191 tp = &pt_tty[minor(dev)]; 192 if (tp->t_oproc) { 193 u.u_error = EIO; 194 return; 195 } 196 tp->t_oproc = ptsstart; 197 if (tp->t_state & TS_WOPEN) 198 wakeup((caddr_t)&tp->t_rawq); 199 tp->t_state |= TS_CARR_ON; 200 pti = &pt_ioctl[minor(dev)]; 201 pti->pt_flags = 0; 202 pti->pt_send = 0; 203 } 204 205 ptcclose(dev) 206 dev_t dev; 207 { 208 register struct tty *tp; 209 210 tp = &pt_tty[minor(dev)]; 211 if (tp->t_state & TS_ISOPEN) 212 gsignal(tp->t_pgrp, SIGHUP); 213 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 214 flushtty(tp, FREAD|FWRITE); 215 tp->t_oproc = 0; /* mark closed */ 216 } 217 218 ptcread(dev, uio) 219 dev_t dev; 220 struct uio *uio; 221 { 222 register struct tty *tp; 223 struct pt_ioctl *pti; 224 225 tp = &pt_tty[minor(dev)]; 226 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 227 return; 228 pti = &pt_ioctl[minor(dev)]; 229 if (pti->pt_flags & PF_PKT) { 230 if (pti->pt_send) { 231 (void) ureadc(pti->pt_send, uio); 232 pti->pt_send = 0; 233 return; 234 } 235 (void) ureadc(0, uio); 236 } 237 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 238 if (pti->pt_flags&PF_NBIO) { 239 u.u_error = EWOULDBLOCK; 240 return; 241 } 242 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 243 } 244 while (tp->t_outq.c_cc && uio->uio_resid > 0) 245 if (ureadc(getc(&tp->t_outq), uio) < 0) { 246 u.u_error = EFAULT; 247 break; 248 } 249 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 250 if (tp->t_state&TS_ASLEEP) { 251 tp->t_state &= ~TS_ASLEEP; 252 wakeup((caddr_t)&tp->t_outq); 253 } 254 if (tp->t_wsel) { 255 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 256 tp->t_wsel = 0; 257 tp->t_state &= ~TS_WCOLL; 258 } 259 } 260 } 261 262 ptsstop(tp, flush) 263 register struct tty *tp; 264 int flush; 265 { 266 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 267 268 /* note: FLUSHREAD and FLUSHWRITE already ok */ 269 if (flush == 0) { 270 flush = TIOCPKT_STOP; 271 pti->pt_flags |= PF_STOPPED; 272 } else { 273 pti->pt_flags &= ~PF_STOPPED; 274 } 275 pti->pt_send |= flush; 276 ptcwakeup(tp); 277 } 278 279 ptcselect(dev, rw) 280 dev_t dev; 281 int rw; 282 { 283 register struct tty *tp = &pt_tty[minor(dev)]; 284 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 285 struct proc *p; 286 int s; 287 288 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 289 return (1); 290 s = spl5(); 291 switch (rw) { 292 293 case FREAD: 294 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 295 splx(s); 296 return (1); 297 } 298 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 299 pti->pt_flags |= PF_RCOLL; 300 else 301 pti->pt_selr = u.u_procp; 302 break; 303 304 case FWRITE: 305 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 306 splx(s); 307 return (1); 308 } 309 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 310 pti->pt_flags |= PF_WCOLL; 311 else 312 pti->pt_selw = u.u_procp; 313 break; 314 } 315 splx(s); 316 return (0); 317 } 318 319 ptcwrite(dev, uio) 320 dev_t dev; 321 struct uio *uio; 322 { 323 register struct tty *tp; 324 register char *cp, *ce; 325 register int cc; 326 char locbuf[BUFSIZ]; 327 int cnt = 0; 328 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 329 330 tp = &pt_tty[minor(dev)]; 331 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 332 return; 333 do { 334 register struct iovec *iov; 335 336 if (uio->uio_iovcnt == 0) 337 break; 338 iov = uio->uio_iov; 339 if (iov->iov_len == 0) { 340 uio->uio_iovcnt--; 341 uio->uio_iov++; 342 if (uio->uio_iovcnt < 0) 343 panic("ptcwrite"); 344 continue; 345 } 346 cc = MIN(iov->iov_len, BUFSIZ); 347 cp = locbuf; 348 u.u_error = uiomove(cp, cc, UIO_WRITE, uio); 349 if (u.u_error) 350 break; 351 ce = cp + cc; 352 again: 353 if (pti->pt_flags & PF_REMOTE) { 354 if (tp->t_rawq.c_cc) { 355 if (pti->pt_flags & PF_NBIO) { 356 iov->iov_base -= ce - cp; 357 iov->iov_len += ce - cp; 358 uio->uio_resid += ce - cp; 359 uio->uio_offset -= ce - cp; 360 u.u_error = EWOULDBLOCK; 361 return; 362 } 363 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 364 goto again; 365 } 366 (void) b_to_q(cp, cc, &tp->t_rawq); 367 (void) putc(0, &tp->t_rawq); 368 wakeup((caddr_t)&tp->t_rawq); 369 return; 370 } 371 while (cp < ce) { 372 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 373 wakeup((caddr_t)&tp->t_rawq); 374 if (tp->t_state & TS_NBIO) { 375 iov->iov_base -= ce - cp; 376 iov->iov_len += ce - cp; 377 uio->uio_resid += ce - cp; 378 uio->uio_offset -= ce - cp; 379 if (cnt == 0) 380 u.u_error = EWOULDBLOCK; 381 return; 382 } 383 /* Better than just flushing it! */ 384 /* Wait for something to be read */ 385 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 386 goto again; 387 } 388 (*linesw[tp->t_line].l_rint)(*cp++, tp); 389 cnt++; 390 } 391 } while (uio->uio_resid); 392 } 393 394 /*ARGSUSED*/ 395 ptyioctl(dev, cmd, data, flag) 396 caddr_t data; 397 dev_t dev; 398 { 399 register struct tty *tp = &pt_tty[minor(dev)]; 400 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 401 402 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 403 if (cdevsw[major(dev)].d_open == ptcopen) 404 switch (cmd) { 405 406 case TIOCPKT: 407 if (*(int *)data) 408 pti->pt_flags |= PF_PKT; 409 else 410 pti->pt_flags &= ~PF_PKT; 411 return; 412 413 case TIOCREMOTE: 414 if (*(int *)data) 415 pti->pt_flags |= PF_REMOTE; 416 else 417 pti->pt_flags &= ~PF_REMOTE; 418 flushtty(tp, FREAD|FWRITE); 419 return; 420 421 case FIONBIO: 422 if (*(int *)data) 423 pti->pt_flags |= PF_NBIO; 424 else 425 pti->pt_flags &= ~PF_NBIO; 426 return; 427 428 case TIOCSETP: 429 while (getc(&tp->t_outq) >= 0) 430 ; 431 break; 432 } 433 if (ttioctl(tp, cmd, data, dev) == 0) 434 u.u_error = ENOTTY; 435 { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 436 tp->t_un.t_chr.t_startc == ('q'&037)); 437 if (pti->pt_flags & PF_NOSTOP) { 438 if (stop) { 439 pti->pt_send &= TIOCPKT_NOSTOP; 440 pti->pt_send |= TIOCPKT_DOSTOP; 441 pti->pt_flags &= ~PF_NOSTOP; 442 ptcwakeup(tp); 443 } 444 } else { 445 if (stop == 0) { 446 pti->pt_send &= ~TIOCPKT_DOSTOP; 447 pti->pt_send |= TIOCPKT_NOSTOP; 448 pti->pt_flags |= PF_NOSTOP; 449 ptcwakeup(tp); 450 } 451 } 452 } 453 } 454 #endif 455