xref: /csrg-svn/sys/kern/tty_pty.c (revision 4484)
1 /*	tty_pty.c	4.9	81/10/11	*/
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 	if (tp->t_outq.c_cc)
175 		return (1);
176 	pti = &pt_ioctl[minor(dev)];
177 	if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)select)
178 		pti->pti_flags |= PTCRCOLL;
179 	else
180 		pti->pti_selr = u.u_procp;
181 	return (0);
182 }
183 
184 ptcwrite(dev)
185 dev_t dev;
186 {
187 	register struct tty *tp;
188 	register char *cp, *ce;
189 	register int cc;
190 	char locbuf[BUFSIZ];
191 
192 	tp = &pt_tty[minor(dev)];
193 	if ((tp->t_state&(CARR_ON|ISOPEN)) == 0)
194 		return;
195 	while (u.u_count) {
196 		cc = MIN(u.u_count, BUFSIZ);
197 		cp = locbuf;
198 		iomove(cp, (unsigned)cc, B_WRITE);
199 		if (u.u_error)
200 			break;
201 		ce = cp + cc;
202 		while (cp < ce) {
203 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
204 				wakeup((caddr_t)&tp->t_rawq);
205 				/* Better than just flushing it! */
206 				/* Wait for something to be read */
207 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
208 			}
209 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
210 		}
211 	}
212 }
213 
214 /*ARGSUSED*/
215 ptyioctl(dev, cmd, addr, flag)
216 	caddr_t addr;
217 	dev_t dev;
218 {
219 	register struct tty *tp;
220 	register int tbd;
221 
222 	tp = &pt_tty[minor(dev)];
223 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
224 	if (cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP)
225 		while (getc(&tp->t_outq) >= 0);
226 	if (ttioctl(tp, cmd, addr, dev) == 0)
227 		u.u_error = ENOTTY;
228 }
229 #endif
230