ofcons.c revision 1.7 1 /* $NetBSD: ofcons.c,v 1.7 1998/01/26 21:49:00 cgd 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 *, struct cfdata *, 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 extern struct cfdriver ofcons_cd;
65
66 static int ofcprobe __P((void));
67
68 static int
69 ofcmatch(parent, match, aux)
70 struct device *parent;
71 struct cfdata *match;
72 void *aux;
73 {
74 struct ofprobe *ofp = aux;
75
76 if (!ofcprobe())
77 return 0;
78 return OF_instance_to_package(stdin) == ofp->phandle
79 || OF_instance_to_package(stdout) == ofp->phandle;
80 }
81
82 static void
83 ofcattach(parent, self, aux)
84 struct device *parent, *self;
85 void *aux;
86 {
87 printf("\n");
88 }
89
90 static void ofcstart __P((struct tty *));
91 static int ofcparam __P((struct tty *, struct termios *));
92 static void ofcpoll __P((void *));
93
94 int
95 ofcopen(dev, flag, mode, p)
96 dev_t dev;
97 int flag, mode;
98 struct proc *p;
99 {
100 struct ofc_softc *sc;
101 int unit = minor(dev);
102 struct tty *tp;
103
104 if (unit >= ofcons_cd.cd_ndevs)
105 return ENXIO;
106 sc = ofcons_cd.cd_devs[unit];
107 if (!sc)
108 return ENXIO;
109 if (!(tp = sc->of_tty))
110 sc->of_tty = tp = ttymalloc();
111 tp->t_oproc = ofcstart;
112 tp->t_param = ofcparam;
113 tp->t_dev = dev;
114 if (!(tp->t_state & TS_ISOPEN)) {
115 tp->t_state |= TS_WOPEN;
116 ttychars(tp);
117 tp->t_iflag = TTYDEF_IFLAG;
118 tp->t_oflag = TTYDEF_OFLAG;
119 tp->t_cflag = TTYDEF_CFLAG;
120 tp->t_lflag = TTYDEF_LFLAG;
121 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
122 ofcparam(tp, &tp->t_termios);
123 ttsetwater(tp);
124 } else if ((tp->t_state&TS_XCLUDE) && suser(p->p_ucred, &p->p_acflag))
125 return EBUSY;
126 tp->t_state |= TS_CARR_ON;
127
128 if (!(sc->of_flags & OFPOLL)) {
129 sc->of_flags |= OFPOLL;
130 timeout(ofcpoll, sc, 1);
131 }
132
133 return (*linesw[tp->t_line].l_open)(dev, tp);
134 }
135
136 int
137 ofcclose(dev, flag, mode, p)
138 dev_t dev;
139 int flag, mode;
140 struct proc *p;
141 {
142 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
143 struct tty *tp = sc->of_tty;
144
145 untimeout(ofcpoll, sc);
146 sc->of_flags &= ~OFPOLL;
147 (*linesw[tp->t_line].l_close)(tp, flag);
148 ttyclose(tp);
149 return 0;
150 }
151
152 int
153 ofcread(dev, uio, flag)
154 dev_t dev;
155 struct uio *uio;
156 int flag;
157 {
158 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
159 struct tty *tp = sc->of_tty;
160
161 return (*linesw[tp->t_line].l_read)(tp, uio, flag);
162 }
163
164 int
165 ofcwrite(dev, uio, flag)
166 dev_t dev;
167 struct uio *uio;
168 int flag;
169 {
170 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
171 struct tty *tp = sc->of_tty;
172
173 return (*linesw[tp->t_line].l_write)(tp, uio, flag);
174 }
175
176 int
177 ofcioctl(dev, cmd, data, flag, p)
178 dev_t dev;
179 u_long cmd;
180 caddr_t data;
181 int flag;
182 struct proc *p;
183 {
184 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
185 struct tty *tp = sc->of_tty;
186 int error;
187
188 if ((error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)) >= 0)
189 return error;
190 if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0)
191 return error;
192 return ENOTTY;
193 }
194
195 struct tty *
196 ofctty(dev)
197 dev_t dev;
198 {
199 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
200
201 return sc->of_tty;
202 }
203
204 void
205 ofcstop(tp, flag)
206 struct tty *tp;
207 int flag;
208 {
209 }
210
211 static void
212 ofcstart(tp)
213 struct tty *tp;
214 {
215 struct clist *cl;
216 int s, len;
217 u_char buf[OFBURSTLEN];
218
219 s = spltty();
220 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
221 splx(s);
222 return;
223 }
224 tp->t_state |= TS_BUSY;
225 splx(s);
226 cl = &tp->t_outq;
227 len = q_to_b(cl, buf, OFBURSTLEN);
228 OF_write(stdout, buf, len);
229 s = spltty();
230 tp->t_state &= ~TS_BUSY;
231 if (cl->c_cc) {
232 tp->t_state |= TS_TIMEOUT;
233 timeout(ttrstrt, (void *)tp, 1);
234 }
235 if (cl->c_cc <= tp->t_lowat) {
236 if (tp->t_state & TS_ASLEEP) {
237 tp->t_state &= ~TS_ASLEEP;
238 wakeup(cl);
239 }
240 selwakeup(&tp->t_wsel);
241 }
242 splx(s);
243 }
244
245 static int
246 ofcparam(tp, t)
247 struct tty *tp;
248 struct termios *t;
249 {
250 tp->t_ispeed = t->c_ispeed;
251 tp->t_ospeed = t->c_ospeed;
252 tp->t_cflag = t->c_cflag;
253 return 0;
254 }
255
256 static void
257 ofcpoll(aux)
258 void *aux;
259 {
260 struct ofc_softc *sc = aux;
261 struct tty *tp = sc->of_tty;
262 char ch;
263
264 while (OF_read(stdin, &ch, 1) > 0) {
265 if (tp && (tp->t_state & TS_ISOPEN))
266 (*linesw[tp->t_line].l_rint)(ch, tp);
267 }
268 timeout(ofcpoll, sc, 1);
269 }
270
271 static int
272 ofcprobe()
273 {
274 int chosen;
275 char stdinbuf[4], stdoutbuf[4];
276
277 if (stdin)
278 return 1;
279 if ((chosen = OF_finddevice("/chosen")) == -1)
280 return 0;
281 if (OF_getprop(chosen, "stdin", stdinbuf, sizeof stdinbuf) !=
282 sizeof stdinbuf ||
283 OF_getprop(chosen, "stdout", stdoutbuf, sizeof stdoutbuf) !=
284 sizeof stdoutbuf)
285 return 0;
286
287 /* Decode properties. */
288 stdin = of_decode_int(stdinbuf);
289 stdout = of_decode_int(stdoutbuf);
290
291 return 1;
292 }
293
294 void
295 ofccnprobe(cd)
296 struct consdev *cd;
297 {
298 int maj;
299
300 if (!ofcprobe())
301 return;
302
303 for (maj = 0; maj < nchrdev; maj++)
304 if (cdevsw[maj].d_open == ofcopen)
305 break;
306 cd->cn_dev = makedev(maj, 0);
307 cd->cn_pri = CN_INTERNAL;
308 }
309
310 void
311 ofccninit(cd)
312 struct consdev *cd;
313 {
314 }
315
316 int
317 ofccngetc(dev)
318 dev_t dev;
319 {
320 unsigned char ch = '\0';
321 int l;
322
323 while ((l = OF_read(stdin, &ch, 1)) != 1)
324 if (l != -2 && l != 0)
325 return -1;
326 return ch;
327 }
328
329 void
330 ofccnputc(dev, c)
331 dev_t dev;
332 int c;
333 {
334 char ch = c;
335
336 OF_write(stdout, &ch, 1);
337 }
338
339 void
340 ofccnpollc(dev, on)
341 dev_t dev;
342 int on;
343 {
344 struct ofc_softc *sc = ofcons_cd.cd_devs[minor(dev)];
345
346 if (!sc)
347 return;
348 if (on) {
349 if (sc->of_flags & OFPOLL)
350 untimeout(ofcpoll, sc);
351 sc->of_flags &= ~OFPOLL;
352 } else {
353 if (!(sc->of_flags & OFPOLL)) {
354 sc->of_flags |= OFPOLL;
355 timeout(ofcpoll, sc, 1);
356 }
357 }
358 }
359