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