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