xref: /csrg-svn/sys/kern/tty_pty.c (revision 7823)
1 /*	tty_pty.c	4.24	82/08/22	*/
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/file.h"
17 #include "../h/proc.h"
18 #include "../h/uio.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, uio)
85 	dev_t dev;
86 	struct uio *uio;
87 {
88 	register struct tty *tp = &pt_tty[minor(dev)];
89 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
90 
91 again:
92 	if (pti->pt_flags & PF_REMOTE) {
93 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
94 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
95 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
96 	/*
97 			    (u.u_procp->p_flag&SDETACH) ||
98 	*/
99 			    u.u_procp->p_flag&SVFORK)
100 				return;
101 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
102 			sleep((caddr_t)&lbolt, TTIPRI);
103 		}
104 		if (tp->t_rawq.c_cc == 0) {
105 			if (tp->t_state & TS_NBIO) {
106 				u.u_error = EWOULDBLOCK;
107 				return;
108 			}
109 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
110 			goto again;
111 		}
112 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
113 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
114 				u.u_error = EFAULT;
115 				break;
116 			}
117 		if (tp->t_rawq.c_cc == 1)
118 			(void) getc(&tp->t_rawq);
119 		if (tp->t_rawq.c_cc)
120 			return;
121 	} else
122 		if (tp->t_oproc)
123 			(*linesw[tp->t_line].l_read)(tp, uio);
124 	wakeup((caddr_t)&tp->t_rawq.c_cf);
125 	if (pti->pt_selw) {
126 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
127 		pti->pt_selw = 0;
128 		pti->pt_flags &= ~PF_WCOLL;
129 	}
130 }
131 
132 /*
133  * Write to pseudo-tty.
134  * Wakeups of controlling tty will happen
135  * indirectly, when tty driver calls ptsstart.
136  */
137 ptswrite(dev, uio)
138 	dev_t dev;
139 	struct uio *uio;
140 {
141 	register struct tty *tp;
142 
143 	tp = &pt_tty[minor(dev)];
144 	if (tp->t_oproc)
145 		(*linesw[tp->t_line].l_write)(tp, uio);
146 }
147 
148 /*
149  * Start output on pseudo-tty.
150  * Wake up process selecting or sleeping for input from controlling tty.
151  */
152 ptsstart(tp)
153 	struct tty *tp;
154 {
155 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
156 
157 	if (tp->t_state & TS_TTSTOP)
158 		return;
159 	if (pti->pt_flags & PF_STOPPED) {
160 		pti->pt_flags &= ~PF_STOPPED;
161 		pti->pt_send = TIOCPKT_START;
162 	}
163 	ptcwakeup(tp);
164 }
165 
166 ptcwakeup(tp)
167 	struct tty *tp;
168 {
169 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
170 
171 	if (pti->pt_selr) {
172 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
173 		pti->pt_selr = 0;
174 		pti->pt_flags &= ~PF_RCOLL;
175 	}
176 	wakeup((caddr_t)&tp->t_outq.c_cf);
177 }
178 
179 /*ARGSUSED*/
180 ptcopen(dev, flag)
181 	dev_t dev;
182 	int flag;
183 {
184 	register struct tty *tp;
185 	struct pt_ioctl *pti;
186 
187 	if (minor(dev) >= NPTY) {
188 		u.u_error = ENXIO;
189 		return;
190 	}
191 	tp = &pt_tty[minor(dev)];
192 	if (tp->t_oproc) {
193 		u.u_error = EIO;
194 		return;
195 	}
196 	tp->t_oproc = ptsstart;
197 	if (tp->t_state & TS_WOPEN)
198 		wakeup((caddr_t)&tp->t_rawq);
199 	tp->t_state |= TS_CARR_ON;
200 	pti = &pt_ioctl[minor(dev)];
201 	pti->pt_flags = 0;
202 	pti->pt_send = 0;
203 }
204 
205 ptcclose(dev)
206 	dev_t dev;
207 {
208 	register struct tty *tp;
209 
210 	tp = &pt_tty[minor(dev)];
211 	if (tp->t_state & TS_ISOPEN)
212 		gsignal(tp->t_pgrp, SIGHUP);
213 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
214 	flushtty(tp, FREAD|FWRITE);
215 	tp->t_oproc = 0;		/* mark closed */
216 }
217 
218 ptcread(dev, uio)
219 	dev_t dev;
220 	struct uio *uio;
221 {
222 	register struct tty *tp;
223 	struct pt_ioctl *pti;
224 
225 	tp = &pt_tty[minor(dev)];
226 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
227 		return;
228 	pti = &pt_ioctl[minor(dev)];
229 	if (pti->pt_flags & PF_PKT) {
230 		if (pti->pt_send) {
231 			(void) ureadc(pti->pt_send, uio);
232 			pti->pt_send = 0;
233 			return;
234 		}
235 		(void) ureadc(0, uio);
236 	}
237 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
238 		if (pti->pt_flags&PF_NBIO) {
239 			u.u_error = EWOULDBLOCK;
240 			return;
241 		}
242 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
243 	}
244 	while (tp->t_outq.c_cc && uio->uio_resid > 0)
245 		if (ureadc(getc(&tp->t_outq), uio) < 0) {
246 			u.u_error = EFAULT;
247 			break;
248 		}
249 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
250 		if (tp->t_state&TS_ASLEEP) {
251 			tp->t_state &= ~TS_ASLEEP;
252 			wakeup((caddr_t)&tp->t_outq);
253 		}
254 		if (tp->t_wsel) {
255 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
256 			tp->t_wsel = 0;
257 			tp->t_state &= ~TS_WCOLL;
258 		}
259 	}
260 }
261 
262 ptsstop(tp, flush)
263 	register struct tty *tp;
264 	int flush;
265 {
266 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
267 
268 	/* note: FLUSHREAD and FLUSHWRITE already ok */
269 	if (flush == 0) {
270 		flush = TIOCPKT_STOP;
271 		pti->pt_flags |= PF_STOPPED;
272 	} else {
273 		pti->pt_flags &= ~PF_STOPPED;
274 	}
275 	pti->pt_send |= flush;
276 	ptcwakeup(tp);
277 }
278 
279 ptcselect(dev, rw)
280 	dev_t dev;
281 	int rw;
282 {
283 	register struct tty *tp = &pt_tty[minor(dev)];
284 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
285 	struct proc *p;
286 	int s;
287 
288 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
289 		return (1);
290 	s = spl5();
291 	switch (rw) {
292 
293 	case FREAD:
294 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
295 			splx(s);
296 			return (1);
297 		}
298 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
299 			pti->pt_flags |= PF_RCOLL;
300 		else
301 			pti->pt_selr = u.u_procp;
302 		break;
303 
304 	case FWRITE:
305 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
306 			splx(s);
307 			return (1);
308 		}
309 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
310 			pti->pt_flags |= PF_WCOLL;
311 		else
312 			pti->pt_selw = u.u_procp;
313 		break;
314 	}
315 	splx(s);
316 	return (0);
317 }
318 
319 ptcwrite(dev, uio)
320 	dev_t dev;
321 	struct uio *uio;
322 {
323 	register struct tty *tp;
324 	register char *cp, *ce;
325 	register int cc;
326 	char locbuf[BUFSIZ];
327 	int cnt = 0;
328 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
329 
330 	tp = &pt_tty[minor(dev)];
331 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
332 		return;
333 	do {
334 		register struct iovec *iov;
335 
336 		if (uio->uio_iovcnt == 0)
337 			break;
338 		iov = uio->uio_iov;
339 		if (iov->iov_len == 0) {
340 			uio->uio_iovcnt--;
341 			uio->uio_iov++;
342 			if (uio->uio_iovcnt < 0)
343 				panic("ptcwrite");
344 			continue;
345 		}
346 		cc = MIN(iov->iov_len, BUFSIZ);
347 		cp = locbuf;
348 		u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
349 		if (u.u_error)
350 			break;
351 		ce = cp + cc;
352 again:
353 		if (pti->pt_flags & PF_REMOTE) {
354 			if (tp->t_rawq.c_cc) {
355 				if (pti->pt_flags & PF_NBIO) {
356 					iov->iov_base -= ce - cp;
357 					iov->iov_len += ce - cp;
358 					uio->uio_resid += ce - cp;
359 					uio->uio_offset -= ce - cp;
360 					u.u_error = EWOULDBLOCK;
361 					return;
362 				}
363 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
364 				goto again;
365 			}
366 			(void) b_to_q(cp, cc, &tp->t_rawq);
367 			(void) putc(0, &tp->t_rawq);
368 			wakeup((caddr_t)&tp->t_rawq);
369 			return;
370 		}
371 		while (cp < ce) {
372 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
373 				wakeup((caddr_t)&tp->t_rawq);
374 				if (tp->t_state & TS_NBIO) {
375 					iov->iov_base -= ce - cp;
376 					iov->iov_len += ce - cp;
377 					uio->uio_resid += ce - cp;
378 					uio->uio_offset -= ce - cp;
379 					if (cnt == 0)
380 						u.u_error = EWOULDBLOCK;
381 					return;
382 				}
383 				/* Better than just flushing it! */
384 				/* Wait for something to be read */
385 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
386 				goto again;
387 			}
388 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
389 			cnt++;
390 		}
391 	} while (uio->uio_resid);
392 }
393 
394 /*ARGSUSED*/
395 ptyioctl(dev, cmd, data, flag)
396 	caddr_t data;
397 	dev_t dev;
398 {
399 	register struct tty *tp = &pt_tty[minor(dev)];
400 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
401 
402 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
403 	if (cdevsw[major(dev)].d_open == ptcopen)
404 		switch (cmd) {
405 
406 		case TIOCPKT:
407 			if (*(int *)data)
408 				pti->pt_flags |= PF_PKT;
409 			else
410 				pti->pt_flags &= ~PF_PKT;
411 			return;
412 
413 		case TIOCREMOTE:
414 			if (*(int *)data)
415 				pti->pt_flags |= PF_REMOTE;
416 			else
417 				pti->pt_flags &= ~PF_REMOTE;
418 			flushtty(tp, FREAD|FWRITE);
419 			return;
420 
421 		case FIONBIO:
422 			if (*(int *)data)
423 				pti->pt_flags |= PF_NBIO;
424 			else
425 				pti->pt_flags &= ~PF_NBIO;
426 			return;
427 
428 		case TIOCSETP:
429 			while (getc(&tp->t_outq) >= 0)
430 				;
431 			break;
432 		}
433 	if (ttioctl(tp, cmd, data, dev) == 0)
434 		u.u_error = ENOTTY;
435 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
436 		      tp->t_un.t_chr.t_startc == ('q'&037));
437 	if (pti->pt_flags & PF_NOSTOP) {
438 		if (stop) {
439 			pti->pt_send &= TIOCPKT_NOSTOP;
440 			pti->pt_send |= TIOCPKT_DOSTOP;
441 			pti->pt_flags &= ~PF_NOSTOP;
442 			ptcwakeup(tp);
443 		}
444 	} else {
445 		if (stop == 0) {
446 			pti->pt_send &= ~TIOCPKT_DOSTOP;
447 			pti->pt_send |= TIOCPKT_NOSTOP;
448 			pti->pt_flags |= PF_NOSTOP;
449 			ptcwakeup(tp);
450 		}
451 	}
452 	}
453 }
454 #endif
455