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