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