xref: /netbsd-src/sys/dev/ofw/ofcons.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: ofcons.c,v 1.3 1996/10/13 01:38:11 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/conf.h>
36 #include <sys/device.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/tty.h>
40 
41 #include <dev/cons.h>
42 
43 #include <dev/ofw/openfirm.h>
44 
45 struct ofc_softc {
46 	struct device of_dev;
47 	struct tty *of_tty;
48 	int of_flags;
49 };
50 /* flags: */
51 #define	OFPOLL		1
52 
53 #define	OFBURSTLEN	128	/* max number of bytes to write in one chunk */
54 
55 static int stdin, stdout;
56 
57 static int ofcmatch __P((struct device *, void *, void *));
58 static void ofcattach __P((struct device *, struct device *, void *));
59 
60 struct cfattach ofcons_ca = {
61 	sizeof(struct ofc_softc), ofcmatch, ofcattach
62 };
63 
64 struct cfdriver ofcons_cd = {
65 	NULL, "ofcons", DV_TTY
66 };
67 
68 static int ofcprobe __P((void));
69 
70 static int
71 ofcmatch(parent, match, aux)
72 	struct device *parent;
73 	void *match, *aux;
74 {
75 	struct ofprobe *ofp = aux;
76 
77 	if (!ofcprobe())
78 		return 0;
79 	return OF_instance_to_package(stdin) == ofp->phandle
80 		|| OF_instance_to_package(stdout) == ofp->phandle;
81 }
82 
83 static void
84 ofcattach(parent, self, aux)
85 	struct device *parent, *self;
86 	void *aux;
87 {
88 	printf("\n");
89 }
90 
91 static void ofcstart __P((struct tty *));
92 static int ofcparam __P((struct tty *, struct termios *));
93 static void ofcpoll __P((void *));
94 
95 int
96 ofcopen(dev, flag, mode, p)
97 	dev_t dev;
98 	int flag, mode;
99 	struct proc *p;
100 {
101 	struct ofc_softc *sc;
102 	int unit = minor(dev);
103 	struct tty *tp;
104 
105 	if (unit >= ofcons_cd.cd_ndevs)
106 		return ENXIO;
107 	sc = ofcons_cd.cd_devs[unit];
108 	if (!sc)
109 		return ENXIO;
110 	if (!(tp = sc->of_tty))
111 		sc->of_tty = tp = ttymalloc();
112 	tp->t_oproc = ofcstart;
113 	tp->t_param = ofcparam;
114 	tp->t_dev = dev;
115 	if (!(tp->t_state & TS_ISOPEN)) {
116 		tp->t_state |= TS_WOPEN;
117 		ttychars(tp);
118 		tp->t_iflag = TTYDEF_IFLAG;
119 		tp->t_oflag = TTYDEF_OFLAG;
120 		tp->t_cflag = TTYDEF_CFLAG;
121 		tp->t_lflag = TTYDEF_LFLAG;
122 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
123 		ofcparam(tp, &tp->t_termios);
124 		ttsetwater(tp);
125 	} else if ((tp->t_state&TS_XCLUDE) && suser(p->p_ucred, &p->p_acflag))
126 		return EBUSY;
127 	tp->t_state |= TS_CARR_ON;
128 
129 	if (!(sc->of_flags & OFPOLL)) {
130 		sc->of_flags |= OFPOLL;
131 		timeout(ofcpoll, sc, 1);
132 	}
133 
134 	return (*linesw[tp->t_line].l_open)(dev, tp);
135 }
136 
137 int
138 ofcclose(dev, flag, mode, p)
139 	dev_t dev;
140 	int flag, mode;
141 	struct proc *p;
142 {
143 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
144 	struct tty *tp = sc->of_tty;
145 
146 	untimeout(ofcpoll, sc);
147 	sc->of_flags &= ~OFPOLL;
148 	(*linesw[tp->t_line].l_close)(tp, flag);
149 	ttyclose(tp);
150 	return 0;
151 }
152 
153 int
154 ofcread(dev, uio, flag)
155 	dev_t dev;
156 	struct uio *uio;
157 	int flag;
158 {
159 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
160 	struct tty *tp = sc->of_tty;
161 
162 	return (*linesw[tp->t_line].l_read)(tp, uio, flag);
163 }
164 
165 int
166 ofcwrite(dev, uio, flag)
167 	dev_t dev;
168 	struct uio *uio;
169 	int flag;
170 {
171 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
172 	struct tty *tp = sc->of_tty;
173 
174 	return (*linesw[tp->t_line].l_write)(tp, uio, flag);
175 }
176 
177 int
178 ofcioctl(dev, cmd, data, flag, p)
179 	dev_t dev;
180 	u_long cmd;
181 	caddr_t data;
182 	int flag;
183 	struct proc *p;
184 {
185 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
186 	struct tty *tp = sc->of_tty;
187 	int error;
188 
189 	if ((error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)) >= 0)
190 		return error;
191 	if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0)
192 		return error;
193 	return ENOTTY;
194 }
195 
196 struct tty *
197 ofctty(dev)
198 	dev_t dev;
199 {
200 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
201 
202 	return sc->of_tty;
203 }
204 
205 void
206 ofcstop(tp, flag)
207 	struct tty *tp;
208 	int flag;
209 {
210 }
211 
212 static void
213 ofcstart(tp)
214 	struct tty *tp;
215 {
216 	struct clist *cl;
217 	int s, len;
218 	u_char buf[OFBURSTLEN];
219 
220 	s = spltty();
221 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
222 		splx(s);
223 		return;
224 	}
225 	tp->t_state |= TS_BUSY;
226 	splx(s);
227 	cl = &tp->t_outq;
228 	len = q_to_b(cl, buf, OFBURSTLEN);
229 	OF_write(stdout, buf, len);
230 	s = spltty();
231 	tp->t_state &= ~TS_BUSY;
232 	if (cl->c_cc) {
233 		tp->t_state |= TS_TIMEOUT;
234 		timeout(ttrstrt, (void *)tp, 1);
235 	}
236 	if (cl->c_cc <= tp->t_lowat) {
237 		if (tp->t_state & TS_ASLEEP) {
238 			tp->t_state &= ~TS_ASLEEP;
239 			wakeup(cl);
240 		}
241 		selwakeup(&tp->t_wsel);
242 	}
243 	splx(s);
244 }
245 
246 static int
247 ofcparam(tp, t)
248 	struct tty *tp;
249 	struct termios *t;
250 {
251 	tp->t_ispeed = t->c_ispeed;
252 	tp->t_ospeed = t->c_ospeed;
253 	tp->t_cflag = t->c_cflag;
254 	return 0;
255 }
256 
257 static void
258 ofcpoll(aux)
259 	void *aux;
260 {
261 	struct ofc_softc *sc = aux;
262 	struct tty *tp = sc->of_tty;
263 	char ch;
264 
265 	while (OF_read(stdin, &ch, 1) > 0) {
266 		if (tp && (tp->t_state & TS_ISOPEN))
267 			(*linesw[tp->t_line].l_rint)(ch, tp);
268 	}
269 	timeout(ofcpoll, sc, 1);
270 }
271 
272 static int
273 ofcprobe()
274 {
275 	int chosen;
276 
277 	if (stdin)
278 		return 1;
279 	if ((chosen = OF_finddevice("/chosen")) == -1)
280 		return 0;
281 	if (OF_getprop(chosen, "stdin", &stdin, sizeof stdin) != sizeof stdin
282 	    || OF_getprop(chosen, "stdout", &stdout, sizeof stdout) != sizeof stdout)
283 		return 0;
284 	return 1;
285 }
286 
287 void
288 ofccnprobe(cd)
289 	struct consdev *cd;
290 {
291 	int maj;
292 
293 	if (!ofcprobe())
294 		return;
295 
296 	for (maj = 0; maj < nchrdev; maj++)
297 		if (cdevsw[maj].d_open == ofcopen)
298 			break;
299 	cd->cn_dev = makedev(maj, 0);
300 	cd->cn_pri = CN_INTERNAL;
301 }
302 
303 void
304 ofccninit(cd)
305 	struct consdev *cd;
306 {
307 }
308 
309 int
310 ofccngetc(dev)
311 	dev_t dev;
312 {
313 	unsigned char ch;
314 	int l;
315 
316 	while ((l = OF_read(stdin, &ch, 1)) != 1)
317 		if (l != -2)
318 			return -1;
319 	return ch;
320 }
321 
322 void
323 ofccnputc(dev, c)
324 	dev_t dev;
325 	int c;
326 {
327 	char ch = c;
328 
329 	OF_write(stdout, &ch, 1);
330 }
331 
332 void
333 ofccnpollc(dev, on)
334 	dev_t dev;
335 	int on;
336 {
337 	struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
338 
339 	if (!sc)
340 		return;
341 	if (on) {
342 		if (sc->of_flags & OFPOLL)
343 			untimeout(ofcpoll, sc);
344 		sc->of_flags &= ~OFPOLL;
345 	} else {
346 		if (!(sc->of_flags & OFPOLL)) {
347 			sc->of_flags |= OFPOLL;
348 			timeout(ofcpoll, sc, 1);
349 		}
350 	}
351 }
352