xref: /csrg-svn/sys/kern/tty_pty.c (revision 2313)
1*2313Stoy /*	tty_pty.c	4.3	01/29/81	*/
22283Stoy 
32281Stoy /*
42281Stoy  * Pseudo-teletype Driver
52281Stoy  * (Actually two drivers, requiring two entries in 'cdevsw')
62281Stoy  */
72281Stoy #include "../h/param.h"
82281Stoy #include "../h/systm.h"
92281Stoy #include "../h/tty.h"
102281Stoy #include "../h/dir.h"
112281Stoy #include "../h/user.h"
122281Stoy #include "../h/conf.h"
132281Stoy #include "../h/buf.h"
14*2313Stoy #include "../pty.h"
152281Stoy 
16*2313Stoy #if WANTPTY > 0
17*2313Stoy 
182281Stoy #define NPTY 16                 /* Number of pseudo-teletypes */
192281Stoy #define BUFSIZ 100              /* Chunk size iomoved from user */
202281Stoy #define ALLDELAYS (NLDELAY|TBDELAY|XTABS|CRDELAY|VTDELAY)
212281Stoy /*
222281Stoy  * A pseudo-teletype is a special device which is not unlike a pipe.
232281Stoy  * It is used to communicate between two processes.  However, it allows
242281Stoy  * one to simulate a teletype, including mode setting, interrupt, and
252281Stoy  * multiple end of files (all not possible on a pipe).  There are
262281Stoy  * really two drivers here.  One is the device which looks like a TTY
272281Stoy  * and can be thought of as the slave device, and hence its routines
282281Stoy  * are prefixed with 'pts' (PTY Slave).  The other driver can be
292281Stoy  * thought of as the controlling device, and its routines are prefixed
302281Stoy  * by 'ptc' (PTY Controller).  To type on the simulated keyboard of the
312281Stoy  * PTY, one does a 'write' to the controlling device.  To get the
322281Stoy  * simulated printout from the PTY, one does a 'read' on the controlling
332281Stoy  * device.  Normally, the controlling device is called 'ptyx' and the
342281Stoy  * slave device is called 'ttyx' (to make programs like 'who' happy).
352281Stoy  */
362281Stoy 
372281Stoy struct tty pt_tty[NPTY];                /* TTY headers for PTYs */
382281Stoy 
392281Stoy /*ARGSUSED*/
402281Stoy ptsopen(dev, flag)
412281Stoy dev_t dev;
422281Stoy {                                       /* Open for PTY Slave */
432281Stoy 	register struct tty *tp;
442281Stoy 
452281Stoy 	if(minor(dev) >= NPTY) {
462281Stoy 		u.u_error = ENXIO;
472281Stoy 		return;
482281Stoy 	}
492281Stoy 	tp = &pt_tty[minor(dev)];
502281Stoy 	if((tp->t_state & ISOPEN) == 0) {
512281Stoy 		ttychars(tp);           /* Set up default chars */
522281Stoy 		tp->t_flags = 0;        /* No features (nor raw mode) */
532281Stoy 	} else if(tp->t_state&XCLUDE && u.u_uid != 0) {
542281Stoy 		u.u_error = EBUSY;
552281Stoy 		return;
562281Stoy 	}
572281Stoy 	if(tp->t_oproc)                 /* Ctrlr still around. */
582281Stoy 		tp->t_state |= CARR_ON;
592281Stoy 	while((tp->t_state & CARR_ON) == 0) {
602281Stoy 		tp->t_state |= WOPEN;
612281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
622281Stoy 	}
632281Stoy 	(*linesw[tp->t_line].l_open)(dev, tp);
642281Stoy }
652281Stoy 
662281Stoy ptsclose(dev)
672281Stoy dev_t dev;
682281Stoy {                                       /* Close slave part of PTY */
692281Stoy 	register struct tty *tp;
702281Stoy 
712281Stoy 	tp = &pt_tty[minor(dev)];
722281Stoy 	(*linesw[tp->t_line].l_close)(tp);
732281Stoy }
742281Stoy 
752281Stoy ptsread(dev)
762281Stoy dev_t dev;
772281Stoy {       /* Read from PTY, i.e. from data written by controlling device */
782281Stoy 	register struct tty    *tp;
792281Stoy 
802281Stoy 	tp = &pt_tty[minor(dev)];
812281Stoy 	if(tp->t_oproc) {
822281Stoy 		(*linesw[tp->t_line].l_read)(tp);
832281Stoy 				/* Wakeup other half if sleeping */
842281Stoy 		wakeup((caddr_t)&tp->t_rawq.c_cf);
852281Stoy 	}
862281Stoy }
872281Stoy 
882281Stoy ptswrite(dev)
892281Stoy dev_t dev;
902281Stoy {                       /* Write on PTY, i.e. to be read from
912281Stoy 			   controlling device */
922281Stoy 	register struct tty *tp;
932281Stoy 
942281Stoy 	tp = &pt_tty[minor(dev)];
952281Stoy 			/* Wait for controlling device to be opened */
962281Stoy 	if(tp->t_oproc)
972281Stoy 		(*linesw[tp->t_line].l_write)(tp);
982281Stoy }
992281Stoy 
1002281Stoy ptsstart(tp)
1012281Stoy struct tty *tp;
1022281Stoy {                       /* Called by 'ttstart' to output a character.
1032281Stoy 			   Merely wakes up controlling half, which
1042281Stoy 			   does actual work */
1052281Stoy 	if(tp->t_state & TTSTOP)
1062281Stoy 		return;
1072281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1082281Stoy }
1092281Stoy 
1102281Stoy /*ARGSUSED*/
1112281Stoy ptcopen(dev, flag)
1122281Stoy dev_t dev;
1132281Stoy {                               /* Open for PTY Controller */
1142281Stoy 	register struct tty *tp;
1152281Stoy 
1162281Stoy 	if(minor(dev) >= NPTY) {
1172281Stoy 		u.u_error = ENXIO;
1182281Stoy 		return;
1192281Stoy 	}
1202281Stoy 	tp = &pt_tty[minor(dev)];
1212281Stoy 	if(tp->t_oproc) {
1222281Stoy 		u.u_error = EIO;
1232281Stoy 		return;
1242281Stoy 	}
1252281Stoy 	tp->t_oproc = ptsstart;         /* Set address of start routine */
1262281Stoy 	tp->t_iproc = 0;
1272281Stoy 	if(tp->t_state & WOPEN)
1282281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1292281Stoy 	tp->t_state |= CARR_ON;
1302281Stoy }
1312281Stoy 
1322281Stoy ptcclose(dev)
1332281Stoy dev_t dev;
1342281Stoy {                                       /* Close controlling part of PTY */
1352281Stoy 	register struct tty *tp;
1362281Stoy 
1372281Stoy 	tp = &pt_tty[minor(dev)];
1382281Stoy 	if(tp->t_state & ISOPEN)
1392281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
1402281Stoy 	tp->t_state &= ~CARR_ON;        /* Virtual carrier is gone */
1412281Stoy 	flushtty(tp);                   /* Clean things up */
1422281Stoy 	tp->t_oproc = 0;                /* Mark as closed */
1432281Stoy }
1442281Stoy 
1452281Stoy ptcread(dev)
1462281Stoy dev_t dev;
1472281Stoy {                                       /* Read from PTY's output buffer */
1482281Stoy 	register struct tty *tp;
1492281Stoy 
1502281Stoy 	tp = &pt_tty[minor(dev)];
1512281Stoy 	if((tp->t_state&(CARR_ON|ISOPEN)) == 0)
1522281Stoy 		return;
1532281Stoy 	while(tp->t_outq.c_cc == 0 ||   /* Wait for something to arrive */
1542281Stoy 	      (tp->t_state&TTSTOP))     /* (Woken by ptsstart) */
1552281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
1562281Stoy 	while(tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0);
1572281Stoy 	if(tp->t_outq.c_cc <= TTLOWAT(tp)  && (tp->t_state&ASLEEP)) {
1582281Stoy 		tp->t_state &= ~ASLEEP;
1592281Stoy 		if(tp->t_chan)
1602281Stoy 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
1612281Stoy 		else
1622281Stoy 			wakeup((caddr_t)&tp->t_outq);
1632281Stoy 	}
1642281Stoy }
1652281Stoy 
1662281Stoy ptcwrite(dev)
1672281Stoy dev_t dev;
1682281Stoy {                       /* Stuff characters into PTY's input buffer */
1692281Stoy 	register struct tty *tp;
1702281Stoy 	register char *cp, *ce;
1712281Stoy 	register int cc;
1722281Stoy 	char locbuf[BUFSIZ];
1732281Stoy 
1742281Stoy 	tp = &pt_tty[minor(dev)];
1752281Stoy 	if((tp->t_state&(CARR_ON|ISOPEN)) == 0)
1762281Stoy 		return;
1772281Stoy 	while(u.u_count) {
1782281Stoy 		cc = MIN(u.u_count, BUFSIZ);
1792281Stoy 		cp = locbuf;
1802281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
1812281Stoy 		if(u.u_error)
1822281Stoy 			break;
1832281Stoy 		ce = cp + cc;
1842281Stoy 		while(cp < ce) {
1852281Stoy 			while(tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
1862281Stoy 				wakeup((caddr_t)&tp->t_rawq);
1872281Stoy 				/* Better than just flushing it! */
1882281Stoy 				/* Wait for something to be read */
1892281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
1902281Stoy 			}
1912281Stoy 			ttyinput(*cp++, tp);
1922281Stoy 		}
1932281Stoy 	}
1942281Stoy }
1952281Stoy 
1962281Stoy /* Note: Both slave and controlling device have the same routine for */
1972281Stoy /* 'ioctl' (but note check for controller - 4/12/78:mob)*/
1982281Stoy /*ARGSUSED*/
1992281Stoy ptyioctl(dev, cmd, addr, flag)
2002281Stoy caddr_t addr;
2012281Stoy dev_t dev;
2022281Stoy {					/* Read and write status bits */
2032281Stoy 	register struct tty *tp;
2042281Stoy 	register int tbd;
2052281Stoy #ifdef BLAND
2062281Stoy 	register int nld;
2072281Stoy #endif
2082281Stoy 
2092281Stoy 	tp = &pt_tty[minor(dev)];
2102281Stoy 		/* if controller stty then must flush to prevent a hang */
2112281Stoy 	if(cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP)
2122281Stoy 		while(getc(&tp->t_outq) >= 0);
2132281Stoy 	if(ttioctl(tp, cmd, addr, dev)) {
2142281Stoy 		if(cmd == TIOCSETP || cmd == TIOCSETN) {
2152281Stoy #ifdef BLAND
2162281Stoy 			nld = tp->t_flags & NLDELAY;
2172281Stoy #endif
2182281Stoy 			tbd = tp->t_flags & TBDELAY;
2192281Stoy 			tp->t_flags &= ~ALLDELAYS;
2202281Stoy 			if(tbd == TBDELAY)      /* Wants tab expansion */
2212281Stoy 				tp->t_flags |= tbd;
2222281Stoy #ifdef BLAND
2232281Stoy 			if(nld == NLDELAY)      /* Allow ANN ARBOR mode. */
2242281Stoy 				tp->t_flags |= nld;
2252281Stoy #endif
2262281Stoy 		}
2272281Stoy 	} else
2282281Stoy 		u.u_error = ENOTTY;
2292281Stoy }
230*2313Stoy #endif
231