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