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