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