xref: /csrg-svn/sys/kern/tty_pty.c (revision 2281)
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