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