1 /* tty_pty.c 4.26 82/10/13 */ 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 int error = 0; 92 93 again: 94 if (pti->pt_flags & PF_REMOTE) { 95 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 96 if (u.u_signal[SIGTTIN] == SIG_IGN || 97 u.u_signal[SIGTTIN] == SIG_HOLD || 98 /* 99 (u.u_procp->p_flag&SDETACH) || 100 */ 101 u.u_procp->p_flag&SVFORK) 102 return (EIO); 103 gsignal(u.u_procp->p_pgrp, SIGTTIN); 104 sleep((caddr_t)&lbolt, TTIPRI); 105 } 106 if (tp->t_rawq.c_cc == 0) { 107 if (tp->t_state & TS_NBIO) 108 return (EWOULDBLOCK); 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 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 (error); 121 } else 122 if (tp->t_oproc) 123 error = (*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 return (error); 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 == 0) 146 return (EIO); 147 return ((*linesw[tp->t_line].l_write)(tp, uio)); 148 } 149 150 /* 151 * Start output on pseudo-tty. 152 * Wake up process selecting or sleeping for input from controlling tty. 153 */ 154 ptsstart(tp) 155 struct tty *tp; 156 { 157 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 158 159 if (tp->t_state & TS_TTSTOP) 160 return; 161 if (pti->pt_flags & PF_STOPPED) { 162 pti->pt_flags &= ~PF_STOPPED; 163 pti->pt_send = TIOCPKT_START; 164 } 165 ptcwakeup(tp); 166 } 167 168 ptcwakeup(tp) 169 struct tty *tp; 170 { 171 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 172 173 if (pti->pt_selr) { 174 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 175 pti->pt_selr = 0; 176 pti->pt_flags &= ~PF_RCOLL; 177 } 178 wakeup((caddr_t)&tp->t_outq.c_cf); 179 } 180 181 /*ARGSUSED*/ 182 ptcopen(dev, flag) 183 dev_t dev; 184 int flag; 185 { 186 register struct tty *tp; 187 struct pt_ioctl *pti; 188 189 if (minor(dev) >= NPTY) { 190 u.u_error = ENXIO; 191 return; 192 } 193 tp = &pt_tty[minor(dev)]; 194 if (tp->t_oproc) { 195 u.u_error = EIO; 196 return; 197 } 198 tp->t_oproc = ptsstart; 199 if (tp->t_state & TS_WOPEN) 200 wakeup((caddr_t)&tp->t_rawq); 201 tp->t_state |= TS_CARR_ON; 202 pti = &pt_ioctl[minor(dev)]; 203 pti->pt_flags = 0; 204 pti->pt_send = 0; 205 } 206 207 ptcclose(dev) 208 dev_t dev; 209 { 210 register struct tty *tp; 211 212 tp = &pt_tty[minor(dev)]; 213 if (tp->t_state & TS_ISOPEN) 214 gsignal(tp->t_pgrp, SIGHUP); 215 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 216 flushtty(tp, FREAD|FWRITE); 217 tp->t_oproc = 0; /* mark closed */ 218 } 219 220 ptcread(dev, uio) 221 dev_t dev; 222 struct uio *uio; 223 { 224 register struct tty *tp = &pt_tty[minor(dev)]; 225 struct pt_ioctl *pti; 226 int error = 0; 227 228 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 229 return; 230 pti = &pt_ioctl[minor(dev)]; 231 if (pti->pt_flags & PF_PKT) { 232 if (pti->pt_send) { 233 error = ureadc(pti->pt_send, uio); 234 if (error) 235 return (error); 236 pti->pt_send = 0; 237 return (0); 238 } 239 error = ureadc(0, uio); 240 } 241 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 242 if (pti->pt_flags&PF_NBIO) 243 return (EWOULDBLOCK); 244 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 245 } 246 while (tp->t_outq.c_cc && uio->uio_resid > 0) 247 if (ureadc(getc(&tp->t_outq), uio) < 0) { 248 error = EFAULT; 249 break; 250 } 251 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 252 if (tp->t_state&TS_ASLEEP) { 253 tp->t_state &= ~TS_ASLEEP; 254 wakeup((caddr_t)&tp->t_outq); 255 } 256 if (tp->t_wsel) { 257 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 258 tp->t_wsel = 0; 259 tp->t_state &= ~TS_WCOLL; 260 } 261 } 262 return (error); 263 } 264 265 ptsstop(tp, flush) 266 register struct tty *tp; 267 int flush; 268 { 269 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 270 271 /* note: FLUSHREAD and FLUSHWRITE already ok */ 272 if (flush == 0) { 273 flush = TIOCPKT_STOP; 274 pti->pt_flags |= PF_STOPPED; 275 } else { 276 pti->pt_flags &= ~PF_STOPPED; 277 } 278 pti->pt_send |= flush; 279 ptcwakeup(tp); 280 } 281 282 ptcselect(dev, rw) 283 dev_t dev; 284 int rw; 285 { 286 register struct tty *tp = &pt_tty[minor(dev)]; 287 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 288 struct proc *p; 289 int s; 290 291 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 292 return (1); 293 s = spl5(); 294 switch (rw) { 295 296 case FREAD: 297 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 298 splx(s); 299 return (1); 300 } 301 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 302 pti->pt_flags |= PF_RCOLL; 303 else 304 pti->pt_selr = u.u_procp; 305 break; 306 307 case FWRITE: 308 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 309 splx(s); 310 return (1); 311 } 312 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 313 pti->pt_flags |= PF_WCOLL; 314 else 315 pti->pt_selw = u.u_procp; 316 break; 317 } 318 splx(s); 319 return (0); 320 } 321 322 ptcwrite(dev, uio) 323 dev_t dev; 324 struct uio *uio; 325 { 326 register struct tty *tp = &pt_tty[minor(dev)]; 327 register char *cp, *ce; 328 register int cc; 329 char locbuf[BUFSIZ]; 330 int cnt = 0; 331 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 332 int error = 0; 333 334 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 335 return (EIO); 336 do { 337 register struct iovec *iov; 338 339 if (uio->uio_iovcnt == 0) 340 break; 341 iov = uio->uio_iov; 342 if (iov->iov_len == 0) { 343 uio->uio_iovcnt--; 344 uio->uio_iov++; 345 if (uio->uio_iovcnt < 0) 346 panic("ptcwrite"); 347 continue; 348 } 349 cc = MIN(iov->iov_len, BUFSIZ); 350 cp = locbuf; 351 error = uiomove(cp, cc, UIO_WRITE, uio); 352 if (error) 353 break; 354 ce = cp + cc; 355 again: 356 if (pti->pt_flags & PF_REMOTE) { 357 if (tp->t_rawq.c_cc) { 358 if (pti->pt_flags & PF_NBIO) { 359 iov->iov_base -= ce - cp; 360 iov->iov_len += ce - cp; 361 uio->uio_resid += ce - cp; 362 uio->uio_offset -= ce - cp; 363 return (EWOULDBLOCK); 364 } 365 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 366 goto again; 367 } 368 (void) b_to_q(cp, cc, &tp->t_rawq); 369 (void) putc(0, &tp->t_rawq); 370 wakeup((caddr_t)&tp->t_rawq); 371 return (0); 372 } 373 while (cp < ce) { 374 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 375 wakeup((caddr_t)&tp->t_rawq); 376 if (tp->t_state & TS_NBIO) { 377 iov->iov_base -= ce - cp; 378 iov->iov_len += ce - cp; 379 uio->uio_resid += ce - cp; 380 uio->uio_offset -= ce - cp; 381 if (cnt == 0) 382 return (EWOULDBLOCK); 383 return (0); 384 } 385 /* Better than just flushing it! */ 386 /* Wait for something to be read */ 387 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 388 goto again; 389 } 390 (*linesw[tp->t_line].l_rint)(*cp++, tp); 391 cnt++; 392 } 393 } while (uio->uio_resid); 394 return (error); 395 } 396 397 /*ARGSUSED*/ 398 ptyioctl(dev, cmd, data, flag) 399 caddr_t data; 400 dev_t dev; 401 { 402 register struct tty *tp = &pt_tty[minor(dev)]; 403 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 404 405 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 406 if (cdevsw[major(dev)].d_open == ptcopen) 407 switch (cmd) { 408 409 case TIOCPKT: 410 if (*(int *)data) 411 pti->pt_flags |= PF_PKT; 412 else 413 pti->pt_flags &= ~PF_PKT; 414 return; 415 416 case TIOCREMOTE: 417 if (*(int *)data) 418 pti->pt_flags |= PF_REMOTE; 419 else 420 pti->pt_flags &= ~PF_REMOTE; 421 flushtty(tp, FREAD|FWRITE); 422 return; 423 424 case FIONBIO: 425 if (*(int *)data) 426 pti->pt_flags |= PF_NBIO; 427 else 428 pti->pt_flags &= ~PF_NBIO; 429 return; 430 431 case TIOCSETP: 432 while (getc(&tp->t_outq) >= 0) 433 ; 434 break; 435 } 436 if (ttioctl(tp, cmd, data, dev) == 0) 437 u.u_error = ENOTTY; 438 { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 439 tp->t_un.t_chr.t_startc == ('q'&037)); 440 if (pti->pt_flags & PF_NOSTOP) { 441 if (stop) { 442 pti->pt_send &= TIOCPKT_NOSTOP; 443 pti->pt_send |= TIOCPKT_DOSTOP; 444 pti->pt_flags &= ~PF_NOSTOP; 445 ptcwakeup(tp); 446 } 447 } else { 448 if (stop == 0) { 449 pti->pt_send &= ~TIOCPKT_DOSTOP; 450 pti->pt_send |= TIOCPKT_NOSTOP; 451 pti->pt_flags |= PF_NOSTOP; 452 ptcwakeup(tp); 453 } 454 } 455 } 456 } 457 #endif 458