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