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