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