1 /* tty_pty.c 4.15 82/01/17 */ 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_FLOWCTL 0x10 /* peers flow control mode */ 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 121 if (tp->t_state & TS_TTSTOP) 122 return; 123 ptcwakeup(tp); 124 } 125 126 ptcwakeup(tp) 127 struct tty *tp; 128 { 129 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 130 131 if (pti->pt_selr) { 132 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 133 pti->pt_selr = 0; 134 pti->pt_flags &= ~PF_RCOLL; 135 } 136 wakeup((caddr_t)&tp->t_outq.c_cf); 137 } 138 139 /*ARGSUSED*/ 140 ptcopen(dev, flag) 141 dev_t dev; 142 int flag; 143 { 144 register struct tty *tp; 145 struct pt_ioctl *pti; 146 147 if (minor(dev) >= NPTY) { 148 u.u_error = ENXIO; 149 return; 150 } 151 tp = &pt_tty[minor(dev)]; 152 if (tp->t_oproc) { 153 u.u_error = EIO; 154 return; 155 } 156 tp->t_oproc = ptsstart; 157 if (tp->t_state & TS_WOPEN) 158 wakeup((caddr_t)&tp->t_rawq); 159 tp->t_state |= TS_CARR_ON; 160 pti = &pt_ioctl[minor(dev)]; 161 pti->pt_flags = 0; 162 pti->pt_send = 0; 163 } 164 165 ptcclose(dev) 166 dev_t dev; 167 { 168 register struct tty *tp; 169 170 tp = &pt_tty[minor(dev)]; 171 if (tp->t_state & TS_ISOPEN) 172 gsignal(tp->t_pgrp, SIGHUP); 173 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 174 flushtty(tp, FREAD|FWRITE); 175 tp->t_oproc = 0; /* mark closed */ 176 } 177 178 ptcread(dev) 179 dev_t dev; 180 { 181 register struct tty *tp; 182 struct pt_ioctl *pti; 183 184 tp = &pt_tty[minor(dev)]; 185 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 186 return; 187 pti = &pt_ioctl[minor(dev)]; 188 if (pti->pt_flags & PF_PKT) { 189 if (pti->pt_send) { 190 passc(pti->pt_send); 191 pti->pt_send = 0; 192 return; 193 } 194 passc(0); 195 } 196 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 197 if (pti->pt_flags&PF_NBIO) { 198 u.u_error = EWOULDBLOCK; 199 return; 200 } 201 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 202 } 203 while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 204 ; 205 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 206 if (tp->t_state&TS_ASLEEP) { 207 tp->t_state &= ~TS_ASLEEP; 208 wakeup((caddr_t)&tp->t_outq); 209 } 210 if (tp->t_wsel) { 211 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 212 tp->t_wsel = 0; 213 tp->t_state &= ~TS_WCOLL; 214 } 215 } 216 } 217 218 ptsstop(tp, flush) 219 register struct tty *tp; 220 int flush; 221 { 222 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 223 224 if (flush == 0) 225 return; 226 pti->pt_send |= flush; 227 ptcwakeup(tp); 228 } 229 230 ptcselect(dev, rw) 231 dev_t dev; 232 int rw; 233 { 234 register struct tty *tp = &pt_tty[minor(dev)]; 235 struct pt_ioctl *pti; 236 struct proc *p; 237 int s; 238 239 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 240 return (1); 241 s = spl5(); 242 switch (rw) { 243 244 case FREAD: 245 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 246 splx(s); 247 return (1); 248 } 249 pti = &pt_ioctl[minor(dev)]; 250 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 251 pti->pt_flags |= PF_RCOLL; 252 else 253 pti->pt_selr = u.u_procp; 254 break; 255 256 case FWRITE: 257 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) { 258 splx(s); 259 return (1); 260 } 261 pti = &pt_ioctl[minor(dev)]; 262 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 263 pti->pt_flags |= PF_WCOLL; 264 else 265 pti->pt_selw = u.u_procp; 266 break; 267 } 268 splx(s); 269 return (0); 270 } 271 272 ptcwrite(dev) 273 dev_t dev; 274 { 275 register struct tty *tp; 276 register char *cp, *ce; 277 register int cc; 278 char locbuf[BUFSIZ]; 279 int cnt = 0; 280 281 tp = &pt_tty[minor(dev)]; 282 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 283 return; 284 while (u.u_count) { 285 cc = MIN(u.u_count, BUFSIZ); 286 cp = locbuf; 287 iomove(cp, (unsigned)cc, B_WRITE); 288 if (u.u_error) 289 break; 290 ce = cp + cc; 291 while (cp < ce) { 292 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 293 wakeup((caddr_t)&tp->t_rawq); 294 if (tp->t_state & TS_NBIO) { 295 u.u_count += ce - cp; 296 if (cnt == 0) 297 u.u_error = EWOULDBLOCK; 298 return; 299 } 300 /* Better than just flushing it! */ 301 /* Wait for something to be read */ 302 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 303 } 304 (*linesw[tp->t_line].l_rint)(*cp++, tp); 305 cnt++; 306 } 307 } 308 } 309 310 /*ARGSUSED*/ 311 ptyioctl(dev, cmd, addr, flag) 312 caddr_t addr; 313 dev_t dev; 314 { 315 register struct tty *tp; 316 317 tp = &pt_tty[minor(dev)]; 318 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 319 if (cdevsw[major(dev)].d_open == ptcopen) { 320 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 321 if (cmd == TIOCPKT) { 322 int packet; 323 if (copyin((caddr_t)addr, &packet, sizeof (packet))) { 324 u.u_error = EFAULT; 325 return; 326 } 327 if (packet) 328 pti->pt_flags |= PF_PKT; 329 else 330 pti->pt_flags &= ~PF_PKT; 331 return; 332 } 333 if (cmd == FIONBIO) { 334 int nbio; 335 if (copyin(addr, &nbio, sizeof (nbio))) { 336 u.u_error = EFAULT; 337 return; 338 } 339 if (nbio) 340 pti->pt_flags |= PF_NBIO; 341 else 342 pti->pt_flags &= ~PF_NBIO; 343 return; 344 } 345 if (cmd == TIOCSETP) 346 while (getc(&tp->t_outq) >= 0); 347 } 348 if (ttioctl(tp, cmd, addr, dev) == 0) 349 u.u_error = ENOTTY; 350 } 351 #endif 352