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