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