ofw_consinit.c revision 1.4.4.2 1 /* $NetBSD: ofw_consinit.c,v 1.4.4.2 2007/11/06 23:20:45 matt 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.4.4.2 2007/11/06 23:20:45 matt 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 #if NOFB > 0
214 ofb_cnattach();
215 #endif
216
217 /*
218 * We must determine which keyboard type we have.
219 */
220 if (OF_getprop(chosen, "stdin", &kstdin, sizeof(kstdin))
221 != sizeof(kstdin)) {
222 printf("WARNING: no `stdin' property in /chosen\n");
223 return;
224 }
225
226 node = OF_instance_to_package(kstdin);
227 memset(name, 0, sizeof(name));
228 OF_getprop(node, "name", name, sizeof(name));
229 if (strcmp(name, "keyboard") != 0) {
230 printf("WARNING: stdin is not a keyboard: %s\n", name);
231 return;
232 }
233
234 #if NAKBD > 0
235 memset(name, 0, sizeof(name));
236 OF_getprop(OF_parent(node), "name", name, sizeof(name));
237 if (strcmp(name, "adb") == 0) {
238 printf("console keyboard type: ADB\n");
239 akbd_cnattach();
240 goto kbd_found;
241 }
242 #endif
243 #if NADBKBD > 0
244 memset(name, 0, sizeof(name));
245 OF_getprop(OF_parent(node), "name", name, sizeof(name));
246 if (strcmp(name, "adb") == 0) {
247 printf("console keyboard type: ADB\n");
248 adbkbd_cnattach();
249 goto kbd_found;
250 }
251 #endif
252 #if NPCKBC > 0
253 memset(name, 0, sizeof(name));
254 OF_getprop(OF_parent(node), "name", name, sizeof(name));
255 if (strcmp(name, "keyboard") == 0) {
256 printf("console keyboard type: PC Keyboard\n");
257 pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP,
258 PCKBC_KBD_SLOT);
259 goto kbd_found;
260 }
261 #endif
262
263 /*
264 * It is not obviously an ADB/PC keyboard. Could be USB,
265 * or ADB on some firmware versions (e.g.: iBook G4)
266 * This is not enough, we have a few more problems:
267 *
268 * (1) The stupid Macintosh firmware uses a
269 * `psuedo-hid' (no typo) or `pseudo-hid',
270 * which apparently merges all keyboards
271 * input into a single input stream.
272 * Because of this, we can't actually
273 * determine which controller or keyboard
274 * is really the console keyboard!
275 *
276 * (2) Even if we could, the keyboard can be USB,
277 * and this requires a lot of the kernel to
278 * be running in order for it to work.
279 *
280 * (3) If the keyboard is behind isa, we don't have enough
281 * kernel setup to use it yet, so punt to the ofroutines.
282 *
283 * So, what we do is this:
284 *
285 * (1) First check for OpenFirmware implementation
286 * that will not let us distinguish between
287 * USB and ADB. In that situation, try attaching
288 * anything as we can, and hope things get better
289 * at autoconfiguration time.
290 *
291 * (2) Assume the keyboard is USB.
292 * Tell the ukbd driver that it is the console.
293 * At autoconfiguration time, it will attach the
294 * first USB keyboard instance as the console
295 * keyboard.
296 *
297 * (3) Until then, so that we have _something_, we
298 * use the OpenFirmware I/O facilities to read
299 * the keyboard.
300 */
301
302 /*
303 * stdin is /pseudo-hid/keyboard. There is no
304 * `adb-kbd-ihandle or `usb-kbd-ihandles methods
305 * available. Try attaching as ADB.
306 *
307 * XXX This must be called before pmap_bootstrap().
308 */
309 if (strcmp(name, "pseudo-hid") == 0) {
310 printf("console keyboard type: unknown, assuming ADB\n");
311 #if NAKBD > 0
312 akbd_cnattach();
313 #endif
314 #if NADBKBD > 0
315 adbkbd_cnattach();
316 #endif
317 goto kbd_found;
318 }
319
320 /*
321 * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and
322 * `usb-kbd-ihandles to figure out the real keyboard(s).
323 *
324 * XXX This must be called before pmap_bootstrap().
325 */
326
327 #if NUKBD > 0
328 if (OF_call_method("`usb-kbd-ihandles", stdin, 0, 1, &ukbds) >= 0 &&
329 ukbds != NULL && ukbds->ihandle != 0 &&
330 OF_instance_to_package(ukbds->ihandle) != -1) {
331 printf("usb-kbd-ihandles matches\n");
332 printf("console keyboard type: USB\n");
333 ukbd_cnattach();
334 goto kbd_found;
335 }
336 /* Try old method name. */
337 if (OF_call_method("`usb-kbd-ihandle", kstdin, 0, 1, &ukbd) >= 0 &&
338 ukbd != 0 &&
339 OF_instance_to_package(ukbd) != -1) {
340 printf("usb-kbd-ihandle matches\n");
341 printf("console keyboard type: USB\n");
342 kstdin = ukbd;
343 ukbd_cnattach();
344 goto kbd_found;
345 }
346 #endif
347
348 #if (NAKBD > 0) || (NADBKBD > 0)
349 if (OF_call_method("`adb-kbd-ihandle", kstdin, 0, 1, &akbd) >= 0 &&
350 akbd != 0 &&
351 OF_instance_to_package(akbd) != -1) {
352 printf("adb-kbd-ihandle matches\n");
353 printf("console keyboard type: ADB\n");
354 kstdin = akbd;
355 #if NAKBD > 0
356 akbd_cnattach();
357 #endif
358 #if NADBKBD > 0
359 adbkbd_cnattach();
360 #endif
361 goto kbd_found;
362 }
363 #endif
364
365 #if NUKBD > 0
366 /*
367 * XXX Old firmware does not have `usb-kbd-ihandles method. Assume
368 * XXX USB keyboard anyway.
369 */
370 printf("defaulting to USB...");
371 printf("console keyboard type: USB\n");
372 ukbd_cnattach();
373 goto kbd_found;
374 #endif
375
376 /*
377 * No keyboard is found. Just return.
378 */
379 printf("no console keyboard\n");
380 return;
381
382 kbd_found:;
383 #if NAKBD + NUKBD + NADBKBD > 0
384 /*
385 * XXX This is a little gross, but we don't get to call
386 * XXX wskbd_cnattach() twice.
387 */
388 ofkbd_ihandle = kstdin;
389 #if NWSDISPLAY > 0
390 wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
391 #endif
392 #endif
393 }
394
395 /*
396 * Bootstrap console keyboard routines, using OpenFirmware I/O.
397 */
398 int
399 ofkbd_cngetc(dev_t dev)
400 {
401 u_char c = '\0';
402 int len;
403
404 do {
405 len = OF_read(ofkbd_ihandle, &c, 1);
406 } while (len != 1);
407
408 return c;
409 }
410
411 /*
412 * Bootstrap console support functions
413 */
414
415 static int
416 ofwbootcons_cngetc(dev_t dev)
417 {
418 unsigned char ch = '\0';
419 int l;
420
421 while ((l = OF_read(stdin, &ch, 1)) != 1)
422 if (l != -2 && l != 0)
423 return -1;
424 return ch;
425 }
426
427 static void
428 ofwbootcons_cnputc(dev_t dev, int c)
429 {
430 char ch = c;
431
432 OF_write(stdout, &ch, 1);
433 }
434
435 void
436 ofwoea_consinit(void)
437 {
438 static int initted = 0;
439
440 if (initted)
441 return;
442
443 initted = 1;
444 cninit();
445 }
446
447 static void
448 ofwoea_bootstrap_console(void)
449 {
450 int node;
451
452 chosen = OF_finddevice("/chosen");
453 if (chosen == -1)
454 goto nocons;
455
456 if (OF_getprop(chosen, "stdout", &stdout,
457 sizeof(stdout)) != sizeof(stdout))
458 goto nocons;
459 if (OF_getprop(chosen, "stdin", &stdin,
460 sizeof(stdin)) != sizeof(stdin))
461 goto nocons;
462 node = OF_instance_to_package(stdout);
463 console_node = node;
464 console_instance = stdout;
465
466 return;
467 nocons:
468 panic("No /chosen could be found!\n");
469 console_node = -1;
470 return;
471 }
472