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