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