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