xref: /csrg-svn/sys/kern/tty_pty.c (revision 7626)
1 /*	tty_pty.c	4.23	82/08/01	*/
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 #include "../h/param.h"
11 #include "../h/systm.h"
12 #include "../h/tty.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/conf.h"
16 #include "../h/buf.h"
17 #include "../h/file.h"
18 #include "../h/proc.h"
19 
20 #if NPTY == 1
21 #undef	NPTY
22 #define	NPTY	32		/* crude XXX */
23 #endif
24 
25 #define BUFSIZ 100		/* Chunk size iomoved from user */
26 
27 /*
28  * pts == /dev/tty[pP]?
29  * ptc == /dev/ptp[pP]?
30  */
31 struct	tty pt_tty[NPTY];
32 struct	pt_ioctl {
33 	int	pt_flags;
34 	int	pt_gensym;
35 	struct	proc *pt_selr, *pt_selw;
36 	int	pt_send;
37 } pt_ioctl[NPTY];
38 
39 #define	PF_RCOLL	0x01
40 #define	PF_WCOLL	0x02
41 #define	PF_NBIO		0x04
42 #define	PF_PKT		0x08		/* packet mode */
43 #define	PF_STOPPED	0x10		/* user told stopped */
44 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
45 #define	PF_NOSTOP	0x40
46 
47 /*ARGSUSED*/
48 ptsopen(dev, flag)
49 	dev_t dev;
50 {
51 	register struct tty *tp;
52 
53 	if (minor(dev) >= NPTY) {
54 		u.u_error = ENXIO;
55 		return;
56 	}
57 	tp = &pt_tty[minor(dev)];
58 	if ((tp->t_state & TS_ISOPEN) == 0) {
59 		ttychars(tp);		/* Set up default chars */
60 		tp->t_flags = 0;	/* No features (nor raw mode) */
61 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
62 		u.u_error = EBUSY;
63 		return;
64 	}
65 	if (tp->t_oproc)			/* Ctrlr still around. */
66 		tp->t_state |= TS_CARR_ON;
67 	while ((tp->t_state & TS_CARR_ON) == 0) {
68 		tp->t_state |= TS_WOPEN;
69 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
70 	}
71 	(*linesw[tp->t_line].l_open)(dev, tp);
72 }
73 
74 ptsclose(dev)
75 	dev_t dev;
76 {
77 	register struct tty *tp;
78 
79 	tp = &pt_tty[minor(dev)];
80 	(*linesw[tp->t_line].l_close)(tp);
81 	ttyclose(tp);
82 }
83 
84 ptsread(dev)
85 	dev_t dev;
86 {
87 	register struct tty *tp = &pt_tty[minor(dev)];
88 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
89 
90 again:
91 	if (pti->pt_flags & PF_REMOTE) {
92 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
93 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
94 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
95 	/*
96 			    (u.u_procp->p_flag&SDETACH) ||
97 	*/
98 			    u.u_procp->p_flag&SVFORK)
99 				return;
100 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
101 			sleep((caddr_t)&lbolt, TTIPRI);
102 		}
103 		if (tp->t_rawq.c_cc == 0) {
104 			if (tp->t_state & TS_NBIO) {
105 				u.u_error = EWOULDBLOCK;
106 				return;
107 			}
108 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
109 			goto again;
110 		}
111 		while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0)
112 			;
113 		if (tp->t_rawq.c_cc == 1)
114 			(void) getc(&tp->t_rawq);
115 		if (tp->t_rawq.c_cc)
116 			return;
117 	} else
118 		if (tp->t_oproc)
119 			(*linesw[tp->t_line].l_read)(tp);
120 	wakeup((caddr_t)&tp->t_rawq.c_cf);
121 	if (pti->pt_selw) {
122 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
123 		pti->pt_selw = 0;
124 		pti->pt_flags &= ~PF_WCOLL;
125 	}
126 }
127 
128 /*
129  * Write to pseudo-tty.
130  * Wakeups of controlling tty will happen
131  * indirectly, when tty driver calls ptsstart.
132  */
133 ptswrite(dev)
134 	dev_t dev;
135 {
136 	register struct tty *tp;
137 
138 	tp = &pt_tty[minor(dev)];
139 	if (tp->t_oproc)
140 		(*linesw[tp->t_line].l_write)(tp);
141 }
142 
143 /*
144  * Start output on pseudo-tty.
145  * Wake up process selecting or sleeping for input from controlling tty.
146  */
147 ptsstart(tp)
148 	struct tty *tp;
149 {
150 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
151 
152 	if (tp->t_state & TS_TTSTOP)
153 		return;
154 	if (pti->pt_flags & PF_STOPPED) {
155 		pti->pt_flags &= ~PF_STOPPED;
156 		pti->pt_send = TIOCPKT_START;
157 	}
158 	ptcwakeup(tp);
159 }
160 
161 ptcwakeup(tp)
162 	struct tty *tp;
163 {
164 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
165 
166 	if (pti->pt_selr) {
167 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
168 		pti->pt_selr = 0;
169 		pti->pt_flags &= ~PF_RCOLL;
170 	}
171 	wakeup((caddr_t)&tp->t_outq.c_cf);
172 }
173 
174 /*ARGSUSED*/
175 ptcopen(dev, flag)
176 	dev_t dev;
177 	int flag;
178 {
179 	register struct tty *tp;
180 	struct pt_ioctl *pti;
181 
182 	if (minor(dev) >= NPTY) {
183 		u.u_error = ENXIO;
184 		return;
185 	}
186 	tp = &pt_tty[minor(dev)];
187 	if (tp->t_oproc) {
188 		u.u_error = EIO;
189 		return;
190 	}
191 	tp->t_oproc = ptsstart;
192 	if (tp->t_state & TS_WOPEN)
193 		wakeup((caddr_t)&tp->t_rawq);
194 	tp->t_state |= TS_CARR_ON;
195 	pti = &pt_ioctl[minor(dev)];
196 	pti->pt_flags = 0;
197 	pti->pt_send = 0;
198 }
199 
200 ptcclose(dev)
201 	dev_t dev;
202 {
203 	register struct tty *tp;
204 
205 	tp = &pt_tty[minor(dev)];
206 	if (tp->t_state & TS_ISOPEN)
207 		gsignal(tp->t_pgrp, SIGHUP);
208 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
209 	flushtty(tp, FREAD|FWRITE);
210 	tp->t_oproc = 0;		/* mark closed */
211 }
212 
213 ptcread(dev)
214 	dev_t dev;
215 {
216 	register struct tty *tp;
217 	struct pt_ioctl *pti;
218 
219 	tp = &pt_tty[minor(dev)];
220 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
221 		return;
222 	pti = &pt_ioctl[minor(dev)];
223 	if (pti->pt_flags & PF_PKT) {
224 		if (pti->pt_send) {
225 			(void) passc(pti->pt_send);
226 			pti->pt_send = 0;
227 			return;
228 		}
229 		(void) passc(0);
230 	}
231 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
232 		if (pti->pt_flags&PF_NBIO) {
233 			u.u_error = EWOULDBLOCK;
234 			return;
235 		}
236 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
237 	}
238 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
239 		;
240 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
241 		if (tp->t_state&TS_ASLEEP) {
242 			tp->t_state &= ~TS_ASLEEP;
243 			wakeup((caddr_t)&tp->t_outq);
244 		}
245 		if (tp->t_wsel) {
246 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
247 			tp->t_wsel = 0;
248 			tp->t_state &= ~TS_WCOLL;
249 		}
250 	}
251 }
252 
253 ptsstop(tp, flush)
254 	register struct tty *tp;
255 	int flush;
256 {
257 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
258 
259 	/* note: FLUSHREAD and FLUSHWRITE already ok */
260 	if (flush == 0) {
261 		flush = TIOCPKT_STOP;
262 		pti->pt_flags |= PF_STOPPED;
263 	} else {
264 		pti->pt_flags &= ~PF_STOPPED;
265 	}
266 	pti->pt_send |= flush;
267 	ptcwakeup(tp);
268 }
269 
270 ptcselect(dev, rw)
271 	dev_t dev;
272 	int rw;
273 {
274 	register struct tty *tp = &pt_tty[minor(dev)];
275 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
276 	struct proc *p;
277 	int s;
278 
279 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
280 		return (1);
281 	s = spl5();
282 	switch (rw) {
283 
284 	case FREAD:
285 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
286 			splx(s);
287 			return (1);
288 		}
289 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
290 			pti->pt_flags |= PF_RCOLL;
291 		else
292 			pti->pt_selr = u.u_procp;
293 		break;
294 
295 	case FWRITE:
296 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
297 			splx(s);
298 			return (1);
299 		}
300 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
301 			pti->pt_flags |= PF_WCOLL;
302 		else
303 			pti->pt_selw = u.u_procp;
304 		break;
305 	}
306 	splx(s);
307 	return (0);
308 }
309 
310 ptcwrite(dev)
311 	dev_t dev;
312 {
313 	register struct tty *tp;
314 	register char *cp, *ce;
315 	register int cc;
316 	char locbuf[BUFSIZ];
317 	int cnt = 0;
318 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
319 
320 	tp = &pt_tty[minor(dev)];
321 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
322 		return;
323 	do {
324 		cc = MIN(u.u_count, BUFSIZ);
325 		cp = locbuf;
326 		iomove(cp, (unsigned)cc, B_WRITE);
327 		if (u.u_error)
328 			break;
329 		ce = cp + cc;
330 again:
331 		if (pti->pt_flags & PF_REMOTE) {
332 			if (tp->t_rawq.c_cc) {
333 				if (pti->pt_flags & PF_NBIO) {
334 					u.u_count += ce - cp;
335 					u.u_error = EWOULDBLOCK;
336 					return;
337 				}
338 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
339 				goto again;
340 			}
341 			(void) b_to_q(cp, cc, &tp->t_rawq);
342 			(void) putc(0, &tp->t_rawq);
343 			wakeup((caddr_t)&tp->t_rawq);
344 			return;
345 		}
346 		while (cp < ce) {
347 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
348 				wakeup((caddr_t)&tp->t_rawq);
349 				if (tp->t_state & TS_NBIO) {
350 					u.u_count += ce - cp;
351 					if (cnt == 0)
352 						u.u_error = EWOULDBLOCK;
353 					return;
354 				}
355 				/* Better than just flushing it! */
356 				/* Wait for something to be read */
357 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
358 				goto again;
359 			}
360 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
361 			cnt++;
362 		}
363 	} while (u.u_count);
364 }
365 
366 /*ARGSUSED*/
367 ptyioctl(dev, cmd, data, flag)
368 	caddr_t data;
369 	dev_t dev;
370 {
371 	register struct tty *tp = &pt_tty[minor(dev)];
372 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
373 
374 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
375 	if (cdevsw[major(dev)].d_open == ptcopen)
376 		switch (cmd) {
377 
378 		case TIOCPKT:
379 			if (*(int *)data)
380 				pti->pt_flags |= PF_PKT;
381 			else
382 				pti->pt_flags &= ~PF_PKT;
383 			return;
384 
385 		case TIOCREMOTE:
386 			if (*(int *)data)
387 				pti->pt_flags |= PF_REMOTE;
388 			else
389 				pti->pt_flags &= ~PF_REMOTE;
390 			flushtty(tp, FREAD|FWRITE);
391 			return;
392 
393 		case FIONBIO:
394 			if (*(int *)data)
395 				pti->pt_flags |= PF_NBIO;
396 			else
397 				pti->pt_flags &= ~PF_NBIO;
398 			return;
399 
400 		case TIOCSETP:
401 			while (getc(&tp->t_outq) >= 0)
402 				;
403 			break;
404 		}
405 	if (ttioctl(tp, cmd, data, dev) == 0)
406 		u.u_error = ENOTTY;
407 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
408 		      tp->t_un.t_chr.t_startc == ('q'&037));
409 	if (pti->pt_flags & PF_NOSTOP) {
410 		if (stop) {
411 			pti->pt_send &= TIOCPKT_NOSTOP;
412 			pti->pt_send |= TIOCPKT_DOSTOP;
413 			pti->pt_flags &= ~PF_NOSTOP;
414 			ptcwakeup(tp);
415 		}
416 	} else {
417 		if (stop == 0) {
418 			pti->pt_send &= ~TIOCPKT_DOSTOP;
419 			pti->pt_send |= TIOCPKT_NOSTOP;
420 			pti->pt_flags |= PF_NOSTOP;
421 			ptcwakeup(tp);
422 		}
423 	}
424 	}
425 }
426 #endif
427