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