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