1 /* tty_pty.c 6.4 84/02/15 */ 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 #define bit(a) (1<<(a-1)) 95 if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 96 (u.u_procp->p_sigmask & bit(SIGTTIN)) || 97 /* 98 (u.u_procp->p_flag&SDETACH) || 99 */ 100 u.u_procp->p_flag&SVFORK) 101 return (EIO); 102 gsignal(u.u_procp->p_pgrp, SIGTTIN); 103 sleep((caddr_t)&lbolt, TTIPRI); 104 } 105 #undef bit 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 return (ENXIO); 191 tp = &pt_tty[minor(dev)]; 192 if (tp->t_oproc) 193 return (EIO); 194 tp->t_oproc = ptsstart; 195 if (tp->t_state & TS_WOPEN) 196 wakeup((caddr_t)&tp->t_rawq); 197 tp->t_state |= TS_CARR_ON; 198 pti = &pt_ioctl[minor(dev)]; 199 pti->pt_flags = 0; 200 pti->pt_send = 0; 201 return (0); 202 } 203 204 ptcclose(dev) 205 dev_t dev; 206 { 207 register struct tty *tp; 208 209 tp = &pt_tty[minor(dev)]; 210 if (tp->t_state & TS_ISOPEN) 211 gsignal(tp->t_pgrp, SIGHUP); 212 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 213 ttyflush(tp, FREAD|FWRITE); 214 tp->t_oproc = 0; /* mark closed */ 215 } 216 217 ptcread(dev, uio) 218 dev_t dev; 219 struct uio *uio; 220 { 221 register struct tty *tp = &pt_tty[minor(dev)]; 222 struct pt_ioctl *pti; 223 int error = 0; 224 225 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 226 return (EIO); 227 pti = &pt_ioctl[minor(dev)]; 228 if (pti->pt_flags & PF_PKT) { 229 if (pti->pt_send) { 230 error = ureadc(pti->pt_send, uio); 231 if (error) 232 return (error); 233 pti->pt_send = 0; 234 return (0); 235 } 236 error = 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 return (EWOULDBLOCK); 241 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 242 } 243 while (tp->t_outq.c_cc && uio->uio_resid > 0) 244 if (ureadc(getc(&tp->t_outq), uio) < 0) { 245 error = EFAULT; 246 break; 247 } 248 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 249 if (tp->t_state&TS_ASLEEP) { 250 tp->t_state &= ~TS_ASLEEP; 251 wakeup((caddr_t)&tp->t_outq); 252 } 253 if (tp->t_wsel) { 254 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 255 tp->t_wsel = 0; 256 tp->t_state &= ~TS_WCOLL; 257 } 258 } 259 return (error); 260 } 261 262 ptsstop(tp, flush) 263 register struct tty *tp; 264 int flush; 265 { 266 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 267 268 /* note: FLUSHREAD and FLUSHWRITE already ok */ 269 if (flush == 0) { 270 flush = TIOCPKT_STOP; 271 pti->pt_flags |= PF_STOPPED; 272 } else { 273 pti->pt_flags &= ~PF_STOPPED; 274 } 275 pti->pt_send |= flush; 276 ptcwakeup(tp); 277 } 278 279 ptcselect(dev, rw) 280 dev_t dev; 281 int rw; 282 { 283 register struct tty *tp = &pt_tty[minor(dev)]; 284 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 285 struct proc *p; 286 int s; 287 288 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 289 return (1); 290 s = spl5(); 291 switch (rw) { 292 293 case FREAD: 294 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 295 splx(s); 296 return (1); 297 } 298 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 299 pti->pt_flags |= PF_RCOLL; 300 else 301 pti->pt_selr = u.u_procp; 302 break; 303 304 case FWRITE: 305 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 306 splx(s); 307 return (1); 308 } 309 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 310 pti->pt_flags |= PF_WCOLL; 311 else 312 pti->pt_selw = u.u_procp; 313 break; 314 } 315 splx(s); 316 return (0); 317 } 318 319 ptcwrite(dev, uio) 320 dev_t dev; 321 struct uio *uio; 322 { 323 register struct tty *tp = &pt_tty[minor(dev)]; 324 register char *cp, *ce; 325 register int cc; 326 char locbuf[BUFSIZ]; 327 int cnt = 0; 328 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 329 int error = 0; 330 331 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 332 return (EIO); 333 do { 334 register struct iovec *iov; 335 336 if (uio->uio_iovcnt == 0) 337 break; 338 iov = uio->uio_iov; 339 if (iov->iov_len == 0) { 340 uio->uio_iovcnt--; 341 uio->uio_iov++; 342 if (uio->uio_iovcnt < 0) 343 panic("ptcwrite"); 344 continue; 345 } 346 cc = MIN(iov->iov_len, BUFSIZ); 347 cp = locbuf; 348 error = uiomove(cp, cc, UIO_WRITE, uio); 349 if (error) 350 break; 351 ce = cp + cc; 352 again: 353 if (pti->pt_flags & PF_REMOTE) { 354 if (tp->t_rawq.c_cc) { 355 if (pti->pt_flags & PF_NBIO) { 356 iov->iov_base -= ce - cp; 357 iov->iov_len += ce - cp; 358 uio->uio_resid += ce - cp; 359 uio->uio_offset -= ce - cp; 360 return (EWOULDBLOCK); 361 } 362 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 363 goto again; 364 } 365 (void) b_to_q(cp, cc, &tp->t_rawq); 366 (void) putc(0, &tp->t_rawq); 367 wakeup((caddr_t)&tp->t_rawq); 368 return (0); 369 } 370 while (cp < ce) { 371 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 372 (tp->t_canq.c_cc > 0)) { 373 wakeup((caddr_t)&tp->t_rawq); 374 if (tp->t_state & TS_NBIO) { 375 iov->iov_base -= ce - cp; 376 iov->iov_len += ce - cp; 377 uio->uio_resid += ce - cp; 378 uio->uio_offset -= ce - cp; 379 if (cnt == 0) 380 return (EWOULDBLOCK); 381 return (0); 382 } 383 /* Better than just flushing it! */ 384 /* Wait for something to be read */ 385 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 386 goto again; 387 } 388 (*linesw[tp->t_line].l_rint)(*cp++, tp); 389 cnt++; 390 } 391 } while (uio->uio_resid); 392 return (error); 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 int error; 403 404 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 405 if (cdevsw[major(dev)].d_open == ptcopen) 406 switch (cmd) { 407 408 case TIOCPKT: 409 if (*(int *)data) 410 pti->pt_flags |= PF_PKT; 411 else 412 pti->pt_flags &= ~PF_PKT; 413 return (0); 414 415 case TIOCREMOTE: 416 if (*(int *)data) 417 pti->pt_flags |= PF_REMOTE; 418 else 419 pti->pt_flags &= ~PF_REMOTE; 420 ttyflush(tp, FREAD|FWRITE); 421 return (0); 422 423 case FIONBIO: 424 if (*(int *)data) 425 pti->pt_flags |= PF_NBIO; 426 else 427 pti->pt_flags &= ~PF_NBIO; 428 return (0); 429 430 case TIOCSETP: 431 while (getc(&tp->t_outq) >= 0) 432 ; 433 break; 434 } 435 error = ttioctl(tp, cmd, data, dev); 436 if (error < 0) 437 error = ENOTTY; 438 { int stop = (tp->t_stopc == ('s'&037) && 439 tp->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 return (error); 457 } 458 #endif 459