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