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