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