xref: /csrg-svn/sys/kern/tty_pty.c (revision 5894)
1 /*	tty_pty.c	4.17	82/02/18	*/
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 
44 /*ARGSUSED*/
45 ptsopen(dev, flag)
46 	dev_t dev;
47 {
48 	register struct tty *tp;
49 
50 	if (minor(dev) >= NPTY) {
51 		u.u_error = ENXIO;
52 		return;
53 	}
54 	tp = &pt_tty[minor(dev)];
55 	if ((tp->t_state & TS_ISOPEN) == 0) {
56 		ttychars(tp);		/* Set up default chars */
57 		tp->t_flags = 0;	/* No features (nor raw mode) */
58 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
59 		u.u_error = EBUSY;
60 		return;
61 	}
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 	(*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 }
79 
80 ptsread(dev)
81 	dev_t dev;
82 {
83 	register struct tty *tp = &pt_tty[minor(dev)];
84 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
85 
86 again:
87 	if (pti->pt_flags & PF_REMOTE) {
88 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
89 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
90 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
91 	/*
92 			    (u.u_procp->p_flag&SDETACH) ||
93 	*/
94 			    u.u_procp->p_flag&SVFORK)
95 				return;
96 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
97 			sleep((caddr_t)&lbolt, TTIPRI);
98 		}
99 		if (tp->t_rawq.c_cc == 0) {
100 			if (tp->t_state & TS_NBIO) {
101 				u.u_error = EWOULDBLOCK;
102 				return;
103 			}
104 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
105 			goto again;
106 		}
107 		while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0)
108 			;
109 		if (tp->t_rawq.c_cc == 1)
110 			(void) getc(&tp->t_rawq);
111 		if (tp->t_rawq.c_cc)
112 			return;
113 	} else
114 		if (tp->t_oproc)
115 			(*linesw[tp->t_line].l_read)(tp);
116 	wakeup((caddr_t)&tp->t_rawq.c_cf);
117 	if (pti->pt_selw) {
118 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
119 		pti->pt_selw = 0;
120 		pti->pt_flags &= ~PF_WCOLL;
121 	}
122 }
123 
124 /*
125  * Write to pseudo-tty.
126  * Wakeups of controlling tty will happen
127  * indirectly, when tty driver calls ptsstart.
128  */
129 ptswrite(dev)
130 	dev_t dev;
131 {
132 	register struct tty *tp;
133 
134 	tp = &pt_tty[minor(dev)];
135 	if (tp->t_oproc)
136 		(*linesw[tp->t_line].l_write)(tp);
137 }
138 
139 /*
140  * Start output on pseudo-tty.
141  * Wake up process selecting or sleeping for input from controlling tty.
142  */
143 ptsstart(tp)
144 	struct tty *tp;
145 {
146 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
147 
148 	if (tp->t_state & TS_TTSTOP)
149 		return;
150 	if (pti->pt_flags & PF_STOPPED) {
151 		pti->pt_flags &= ~PF_STOPPED;
152 		pti->pt_send = TIOCPKT_START;
153 	}
154 	ptcwakeup(tp);
155 }
156 
157 ptcwakeup(tp)
158 	struct tty *tp;
159 {
160 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
161 
162 	if (pti->pt_selr) {
163 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
164 		pti->pt_selr = 0;
165 		pti->pt_flags &= ~PF_RCOLL;
166 	}
167 	wakeup((caddr_t)&tp->t_outq.c_cf);
168 }
169 
170 /*ARGSUSED*/
171 ptcopen(dev, flag)
172 	dev_t dev;
173 	int flag;
174 {
175 	register struct tty *tp;
176 	struct pt_ioctl *pti;
177 
178 	if (minor(dev) >= NPTY) {
179 		u.u_error = ENXIO;
180 		return;
181 	}
182 	tp = &pt_tty[minor(dev)];
183 	if (tp->t_oproc) {
184 		u.u_error = EIO;
185 		return;
186 	}
187 	tp->t_oproc = ptsstart;
188 	if (tp->t_state & TS_WOPEN)
189 		wakeup((caddr_t)&tp->t_rawq);
190 	tp->t_state |= TS_CARR_ON;
191 	pti = &pt_ioctl[minor(dev)];
192 	pti->pt_flags = 0;
193 	pti->pt_send = 0;
194 }
195 
196 ptcclose(dev)
197 	dev_t dev;
198 {
199 	register struct tty *tp;
200 
201 	tp = &pt_tty[minor(dev)];
202 	if (tp->t_state & TS_ISOPEN)
203 		gsignal(tp->t_pgrp, SIGHUP);
204 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
205 	flushtty(tp, FREAD|FWRITE);
206 	tp->t_oproc = 0;		/* mark closed */
207 }
208 
209 ptcread(dev)
210 	dev_t dev;
211 {
212 	register struct tty *tp;
213 	struct pt_ioctl *pti;
214 
215 	tp = &pt_tty[minor(dev)];
216 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
217 		return;
218 	pti = &pt_ioctl[minor(dev)];
219 	if (pti->pt_flags & PF_PKT) {
220 		if (pti->pt_send) {
221 			passc(pti->pt_send);
222 			pti->pt_send = 0;
223 			return;
224 		}
225 		passc(0);
226 	}
227 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
228 		if (pti->pt_flags&PF_NBIO) {
229 			u.u_error = EWOULDBLOCK;
230 			return;
231 		}
232 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
233 	}
234 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
235 		;
236 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
237 		if (tp->t_state&TS_ASLEEP) {
238 			tp->t_state &= ~TS_ASLEEP;
239 			wakeup((caddr_t)&tp->t_outq);
240 		}
241 		if (tp->t_wsel) {
242 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
243 			tp->t_wsel = 0;
244 			tp->t_state &= ~TS_WCOLL;
245 		}
246 	}
247 }
248 
249 ptsstop(tp, flush)
250 	register struct tty *tp;
251 	int flush;
252 {
253 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
254 
255 	/* note: FLUSHREAD and FLUSHWRITE already ok */
256 	if (flush == 0) {
257 		flush = TIOCPKT_STOP;
258 		pti->pt_flags |= PF_STOPPED;
259 	} else {
260 		pti->pt_flags &= ~PF_STOPPED;
261 	}
262 	pti->pt_send = flush;
263 	ptcwakeup(tp);
264 }
265 
266 ptcselect(dev, rw)
267 	dev_t dev;
268 	int rw;
269 {
270 	register struct tty *tp = &pt_tty[minor(dev)];
271 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
272 	struct proc *p;
273 	int s;
274 
275 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
276 		return (1);
277 	s = spl5();
278 	switch (rw) {
279 
280 	case FREAD:
281 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
282 			splx(s);
283 			return (1);
284 		}
285 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
286 			pti->pt_flags |= PF_RCOLL;
287 		else
288 			pti->pt_selr = u.u_procp;
289 		break;
290 
291 	case FWRITE:
292 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
293 			splx(s);
294 			return (1);
295 		}
296 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
297 			pti->pt_flags |= PF_WCOLL;
298 		else
299 			pti->pt_selw = u.u_procp;
300 		break;
301 	}
302 	splx(s);
303 	return (0);
304 }
305 
306 ptcwrite(dev)
307 	dev_t dev;
308 {
309 	register struct tty *tp;
310 	register char *cp, *ce;
311 	register int cc;
312 	char locbuf[BUFSIZ];
313 	int cnt = 0;
314 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
315 
316 	tp = &pt_tty[minor(dev)];
317 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
318 		return;
319 	do {
320 		cc = MIN(u.u_count, BUFSIZ);
321 		cp = locbuf;
322 		iomove(cp, (unsigned)cc, B_WRITE);
323 		if (u.u_error)
324 			break;
325 		ce = cp + cc;
326 again:
327 		if (pti->pt_flags & PF_REMOTE) {
328 			if (tp->t_rawq.c_cc) {
329 				if (pti->pt_flags & PF_NBIO) {
330 					u.u_count += ce - cp;
331 					u.u_error = EWOULDBLOCK;
332 					return;
333 				}
334 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
335 				goto again;
336 			}
337 			b_to_q(cp, cc, &tp->t_rawq);
338 			putc(0, &tp->t_rawq);
339 			wakeup((caddr_t)&tp->t_rawq);
340 			return;
341 		}
342 		while (cp < ce) {
343 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
344 				wakeup((caddr_t)&tp->t_rawq);
345 				if (tp->t_state & TS_NBIO) {
346 					u.u_count += ce - cp;
347 					if (cnt == 0)
348 						u.u_error = EWOULDBLOCK;
349 					return;
350 				}
351 				/* Better than just flushing it! */
352 				/* Wait for something to be read */
353 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
354 				goto again;
355 			}
356 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
357 			cnt++;
358 		}
359 	} while (u.u_count);
360 }
361 
362 /*ARGSUSED*/
363 ptyioctl(dev, cmd, addr, flag)
364 	caddr_t addr;
365 	dev_t dev;
366 {
367 	register struct tty *tp;
368 
369 	tp = &pt_tty[minor(dev)];
370 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
371 	if (cdevsw[major(dev)].d_open == ptcopen) {
372 		register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
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 }
416 #endif
417