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