xref: /csrg-svn/sys/kern/tty_pty.c (revision 5411)
1 /*	tty_pty.c	4.13	82/01/15	*/
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	pti_flags;
32 	struct	clist pti_ioctl, pti_ioans;
33 	int	pti_gensym;
34 	struct	proc *pti_selr, *pti_selw;
35 } pt_ioctl[NPTY];
36 
37 #define	PTCRCOLL	0x01
38 #define	PTCWCOLL	0x02
39 #define	PTCNBIO		0x04
40 
41 /*ARGSUSED*/
42 ptsopen(dev, flag)
43 	dev_t dev;
44 {
45 	register struct tty *tp;
46 
47 	if (minor(dev) >= NPTY) {
48 		u.u_error = ENXIO;
49 		return;
50 	}
51 	tp = &pt_tty[minor(dev)];
52 	if ((tp->t_state & TS_ISOPEN) == 0) {
53 		ttychars(tp);		/* Set up default chars */
54 		tp->t_flags = 0;	/* No features (nor raw mode) */
55 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
56 		u.u_error = EBUSY;
57 		return;
58 	}
59 	if (tp->t_oproc)			/* Ctrlr still around. */
60 		tp->t_state |= TS_CARR_ON;
61 	while ((tp->t_state & TS_CARR_ON) == 0) {
62 		tp->t_state |= TS_WOPEN;
63 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
64 	}
65 	(*linesw[tp->t_line].l_open)(dev, tp);
66 }
67 
68 ptsclose(dev)
69 	dev_t dev;
70 {
71 	register struct tty *tp;
72 
73 	tp = &pt_tty[minor(dev)];
74 	(*linesw[tp->t_line].l_close)(tp);
75 }
76 
77 ptsread(dev)
78 	dev_t dev;
79 {
80 	register struct tty *tp;
81 	register struct pt_ioctl *pti;
82 
83 	tp = &pt_tty[minor(dev)];
84 	if (tp->t_oproc) {
85 		(*linesw[tp->t_line].l_read)(tp);
86 		wakeup((caddr_t)&tp->t_rawq.c_cf);
87 		if (tp->t_rawq.c_cc < TTYHOG/2 &&
88 		    (pti = &pt_ioctl[minor(tp->t_dev)])->pti_selw) {
89 			selwakeup(pti->pti_selw, pti->pti_flags & PTCWCOLL);
90 			pti->pti_selw = 0;
91 			pti->pti_flags &= ~PTCWCOLL;
92 		}
93 	}
94 }
95 
96 /*
97  * Write to pseudo-tty.
98  * Wakeups of controlling tty will happen
99  * indirectly, when tty driver calls ptsstart.
100  */
101 ptswrite(dev)
102 	dev_t dev;
103 {
104 	register struct tty *tp;
105 
106 	tp = &pt_tty[minor(dev)];
107 	if (tp->t_oproc)
108 		(*linesw[tp->t_line].l_write)(tp);
109 }
110 
111 /*
112  * Start output on pseudo-tty.
113  * Wake up process selecting or sleeping for input from controlling tty.
114  */
115 ptsstart(tp)
116 	struct tty *tp;
117 {
118 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
119 
120 	if (tp->t_state & TS_TTSTOP)
121 		return;
122 	if (pti->pti_selr) {
123 		selwakeup(pti->pti_selr, pti->pti_flags & PTCRCOLL);
124 		pti->pti_selr = 0;
125 		pti->pti_flags &= ~PTCRCOLL;
126 	}
127 	wakeup((caddr_t)&tp->t_outq.c_cf);
128 }
129 
130 /*ARGSUSED*/
131 ptcopen(dev, flag)
132 	dev_t dev;
133 	int flag;
134 {
135 	register struct tty *tp;
136 
137 	if (minor(dev) >= NPTY) {
138 		u.u_error = ENXIO;
139 		return;
140 	}
141 	tp = &pt_tty[minor(dev)];
142 	if (tp->t_oproc) {
143 		u.u_error = EIO;
144 		return;
145 	}
146 	tp->t_oproc = ptsstart;
147 	if (tp->t_state & TS_WOPEN)
148 		wakeup((caddr_t)&tp->t_rawq);
149 	tp->t_state |= TS_CARR_ON;
150 }
151 
152 ptcclose(dev)
153 	dev_t dev;
154 {
155 	register struct tty *tp;
156 
157 	tp = &pt_tty[minor(dev)];
158 	if (tp->t_state & TS_ISOPEN)
159 		gsignal(tp->t_pgrp, SIGHUP);
160 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
161 	flushtty(tp, FREAD|FWRITE);
162 	tp->t_oproc = 0;		/* mark closed */
163 }
164 
165 ptcread(dev)
166 dev_t dev;
167 {
168 	register struct tty *tp;
169 
170 	tp = &pt_tty[minor(dev)];
171 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
172 		return;
173 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
174 		if (pt_ioctl[minor(dev)].pti_flags&PTCNBIO) {
175 			u.u_error = EWOULDBLOCK;
176 			return;
177 		}
178 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
179 	}
180 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
181 		;
182 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
183 		if (tp->t_state&TS_ASLEEP) {
184 			tp->t_state &= ~TS_ASLEEP;
185 			wakeup((caddr_t)&tp->t_outq);
186 		}
187 		if (tp->t_wsel) {
188 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
189 			tp->t_wsel = 0;
190 			tp->t_state &= ~TS_WCOLL;
191 		}
192 	}
193 }
194 
195 ptcselect(dev, rw)
196 	dev_t dev;
197 	int rw;
198 {
199 	register struct tty *tp = &pt_tty[minor(dev)];
200 	struct pt_ioctl *pti;
201 	struct proc *p;
202 
203 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
204 		return (1);
205 	switch (rw) {
206 
207 	case FREAD:
208 		if (tp->t_outq.c_cc)
209 			return (1);
210 		pti = &pt_ioctl[minor(dev)];
211 		if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)&selwait)
212 			pti->pti_flags |= PTCRCOLL;
213 		else
214 			pti->pti_selr = u.u_procp;
215 		return (0);
216 
217 	case FWRITE:
218 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2)
219 			return (1);
220 		pti = &pt_ioctl[minor(dev)];
221 		if ((p = pti->pti_selw) && p->p_wchan == (caddr_t)&selwait)
222 			pti->pti_flags |= PTCWCOLL;
223 		else
224 			pti->pti_selw = u.u_procp;
225 	}
226 }
227 
228 ptcwrite(dev)
229 	dev_t dev;
230 {
231 	register struct tty *tp;
232 	register char *cp, *ce;
233 	register int cc;
234 	char locbuf[BUFSIZ];
235 	int cnt = 0;
236 
237 	tp = &pt_tty[minor(dev)];
238 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
239 		return;
240 	while (u.u_count) {
241 		cc = MIN(u.u_count, BUFSIZ);
242 		cp = locbuf;
243 		iomove(cp, (unsigned)cc, B_WRITE);
244 		if (u.u_error)
245 			break;
246 		ce = cp + cc;
247 		while (cp < ce) {
248 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
249 				wakeup((caddr_t)&tp->t_rawq);
250 				if (tp->t_state & TS_NBIO) {
251 					u.u_count += ce - cp;
252 					if (cnt == 0)
253 						u.u_error = EWOULDBLOCK;
254 					return;
255 				}
256 				/* Better than just flushing it! */
257 				/* Wait for something to be read */
258 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
259 			}
260 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
261 			cnt++;
262 		}
263 	}
264 }
265 
266 /*ARGSUSED*/
267 ptyioctl(dev, cmd, addr, flag)
268 	caddr_t addr;
269 	dev_t dev;
270 {
271 	register struct tty *tp;
272 
273 	tp = &pt_tty[minor(dev)];
274 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
275 	if (cdevsw[major(dev)].d_open == ptcopen) {
276 		if (cmd == FIONBIO) {
277 			int nbio;
278 			register struct pt_ioctl *pti;
279 			if (copyin(addr, &nbio, sizeof (nbio))) {
280 				u.u_error = EFAULT;
281 				return;
282 			}
283 			pti = &pt_ioctl[minor(dev)];
284 			if (nbio)
285 				pti->pti_flags |= PTCNBIO;
286 			else
287 				pti->pti_flags &= ~PTCNBIO;
288 			return;
289 		}
290 		if (cmd == TIOCSETP)
291 			while (getc(&tp->t_outq) >= 0);
292 	}
293 	if (ttioctl(tp, cmd, addr, dev) == 0)
294 		u.u_error = ENOTTY;
295 }
296 #endif
297