xref: /csrg-svn/sys/kern/tty_pty.c (revision 5430)
1 /*	tty_pty.c	4.15	82/01/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/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_FLOWCTL	0x10		/* peers flow control mode */
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 
121 	if (tp->t_state & TS_TTSTOP)
122 		return;
123 	ptcwakeup(tp);
124 }
125 
126 ptcwakeup(tp)
127 	struct tty *tp;
128 {
129 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
130 
131 	if (pti->pt_selr) {
132 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
133 		pti->pt_selr = 0;
134 		pti->pt_flags &= ~PF_RCOLL;
135 	}
136 	wakeup((caddr_t)&tp->t_outq.c_cf);
137 }
138 
139 /*ARGSUSED*/
140 ptcopen(dev, flag)
141 	dev_t dev;
142 	int flag;
143 {
144 	register struct tty *tp;
145 	struct pt_ioctl *pti;
146 
147 	if (minor(dev) >= NPTY) {
148 		u.u_error = ENXIO;
149 		return;
150 	}
151 	tp = &pt_tty[minor(dev)];
152 	if (tp->t_oproc) {
153 		u.u_error = EIO;
154 		return;
155 	}
156 	tp->t_oproc = ptsstart;
157 	if (tp->t_state & TS_WOPEN)
158 		wakeup((caddr_t)&tp->t_rawq);
159 	tp->t_state |= TS_CARR_ON;
160 	pti = &pt_ioctl[minor(dev)];
161 	pti->pt_flags = 0;
162 	pti->pt_send = 0;
163 }
164 
165 ptcclose(dev)
166 	dev_t dev;
167 {
168 	register struct tty *tp;
169 
170 	tp = &pt_tty[minor(dev)];
171 	if (tp->t_state & TS_ISOPEN)
172 		gsignal(tp->t_pgrp, SIGHUP);
173 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
174 	flushtty(tp, FREAD|FWRITE);
175 	tp->t_oproc = 0;		/* mark closed */
176 }
177 
178 ptcread(dev)
179 	dev_t dev;
180 {
181 	register struct tty *tp;
182 	struct pt_ioctl *pti;
183 
184 	tp = &pt_tty[minor(dev)];
185 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
186 		return;
187 	pti = &pt_ioctl[minor(dev)];
188 	if (pti->pt_flags & PF_PKT) {
189 		if (pti->pt_send) {
190 			passc(pti->pt_send);
191 			pti->pt_send = 0;
192 			return;
193 		}
194 		passc(0);
195 	}
196 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
197 		if (pti->pt_flags&PF_NBIO) {
198 			u.u_error = EWOULDBLOCK;
199 			return;
200 		}
201 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
202 	}
203 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
204 		;
205 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
206 		if (tp->t_state&TS_ASLEEP) {
207 			tp->t_state &= ~TS_ASLEEP;
208 			wakeup((caddr_t)&tp->t_outq);
209 		}
210 		if (tp->t_wsel) {
211 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
212 			tp->t_wsel = 0;
213 			tp->t_state &= ~TS_WCOLL;
214 		}
215 	}
216 }
217 
218 ptsstop(tp, flush)
219 	register struct tty *tp;
220 	int flush;
221 {
222 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
223 
224 	if (flush == 0)
225 		return;
226 	pti->pt_send |= flush;
227 	ptcwakeup(tp);
228 }
229 
230 ptcselect(dev, rw)
231 	dev_t dev;
232 	int rw;
233 {
234 	register struct tty *tp = &pt_tty[minor(dev)];
235 	struct pt_ioctl *pti;
236 	struct proc *p;
237 	int s;
238 
239 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
240 		return (1);
241 	s = spl5();
242 	switch (rw) {
243 
244 	case FREAD:
245 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
246 			splx(s);
247 			return (1);
248 		}
249 		pti = &pt_ioctl[minor(dev)];
250 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
251 			pti->pt_flags |= PF_RCOLL;
252 		else
253 			pti->pt_selr = u.u_procp;
254 		break;
255 
256 	case FWRITE:
257 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) {
258 			splx(s);
259 			return (1);
260 		}
261 		pti = &pt_ioctl[minor(dev)];
262 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
263 			pti->pt_flags |= PF_WCOLL;
264 		else
265 			pti->pt_selw = u.u_procp;
266 		break;
267 	}
268 	splx(s);
269 	return (0);
270 }
271 
272 ptcwrite(dev)
273 	dev_t dev;
274 {
275 	register struct tty *tp;
276 	register char *cp, *ce;
277 	register int cc;
278 	char locbuf[BUFSIZ];
279 	int cnt = 0;
280 
281 	tp = &pt_tty[minor(dev)];
282 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
283 		return;
284 	while (u.u_count) {
285 		cc = MIN(u.u_count, BUFSIZ);
286 		cp = locbuf;
287 		iomove(cp, (unsigned)cc, B_WRITE);
288 		if (u.u_error)
289 			break;
290 		ce = cp + cc;
291 		while (cp < ce) {
292 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
293 				wakeup((caddr_t)&tp->t_rawq);
294 				if (tp->t_state & TS_NBIO) {
295 					u.u_count += ce - cp;
296 					if (cnt == 0)
297 						u.u_error = EWOULDBLOCK;
298 					return;
299 				}
300 				/* Better than just flushing it! */
301 				/* Wait for something to be read */
302 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
303 			}
304 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
305 			cnt++;
306 		}
307 	}
308 }
309 
310 /*ARGSUSED*/
311 ptyioctl(dev, cmd, addr, flag)
312 	caddr_t addr;
313 	dev_t dev;
314 {
315 	register struct tty *tp;
316 
317 	tp = &pt_tty[minor(dev)];
318 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
319 	if (cdevsw[major(dev)].d_open == ptcopen) {
320 		register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
321 		if (cmd == TIOCPKT) {
322 			int packet;
323 			if (copyin((caddr_t)addr, &packet, sizeof (packet))) {
324 				u.u_error = EFAULT;
325 				return;
326 			}
327 			if (packet)
328 				pti->pt_flags |= PF_PKT;
329 			else
330 				pti->pt_flags &= ~PF_PKT;
331 			return;
332 		}
333 		if (cmd == FIONBIO) {
334 			int nbio;
335 			if (copyin(addr, &nbio, sizeof (nbio))) {
336 				u.u_error = EFAULT;
337 				return;
338 			}
339 			if (nbio)
340 				pti->pt_flags |= PF_NBIO;
341 			else
342 				pti->pt_flags &= ~PF_NBIO;
343 			return;
344 		}
345 		if (cmd == TIOCSETP)
346 			while (getc(&tp->t_outq) >= 0);
347 	}
348 	if (ttioctl(tp, cmd, addr, dev) == 0)
349 		u.u_error = ENOTTY;
350 }
351 #endif
352