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