ofcons.c revision 1.3 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