ofw_consinit.c revision 1.3 1 /* $NetBSD: ofw_consinit.c,v 1.3 2007/11/04 16:28:28 garbled Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ofw_consinit.c,v 1.3 2007/11/04 16:28:28 garbled Exp $");
41
42 #include <sys/param.h>
43 #include <sys/buf.h>
44 #include <sys/tty.h>
45
46 #include <machine/autoconf.h>
47 #include <machine/trap.h>
48 #include <machine/bus.h>
49
50 #include <powerpc/ofw_cons.h>
51
52 #include <dev/cons.h>
53 #include <dev/ofw/openfirm.h>
54
55 #include <dev/wscons/wsksymvar.h>
56 #include <dev/wscons/wscons_callbacks.h>
57
58 #include <machine/stdarg.h>
59
60 #include "akbd.h"
61 #include "adbkbd.h"
62 #include "ofb.h"
63 #include "isa.h"
64
65 #include "zsc.h"
66 #if NZSC > 0
67 #include <machine/z8530var.h>
68 #endif
69
70 #include "adb.h"
71 #if (NADB > 0)
72 #include <macppc/dev/adbvar.h>
73 #endif
74
75 #include "ukbd.h"
76 #if (NUKBD > 0)
77 #include <dev/usb/ukbdvar.h>
78 struct usb_kbd_ihandles {
79 struct usb_kbd_ihandles *next;
80 int ihandle;
81 };
82 #endif
83
84 #include "zstty.h"
85 #if (NZSTTY > 0)
86 #include <dev/ic/z8530reg.h>
87 extern struct consdev consdev_zs;
88 #endif
89
90 #include "pckbc.h"
91 #if (NPCKBC > 0)
92 #include <dev/isa/isareg.h>
93 #include <dev/ic/i8042reg.h>
94 #include <dev/ic/pckbcvar.h>
95 #endif
96
97 extern int console_node, console_instance;
98
99 int chosen, stdin, stdout;
100 int ofkbd_ihandle;
101
102 static void cninit_kd(void);
103 static void ofwoea_bootstrap_console(void);
104 static int ofwbootcons_cngetc(dev_t);
105 static void ofwbootcons_cnputc(dev_t, int);
106
107 /*#define OFDEBUG*/
108
109 struct consdev consdev_ofwbootcons = {
110 NULL, NULL,
111 ofwbootcons_cngetc,
112 ofwbootcons_cnputc,
113 nullcnpollc,
114 NULL, NULL, NULL, NODEV, CN_INTERNAL,
115 };
116
117 #ifdef OFDEBUG
118 void ofprint(const char *, ...);
119
120 void ofprint(const char *blah, ...)
121 {
122 va_list va;
123 char buf[256];
124 int len;
125
126 va_start(va, blah);
127 len = vsnprintf(buf, sizeof(buf), blah, va);
128 OF_write(console_instance, buf, len);
129 }
130
131 #define OFPRINTF ofprint
132 #else
133 #define OFPRINTF while(0) printf
134 #endif
135
136 void
137 cninit(void)
138 {
139 char type[16];
140
141 ofwoea_bootstrap_console();
142
143 OFPRINTF("console node: %08x\n", console_node);
144
145 if (console_node == -1)
146 goto nocons;
147
148 memset(type, 0, sizeof(type));
149 if (OF_getprop(console_node, "device_type", type, sizeof(type)) == -1)
150 goto nocons;
151
152 OFPRINTF("console type: %s\n", type);
153 if (strcmp(type, "display") == 0) {
154 cninit_kd();
155 return;
156 }
157
158 if (strcmp(type, "serial") == 0) {
159 struct consdev *cp;
160 char name[32];
161
162 #ifdef PMAC_G5
163 /* The MMU hasn't been initialized yet, use failsafe for now */
164 cp = &failsafe_cons;
165 cn_tab = cp;
166 (*cp->cn_probe)(cp);
167 (*cp->cn_init)(cp);
168 aprint_verbose("Early G5 console initialized\n");
169 return;
170 #endif /* PMAC_G5 */
171
172 #if (NZSTTY > 0) && !defined(MAMBO)
173 OF_getprop(console_node, "name", name, sizeof(name));
174 if (strcmp(name, "ch-a") == 0 || strcmp(name, "ch-b") == 0) {
175 cp = &consdev_zs;
176 (*cp->cn_probe)(cp);
177 (*cp->cn_init)(cp);
178 cn_tab = cp;
179 }
180 return;
181 #endif /* NZTTY */
182
183 OF_getprop(console_node, "name", name, sizeof(name));
184 /* fallback to ofwbootcons */
185 if (strcmp(name, "serial") == 0) {
186 cp = &consdev_ofwbootcons;
187 cn_tab = cp;
188 }
189 return;
190 }
191 nocons:
192 return;
193 }
194
195
196 static void
197 cninit_kd(void)
198 {
199 int kstdin, node;
200 char name[16];
201 #if (NAKBD > 0) || (NADBKBD > 0)
202 int akbd;
203 #endif
204 #if NUKBD > 0
205 struct usb_kbd_ihandles *ukbds;
206 int ukbd;
207 #endif
208
209 /*
210 * Attach the console output now (so we can see debugging messages,
211 * if any).
212 */
213 ofb_cnattach();
214
215 /*
216 * We must determine which keyboard type we have.
217 */
218 if (OF_getprop(chosen, "stdin", &kstdin, sizeof(kstdin))
219 != sizeof(kstdin)) {
220 printf("WARNING: no `stdin' property in /chosen\n");
221 return;
222 }
223
224 node = OF_instance_to_package(kstdin);
225 memset(name, 0, sizeof(name));
226 OF_getprop(node, "name", name, sizeof(name));
227 if (strcmp(name, "keyboard") != 0) {
228 printf("WARNING: stdin is not a keyboard: %s\n", name);
229 return;
230 }
231
232 #if NAKBD > 0
233 memset(name, 0, sizeof(name));
234 OF_getprop(OF_parent(node), "name", name, sizeof(name));
235 if (strcmp(name, "adb") == 0) {
236 printf("console keyboard type: ADB\n");
237 akbd_cnattach();
238 goto kbd_found;
239 }
240 #endif
241 #if NADBKBD > 0
242 memset(name, 0, sizeof(name));
243 OF_getprop(OF_parent(node), "name", name, sizeof(name));
244 if (strcmp(name, "adb") == 0) {
245 printf("console keyboard type: ADB\n");
246 adbkbd_cnattach();
247 goto kbd_found;
248 }
249 #endif
250 #if NPCKBC > 0
251 memset(name, 0, sizeof(name));
252 OF_getprop(OF_parent(node), "name", name, sizeof(name));
253 if (strcmp(name, "keyboard") == 0) {
254 printf("console keyboard type: PC Keyboard\n");
255 pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP,
256 PCKBC_KBD_SLOT);
257 goto kbd_found;
258 }
259 #endif
260
261 /*
262 * It is not obviously an ADB/PC keyboard. Could be USB,
263 * or ADB on some firmware versions (e.g.: iBook G4)
264 * This is not enough, we have a few more problems:
265 *
266 * (1) The stupid Macintosh firmware uses a
267 * `psuedo-hid' (no typo) or `pseudo-hid',
268 * which apparently merges all keyboards
269 * input into a single input stream.
270 * Because of this, we can't actually
271 * determine which controller or keyboard
272 * is really the console keyboard!
273 *
274 * (2) Even if we could, the keyboard can be USB,
275 * and this requires a lot of the kernel to
276 * be running in order for it to work.
277 *
278 * (3) If the keyboard is behind isa, we don't have enough
279 * kernel setup to use it yet, so punt to the ofroutines.
280 *
281 * So, what we do is this:
282 *
283 * (1) First check for OpenFirmware implementation
284 * that will not let us distinguish between
285 * USB and ADB. In that situation, try attaching
286 * anything as we can, and hope things get better
287 * at autoconfiguration time.
288 *
289 * (2) Assume the keyboard is USB.
290 * Tell the ukbd driver that it is the console.
291 * At autoconfiguration time, it will attach the
292 * first USB keyboard instance as the console
293 * keyboard.
294 *
295 * (3) Until then, so that we have _something_, we
296 * use the OpenFirmware I/O facilities to read
297 * the keyboard.
298 */
299
300 /*
301 * stdin is /pseudo-hid/keyboard. There is no
302 * `adb-kbd-ihandle or `usb-kbd-ihandles methods
303 * available. Try attaching as ADB.
304 *
305 * XXX This must be called before pmap_bootstrap().
306 */
307 if (strcmp(name, "pseudo-hid") == 0) {
308 printf("console keyboard type: unknown, assuming ADB\n");
309 #if NAKBD > 0
310 akbd_cnattach();
311 #endif
312 #if NADBKBD > 0
313 adbkbd_cnattach();
314 #endif
315 goto kbd_found;
316 }
317
318 /*
319 * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and
320 * `usb-kbd-ihandles to figure out the real keyboard(s).
321 *
322 * XXX This must be called before pmap_bootstrap().
323 */
324
325 #if NUKBD > 0
326 if (OF_call_method("`usb-kbd-ihandles", stdin, 0, 1, &ukbds) >= 0 &&
327 ukbds != NULL && ukbds->ihandle != 0 &&
328 OF_instance_to_package(ukbds->ihandle) != -1) {
329 printf("usb-kbd-ihandles matches\n");
330 printf("console keyboard type: USB\n");
331 ukbd_cnattach();
332 goto kbd_found;
333 }
334 /* Try old method name. */
335 if (OF_call_method("`usb-kbd-ihandle", kstdin, 0, 1, &ukbd) >= 0 &&
336 ukbd != 0 &&
337 OF_instance_to_package(ukbd) != -1) {
338 printf("usb-kbd-ihandle matches\n");
339 printf("console keyboard type: USB\n");
340 kstdin = ukbd;
341 ukbd_cnattach();
342 goto kbd_found;
343 }
344 #endif
345
346 #if (NAKBD > 0) || (NADBKBD > 0)
347 if (OF_call_method("`adb-kbd-ihandle", kstdin, 0, 1, &akbd) >= 0 &&
348 akbd != 0 &&
349 OF_instance_to_package(akbd) != -1) {
350 printf("adb-kbd-ihandle matches\n");
351 printf("console keyboard type: ADB\n");
352 kstdin = akbd;
353 #if NAKBD > 0
354 akbd_cnattach();
355 #endif
356 #if NADBKBD > 0
357 adbkbd_cnattach();
358 #endif
359 goto kbd_found;
360 }
361 #endif
362
363 #if NUKBD > 0
364 /*
365 * XXX Old firmware does not have `usb-kbd-ihandles method. Assume
366 * XXX USB keyboard anyway.
367 */
368 printf("defaulting to USB...");
369 printf("console keyboard type: USB\n");
370 ukbd_cnattach();
371 goto kbd_found;
372 #endif
373
374 /*
375 * No keyboard is found. Just return.
376 */
377 printf("no console keyboard\n");
378 return;
379
380 kbd_found:;
381 #if NAKBD + NUKBD + NADBKBD > 0
382 /*
383 * XXX This is a little gross, but we don't get to call
384 * XXX wskbd_cnattach() twice.
385 */
386 ofkbd_ihandle = kstdin;
387 #if NWSDISPLAY > 0
388 wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
389 #endif
390 #endif
391 }
392
393 /*
394 * Bootstrap console keyboard routines, using OpenFirmware I/O.
395 */
396 int
397 ofkbd_cngetc(dev_t dev)
398 {
399 u_char c = '\0';
400 int len;
401
402 do {
403 len = OF_read(ofkbd_ihandle, &c, 1);
404 } while (len != 1);
405
406 return c;
407 }
408
409 /*
410 * Bootstrap console support functions
411 */
412
413 static int
414 ofwbootcons_cngetc(dev_t dev)
415 {
416 unsigned char ch = '\0';
417 int l;
418
419 while ((l = OF_read(stdin, &ch, 1)) != 1)
420 if (l != -2 && l != 0)
421 return -1;
422 return ch;
423 }
424
425 static void
426 ofwbootcons_cnputc(dev_t dev, int c)
427 {
428 char ch = c;
429
430 OF_write(stdout, &ch, 1);
431 }
432
433 void
434 ofwoea_consinit(void)
435 {
436 static int initted = 0;
437
438 if (initted)
439 return;
440
441 initted = 1;
442 cninit();
443 }
444
445 static void
446 ofwoea_bootstrap_console(void)
447 {
448 int node;
449
450 chosen = OF_finddevice("/chosen");
451 if (chosen == -1)
452 goto nocons;
453
454 if (OF_getprop(chosen, "stdout", &stdout,
455 sizeof(stdout)) != sizeof(stdout))
456 goto nocons;
457 if (OF_getprop(chosen, "stdin", &stdin,
458 sizeof(stdin)) != sizeof(stdin))
459 goto nocons;
460 node = OF_instance_to_package(stdout);
461 console_node = node;
462 console_instance = stdout;
463
464 return;
465 nocons:
466 panic("No /chosen could be found!\n");
467 console_node = -1;
468 return;
469 }
470