1 /* tty_pty.c 4.13 82/01/15 */ 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 pti_flags; 32 struct clist pti_ioctl, pti_ioans; 33 int pti_gensym; 34 struct proc *pti_selr, *pti_selw; 35 } pt_ioctl[NPTY]; 36 37 #define PTCRCOLL 0x01 38 #define PTCWCOLL 0x02 39 #define PTCNBIO 0x04 40 41 /*ARGSUSED*/ 42 ptsopen(dev, flag) 43 dev_t dev; 44 { 45 register struct tty *tp; 46 47 if (minor(dev) >= NPTY) { 48 u.u_error = ENXIO; 49 return; 50 } 51 tp = &pt_tty[minor(dev)]; 52 if ((tp->t_state & TS_ISOPEN) == 0) { 53 ttychars(tp); /* Set up default chars */ 54 tp->t_flags = 0; /* No features (nor raw mode) */ 55 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 56 u.u_error = EBUSY; 57 return; 58 } 59 if (tp->t_oproc) /* Ctrlr still around. */ 60 tp->t_state |= TS_CARR_ON; 61 while ((tp->t_state & TS_CARR_ON) == 0) { 62 tp->t_state |= TS_WOPEN; 63 sleep((caddr_t)&tp->t_rawq, TTIPRI); 64 } 65 (*linesw[tp->t_line].l_open)(dev, tp); 66 } 67 68 ptsclose(dev) 69 dev_t dev; 70 { 71 register struct tty *tp; 72 73 tp = &pt_tty[minor(dev)]; 74 (*linesw[tp->t_line].l_close)(tp); 75 } 76 77 ptsread(dev) 78 dev_t dev; 79 { 80 register struct tty *tp; 81 register struct pt_ioctl *pti; 82 83 tp = &pt_tty[minor(dev)]; 84 if (tp->t_oproc) { 85 (*linesw[tp->t_line].l_read)(tp); 86 wakeup((caddr_t)&tp->t_rawq.c_cf); 87 if (tp->t_rawq.c_cc < TTYHOG/2 && 88 (pti = &pt_ioctl[minor(tp->t_dev)])->pti_selw) { 89 selwakeup(pti->pti_selw, pti->pti_flags & PTCWCOLL); 90 pti->pti_selw = 0; 91 pti->pti_flags &= ~PTCWCOLL; 92 } 93 } 94 } 95 96 /* 97 * Write to pseudo-tty. 98 * Wakeups of controlling tty will happen 99 * indirectly, when tty driver calls ptsstart. 100 */ 101 ptswrite(dev) 102 dev_t dev; 103 { 104 register struct tty *tp; 105 106 tp = &pt_tty[minor(dev)]; 107 if (tp->t_oproc) 108 (*linesw[tp->t_line].l_write)(tp); 109 } 110 111 /* 112 * Start output on pseudo-tty. 113 * Wake up process selecting or sleeping for input from controlling tty. 114 */ 115 ptsstart(tp) 116 struct tty *tp; 117 { 118 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 119 120 if (tp->t_state & TS_TTSTOP) 121 return; 122 if (pti->pti_selr) { 123 selwakeup(pti->pti_selr, pti->pti_flags & PTCRCOLL); 124 pti->pti_selr = 0; 125 pti->pti_flags &= ~PTCRCOLL; 126 } 127 wakeup((caddr_t)&tp->t_outq.c_cf); 128 } 129 130 /*ARGSUSED*/ 131 ptcopen(dev, flag) 132 dev_t dev; 133 int flag; 134 { 135 register struct tty *tp; 136 137 if (minor(dev) >= NPTY) { 138 u.u_error = ENXIO; 139 return; 140 } 141 tp = &pt_tty[minor(dev)]; 142 if (tp->t_oproc) { 143 u.u_error = EIO; 144 return; 145 } 146 tp->t_oproc = ptsstart; 147 if (tp->t_state & TS_WOPEN) 148 wakeup((caddr_t)&tp->t_rawq); 149 tp->t_state |= TS_CARR_ON; 150 } 151 152 ptcclose(dev) 153 dev_t dev; 154 { 155 register struct tty *tp; 156 157 tp = &pt_tty[minor(dev)]; 158 if (tp->t_state & TS_ISOPEN) 159 gsignal(tp->t_pgrp, SIGHUP); 160 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 161 flushtty(tp, FREAD|FWRITE); 162 tp->t_oproc = 0; /* mark closed */ 163 } 164 165 ptcread(dev) 166 dev_t dev; 167 { 168 register struct tty *tp; 169 170 tp = &pt_tty[minor(dev)]; 171 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 172 return; 173 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 174 if (pt_ioctl[minor(dev)].pti_flags&PTCNBIO) { 175 u.u_error = EWOULDBLOCK; 176 return; 177 } 178 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 179 } 180 while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 181 ; 182 if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 183 if (tp->t_state&TS_ASLEEP) { 184 tp->t_state &= ~TS_ASLEEP; 185 wakeup((caddr_t)&tp->t_outq); 186 } 187 if (tp->t_wsel) { 188 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 189 tp->t_wsel = 0; 190 tp->t_state &= ~TS_WCOLL; 191 } 192 } 193 } 194 195 ptcselect(dev, rw) 196 dev_t dev; 197 int rw; 198 { 199 register struct tty *tp = &pt_tty[minor(dev)]; 200 struct pt_ioctl *pti; 201 struct proc *p; 202 203 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 204 return (1); 205 switch (rw) { 206 207 case FREAD: 208 if (tp->t_outq.c_cc) 209 return (1); 210 pti = &pt_ioctl[minor(dev)]; 211 if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)&selwait) 212 pti->pti_flags |= PTCRCOLL; 213 else 214 pti->pti_selr = u.u_procp; 215 return (0); 216 217 case FWRITE: 218 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) 219 return (1); 220 pti = &pt_ioctl[minor(dev)]; 221 if ((p = pti->pti_selw) && p->p_wchan == (caddr_t)&selwait) 222 pti->pti_flags |= PTCWCOLL; 223 else 224 pti->pti_selw = u.u_procp; 225 } 226 } 227 228 ptcwrite(dev) 229 dev_t dev; 230 { 231 register struct tty *tp; 232 register char *cp, *ce; 233 register int cc; 234 char locbuf[BUFSIZ]; 235 int cnt = 0; 236 237 tp = &pt_tty[minor(dev)]; 238 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 239 return; 240 while (u.u_count) { 241 cc = MIN(u.u_count, BUFSIZ); 242 cp = locbuf; 243 iomove(cp, (unsigned)cc, B_WRITE); 244 if (u.u_error) 245 break; 246 ce = cp + cc; 247 while (cp < ce) { 248 while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 249 wakeup((caddr_t)&tp->t_rawq); 250 if (tp->t_state & TS_NBIO) { 251 u.u_count += ce - cp; 252 if (cnt == 0) 253 u.u_error = EWOULDBLOCK; 254 return; 255 } 256 /* Better than just flushing it! */ 257 /* Wait for something to be read */ 258 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 259 } 260 (*linesw[tp->t_line].l_rint)(*cp++, tp); 261 cnt++; 262 } 263 } 264 } 265 266 /*ARGSUSED*/ 267 ptyioctl(dev, cmd, addr, flag) 268 caddr_t addr; 269 dev_t dev; 270 { 271 register struct tty *tp; 272 273 tp = &pt_tty[minor(dev)]; 274 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 275 if (cdevsw[major(dev)].d_open == ptcopen) { 276 if (cmd == FIONBIO) { 277 int nbio; 278 register struct pt_ioctl *pti; 279 if (copyin(addr, &nbio, sizeof (nbio))) { 280 u.u_error = EFAULT; 281 return; 282 } 283 pti = &pt_ioctl[minor(dev)]; 284 if (nbio) 285 pti->pti_flags |= PTCNBIO; 286 else 287 pti->pti_flags &= ~PTCNBIO; 288 return; 289 } 290 if (cmd == TIOCSETP) 291 while (getc(&tp->t_outq) >= 0); 292 } 293 if (ttioctl(tp, cmd, addr, dev) == 0) 294 u.u_error = ENOTTY; 295 } 296 #endif 297