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