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