xref: /csrg-svn/sys/kern/tty_pty.c (revision 5396)
1 /*	tty_pty.c	4.11	82/01/13	*/
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 
11 #include "../h/param.h"
12 #include "../h/systm.h"
13 #include "../h/tty.h"
14 #include "../h/dir.h"
15 #include "../h/user.h"
16 #include "../h/conf.h"
17 #include "../h/buf.h"
18 #include "../h/file.h"
19 #include "../h/proc.h"
20 
21 #undef	NPTY
22 #define NPTY 16
23 
24 #define BUFSIZ 100		/* Chunk size iomoved from user */
25 
26 /*
27  * pts == /dev/tty[pP]?
28  * ptc == /dev/ptp[pP]?
29  */
30 struct	tty pt_tty[NPTY];
31 struct	pt_ioctl {
32 	int	pti_flags;
33 	struct	clist pti_ioctl, pti_ioans;
34 	int	pti_gensym;
35 	struct	proc *pti_selr;
36 } pt_ioctl[NPTY];
37 
38 #define	PTCRCOLL	0x01
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 & 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&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 |= CARR_ON;
60 	while ((tp->t_state & CARR_ON) == 0) {
61 		tp->t_state |= 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 {					/* Close slave part of PTY */
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 
81 	tp = &pt_tty[minor(dev)];
82 	if (tp->t_oproc) {
83 		(*linesw[tp->t_line].l_read)(tp);
84 		wakeup((caddr_t)&tp->t_rawq.c_cf);
85 	}
86 }
87 
88 ptswrite(dev)
89 	dev_t dev;
90 {
91 	register struct tty *tp;
92 
93 	tp = &pt_tty[minor(dev)];
94 	if (tp->t_oproc)
95 		(*linesw[tp->t_line].l_write)(tp);
96 }
97 
98 ptsstart(tp)
99 	struct tty *tp;
100 {
101 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
102 
103 	if (tp->t_state & TTSTOP)
104 		return;
105 	if (pti->pti_selr) {
106 		selwakeup(pti->pti_selr, pti->pti_flags & PTCRCOLL);
107 		pti->pti_selr = 0;
108 		pti->pti_flags &= ~PTCRCOLL;
109 	}
110 	wakeup((caddr_t)&tp->t_outq.c_cf);
111 }
112 
113 /*ARGSUSED*/
114 ptcopen(dev, flag)
115 	dev_t dev;
116 	int flag;
117 {
118 	register struct tty *tp;
119 
120 	if (minor(dev) >= NPTY) {
121 		u.u_error = ENXIO;
122 		return;
123 	}
124 	tp = &pt_tty[minor(dev)];
125 	if (tp->t_oproc) {
126 		u.u_error = EIO;
127 		return;
128 	}
129 	tp->t_oproc = ptsstart;
130 	if (tp->t_state & WOPEN)
131 		wakeup((caddr_t)&tp->t_rawq);
132 	tp->t_state |= CARR_ON;
133 }
134 
135 ptcclose(dev)
136 	dev_t dev;
137 {
138 	register struct tty *tp;
139 
140 	tp = &pt_tty[minor(dev)];
141 	if (tp->t_state & ISOPEN)
142 		gsignal(tp->t_pgrp, SIGHUP);
143 	tp->t_state &= ~CARR_ON;	/* virtual carrier gone */
144 	flushtty(tp, FREAD|FWRITE);
145 	tp->t_oproc = 0;		/* mark closed */
146 }
147 
148 ptcread(dev)
149 dev_t dev;
150 {
151 	register struct tty *tp;
152 
153 	tp = &pt_tty[minor(dev)];
154 	if ((tp->t_state&(CARR_ON|ISOPEN)) == 0)
155 		return;
156 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TTSTOP))
157 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
158 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0);
159 	if (tp->t_outq.c_cc <= TTLOWAT(tp)  && (tp->t_state&ASLEEP)) {
160 		tp->t_state &= ~ASLEEP;
161 		wakeup((caddr_t)&tp->t_outq);
162 	}
163 }
164 
165 ptcselect(dev)
166 	dev_t dev;
167 {
168 	register struct tty *tp = &pt_tty[minor(dev)];
169 	struct pt_ioctl *pti;
170 	struct proc *p;
171 
172 	if ((tp->t_state&(CARR_ON|ISOPEN)) == 0) {
173 		return (1);
174 }
175 	if (tp->t_outq.c_cc) {
176 		return (1);
177 }
178 	pti = &pt_ioctl[minor(dev)];
179 	if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)&selwait)
180 		pti->pti_flags |= PTCRCOLL;
181 	else
182 		pti->pti_selr = u.u_procp;
183 	return (0);
184 }
185 
186 ptcwrite(dev)
187 dev_t dev;
188 {
189 	register struct tty *tp;
190 	register char *cp, *ce;
191 	register int cc;
192 	char locbuf[BUFSIZ];
193 
194 	tp = &pt_tty[minor(dev)];
195 	if ((tp->t_state&(CARR_ON|ISOPEN)) == 0)
196 		return;
197 	while (u.u_count) {
198 		cc = MIN(u.u_count, BUFSIZ);
199 		cp = locbuf;
200 		iomove(cp, (unsigned)cc, B_WRITE);
201 		if (u.u_error)
202 			break;
203 		ce = cp + cc;
204 		while (cp < ce) {
205 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
206 				wakeup((caddr_t)&tp->t_rawq);
207 				/* Better than just flushing it! */
208 				/* Wait for something to be read */
209 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
210 			}
211 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
212 		}
213 	}
214 }
215 
216 /*ARGSUSED*/
217 ptyioctl(dev, cmd, addr, flag)
218 	caddr_t addr;
219 	dev_t dev;
220 {
221 	register struct tty *tp;
222 
223 	tp = &pt_tty[minor(dev)];
224 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
225 	if (cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP)
226 		while (getc(&tp->t_outq) >= 0);
227 	if (ttioctl(tp, cmd, addr, dev) == 0)
228 		u.u_error = ENOTTY;
229 }
230 #endif
231