1 # 2 /* 3 * Pseudo-teletype Driver 4 * (Actually two drivers, requiring two entries in 'cdevsw') 5 * 6 * Overhauled, and ported to VAX/VMUNIX (V7) Bruce Borden, July 80 7 */ 8 #include "../h/param.h" 9 #include "../h/systm.h" 10 #include "../h/tty.h" 11 #include "../h/dir.h" 12 #include "../h/user.h" 13 #include "../h/conf.h" 14 #include "../h/buf.h" 15 16 #define NPTY 16 /* Number of pseudo-teletypes */ 17 #define BUFSIZ 100 /* Chunk size iomoved from user */ 18 #define ALLDELAYS (NLDELAY|TBDELAY|XTABS|CRDELAY|VTDELAY) 19 /* 20 * A pseudo-teletype is a special device which is not unlike a pipe. 21 * It is used to communicate between two processes. However, it allows 22 * one to simulate a teletype, including mode setting, interrupt, and 23 * multiple end of files (all not possible on a pipe). There are 24 * really two drivers here. One is the device which looks like a TTY 25 * and can be thought of as the slave device, and hence its routines 26 * are prefixed with 'pts' (PTY Slave). The other driver can be 27 * thought of as the controlling device, and its routines are prefixed 28 * by 'ptc' (PTY Controller). To type on the simulated keyboard of the 29 * PTY, one does a 'write' to the controlling device. To get the 30 * simulated printout from the PTY, one does a 'read' on the controlling 31 * device. Normally, the controlling device is called 'ptyx' and the 32 * slave device is called 'ttyx' (to make programs like 'who' happy). 33 */ 34 35 struct tty pt_tty[NPTY]; /* TTY headers for PTYs */ 36 37 /*ARGSUSED*/ 38 ptsopen(dev, flag) 39 dev_t dev; 40 { /* Open for PTY Slave */ 41 register struct tty *tp; 42 43 if(minor(dev) >= NPTY) { 44 u.u_error = ENXIO; 45 return; 46 } 47 tp = &pt_tty[minor(dev)]; 48 if((tp->t_state & ISOPEN) == 0) { 49 ttychars(tp); /* Set up default chars */ 50 tp->t_flags = 0; /* No features (nor raw mode) */ 51 } else if(tp->t_state&XCLUDE && u.u_uid != 0) { 52 u.u_error = EBUSY; 53 return; 54 } 55 if(tp->t_oproc) /* Ctrlr still around. */ 56 tp->t_state |= CARR_ON; 57 while((tp->t_state & CARR_ON) == 0) { 58 tp->t_state |= WOPEN; 59 sleep((caddr_t)&tp->t_rawq, TTIPRI); 60 } 61 (*linesw[tp->t_line].l_open)(dev, tp); 62 } 63 64 ptsclose(dev) 65 dev_t dev; 66 { /* Close slave part of PTY */ 67 register struct tty *tp; 68 69 tp = &pt_tty[minor(dev)]; 70 (*linesw[tp->t_line].l_close)(tp); 71 } 72 73 ptsread(dev) 74 dev_t dev; 75 { /* Read from PTY, i.e. from data written by controlling device */ 76 register struct tty *tp; 77 78 tp = &pt_tty[minor(dev)]; 79 if(tp->t_oproc) { 80 (*linesw[tp->t_line].l_read)(tp); 81 /* Wakeup other half if sleeping */ 82 wakeup((caddr_t)&tp->t_rawq.c_cf); 83 } 84 } 85 86 ptswrite(dev) 87 dev_t dev; 88 { /* Write on PTY, i.e. to be read from 89 controlling device */ 90 register struct tty *tp; 91 92 tp = &pt_tty[minor(dev)]; 93 /* Wait for controlling device to be opened */ 94 if(tp->t_oproc) 95 (*linesw[tp->t_line].l_write)(tp); 96 } 97 98 ptsstart(tp) 99 struct tty *tp; 100 { /* Called by 'ttstart' to output a character. 101 Merely wakes up controlling half, which 102 does actual work */ 103 if(tp->t_state & TTSTOP) 104 return; 105 wakeup((caddr_t)&tp->t_outq.c_cf); 106 } 107 108 /*ARGSUSED*/ 109 ptcopen(dev, flag) 110 dev_t dev; 111 { /* Open for PTY Controller */ 112 register struct tty *tp; 113 114 if(minor(dev) >= NPTY) { 115 u.u_error = ENXIO; 116 return; 117 } 118 tp = &pt_tty[minor(dev)]; 119 if(tp->t_oproc) { 120 u.u_error = EIO; 121 return; 122 } 123 tp->t_oproc = ptsstart; /* Set address of start routine */ 124 tp->t_iproc = 0; 125 if(tp->t_state & WOPEN) 126 wakeup((caddr_t)&tp->t_rawq); 127 tp->t_state |= CARR_ON; 128 } 129 130 ptcclose(dev) 131 dev_t dev; 132 { /* Close controlling part of PTY */ 133 register struct tty *tp; 134 135 tp = &pt_tty[minor(dev)]; 136 if(tp->t_state & ISOPEN) 137 gsignal(tp->t_pgrp, SIGHUP); 138 tp->t_state &= ~CARR_ON; /* Virtual carrier is gone */ 139 flushtty(tp); /* Clean things up */ 140 tp->t_oproc = 0; /* Mark as closed */ 141 } 142 143 ptcread(dev) 144 dev_t dev; 145 { /* Read from PTY's output buffer */ 146 register struct tty *tp; 147 148 tp = &pt_tty[minor(dev)]; 149 if((tp->t_state&(CARR_ON|ISOPEN)) == 0) 150 return; 151 while(tp->t_outq.c_cc == 0 || /* Wait for something to arrive */ 152 (tp->t_state&TTSTOP)) /* (Woken by ptsstart) */ 153 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 154 while(tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0); 155 if(tp->t_outq.c_cc <= TTLOWAT(tp) && (tp->t_state&ASLEEP)) { 156 tp->t_state &= ~ASLEEP; 157 if(tp->t_chan) 158 mcstart(tp->t_chan, (caddr_t)&tp->t_outq); 159 else 160 wakeup((caddr_t)&tp->t_outq); 161 } 162 } 163 164 ptcwrite(dev) 165 dev_t dev; 166 { /* Stuff characters into PTY's input buffer */ 167 register struct tty *tp; 168 register char *cp, *ce; 169 register int cc; 170 char locbuf[BUFSIZ]; 171 172 tp = &pt_tty[minor(dev)]; 173 if((tp->t_state&(CARR_ON|ISOPEN)) == 0) 174 return; 175 while(u.u_count) { 176 cc = MIN(u.u_count, BUFSIZ); 177 cp = locbuf; 178 iomove(cp, (unsigned)cc, B_WRITE); 179 if(u.u_error) 180 break; 181 ce = cp + cc; 182 while(cp < ce) { 183 while(tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 184 wakeup((caddr_t)&tp->t_rawq); 185 /* Better than just flushing it! */ 186 /* Wait for something to be read */ 187 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 188 } 189 ttyinput(*cp++, tp); 190 } 191 } 192 } 193 194 /* Note: Both slave and controlling device have the same routine for */ 195 /* 'ioctl' (but note check for controller - 4/12/78:mob)*/ 196 /*ARGSUSED*/ 197 ptyioctl(dev, cmd, addr, flag) 198 caddr_t addr; 199 dev_t dev; 200 { /* Read and write status bits */ 201 register struct tty *tp; 202 register int tbd; 203 #ifdef BLAND 204 register int nld; 205 #endif 206 207 tp = &pt_tty[minor(dev)]; 208 /* if controller stty then must flush to prevent a hang */ 209 if(cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP) 210 while(getc(&tp->t_outq) >= 0); 211 if(ttioctl(tp, cmd, addr, dev)) { 212 if(cmd == TIOCSETP || cmd == TIOCSETN) { 213 #ifdef BLAND 214 nld = tp->t_flags & NLDELAY; 215 #endif 216 tbd = tp->t_flags & TBDELAY; 217 tp->t_flags &= ~ALLDELAYS; 218 if(tbd == TBDELAY) /* Wants tab expansion */ 219 tp->t_flags |= tbd; 220 #ifdef BLAND 221 if(nld == NLDELAY) /* Allow ANN ARBOR mode. */ 222 tp->t_flags |= nld; 223 #endif 224 } 225 } else 226 u.u_error = ENOTTY; 227 } 228