ofw_consinit.c revision 1.2 1 /* $NetBSD: ofw_consinit.c,v 1.2 2007/10/17 19:56:43 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.2 2007/10/17 19:56:43 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 #include "com.h"
98 #if (NCOM > 0)
99 #include <sys/termios.h>
100 #include <dev/ic/comreg.h>
101 #include <dev/ic/comvar.h>
102 #endif
103
104 extern int console_node, console_instance;
105 extern struct consdev consdev_ofcons;
106
107 int chosen;
108 int ofkbd_ihandle;
109
110 static void cninit_kd(void);
111 static void ofwoea_bootstrap_console(void);
112
113 /*#define OFDEBUG*/
114
115 #ifdef OFDEBUG
116 void ofprint(const char *, ...);
117
118 void ofprint(const char *blah, ...)
119 {
120 va_list va;
121 char buf[256];
122 int len;
123
124 va_start(va, blah);
125 len = vsnprintf(buf, sizeof(buf), blah, va);
126 OF_write(console_instance, buf, len);
127 }
128
129 #define OFPRINTF ofprint
130 #else
131 #define OFPRINTF while(0) printf
132 #endif
133
134 void
135 cninit(void)
136 {
137 char type[16];
138
139 ofwoea_bootstrap_console();
140
141 OFPRINTF("console node: %08x\n", console_node);
142
143 if (console_node == -1)
144 goto nocons;
145
146 memset(type, 0, sizeof(type));
147 if (OF_getprop(console_node, "device_type", type, sizeof(type)) == -1)
148 goto nocons;
149
150 OFPRINTF("console type: %s\n", type);
151 if (strcmp(type, "display") == 0) {
152 cninit_kd();
153 return;
154 }
155
156 if (strcmp(type, "serial") == 0) {
157 #if defined(PMAC_G5) || defined (MAMBO) || NZSTTY > 0 || NCOM > 0
158 struct consdev *cp;
159 #endif
160 char name[32];
161
162 #if defined(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 #elif defined(MAMBO)
170 goto fallback;
171 #else
172 OF_getprop(console_node, "name", name, sizeof(name));
173 #if NZSTTY > 0
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 #if (NCOM > 0 && NISA > 0)
183 if (strcmp(name, "serial") == 0) {
184 bus_space_tag_t tag = &genppc_isa_io_space_tag;
185 u_int32_t freq, reg[3];
186
187 if (OF_getprop(console_node, "clock-frequency", &freq,
188 sizeof(freq)) != sizeof(freq))
189 goto fallback;
190 if (OF_getprop(console_node, "reg", reg, sizeof(reg))
191 != sizeof(reg))
192 goto fallback;
193
194 /* We assume 9600. Sorry. */
195 if (comcnattach(tag, reg[1], 9600,
196 freq, COM_TYPE_NORMAL,
197 ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8)))
198 goto fallback;
199 }
200 #endif /* NCOM */
201 #endif /* MAMBO || PMACG5 */
202 #if 0
203 #if (NCOM > 0 || MAMBO)
204 fallback:
205 /* fallback to ofcons */
206 if (strcmp(name, "serial") == 0) {
207 cp = &consdev_ofcons;
208 cn_tab = cp;
209 (*cp->cn_probe)(cp);
210 (*cp->cn_init)(cp);
211 }
212 return;
213 #endif
214 #endif
215 }
216 nocons:
217 return;
218 }
219
220
221 static void
222 cninit_kd(void)
223 {
224 int stdin, node;
225 char name[16];
226 #if (NAKBD > 0) || (NADBKBD > 0)
227 int akbd;
228 #endif
229 #if NUKBD > 0
230 struct usb_kbd_ihandles *ukbds;
231 int ukbd;
232 #endif
233
234 /*
235 * Attach the console output now (so we can see debugging messages,
236 * if any).
237 */
238 ofb_cnattach();
239
240 /*
241 * We must determine which keyboard type we have.
242 */
243 if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin))
244 != sizeof(stdin)) {
245 printf("WARNING: no `stdin' property in /chosen\n");
246 return;
247 }
248
249 node = OF_instance_to_package(stdin);
250 memset(name, 0, sizeof(name));
251 OF_getprop(node, "name", name, sizeof(name));
252 if (strcmp(name, "keyboard") != 0) {
253 printf("WARNING: stdin is not a keyboard: %s\n", name);
254 return;
255 }
256
257 #if NAKBD > 0
258 memset(name, 0, sizeof(name));
259 OF_getprop(OF_parent(node), "name", name, sizeof(name));
260 if (strcmp(name, "adb") == 0) {
261 printf("console keyboard type: ADB\n");
262 akbd_cnattach();
263 goto kbd_found;
264 }
265 #endif
266 #if NADBKBD > 0
267 memset(name, 0, sizeof(name));
268 OF_getprop(OF_parent(node), "name", name, sizeof(name));
269 if (strcmp(name, "adb") == 0) {
270 printf("console keyboard type: ADB\n");
271 adbkbd_cnattach();
272 goto kbd_found;
273 }
274 #endif
275 #if NPCKBC > 0
276 memset(name, 0, sizeof(name));
277 OF_getprop(OF_parent(node), "name", name, sizeof(name));
278 if (strcmp(name, "keyboard") == 0) {
279 printf("console keyboard type: PC Keyboard\n");
280 pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP,
281 PCKBC_KBD_SLOT);
282 goto kbd_found;
283 }
284 #endif
285
286 /*
287 * It is not obviously an ADB/PC keyboard. Could be USB,
288 * or ADB on some firmware versions (e.g.: iBook G4)
289 * This is not enough, we have a few more problems:
290 *
291 * (1) The stupid Macintosh firmware uses a
292 * `psuedo-hid' (no typo) or `pseudo-hid',
293 * which apparently merges all keyboards
294 * input into a single input stream.
295 * Because of this, we can't actually
296 * determine which controller or keyboard
297 * is really the console keyboard!
298 *
299 * (2) Even if we could, the keyboard can be USB,
300 * and this requires a lot of the kernel to
301 * be running in order for it to work.
302 *
303 * (3) If the keyboard is behind isa, we don't have enough
304 * kernel setup to use it yet, so punt to the ofroutines.
305 *
306 * So, what we do is this:
307 *
308 * (1) First check for OpenFirmware implementation
309 * that will not let us distinguish between
310 * USB and ADB. In that situation, try attaching
311 * anything as we can, and hope things get better
312 * at autoconfiguration time.
313 *
314 * (2) Assume the keyboard is USB.
315 * Tell the ukbd driver that it is the console.
316 * At autoconfiguration time, it will attach the
317 * first USB keyboard instance as the console
318 * keyboard.
319 *
320 * (3) Until then, so that we have _something_, we
321 * use the OpenFirmware I/O facilities to read
322 * the keyboard.
323 */
324
325 /*
326 * stdin is /pseudo-hid/keyboard. There is no
327 * `adb-kbd-ihandle or `usb-kbd-ihandles methods
328 * available. Try attaching as ADB.
329 *
330 * XXX This must be called before pmap_bootstrap().
331 */
332 if (strcmp(name, "pseudo-hid") == 0) {
333 printf("console keyboard type: unknown, assuming ADB\n");
334 #if NAKBD > 0
335 akbd_cnattach();
336 #endif
337 #if NADBKBD > 0
338 adbkbd_cnattach();
339 #endif
340 goto kbd_found;
341 }
342
343 /*
344 * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and
345 * `usb-kbd-ihandles to figure out the real keyboard(s).
346 *
347 * XXX This must be called before pmap_bootstrap().
348 */
349
350 #if NUKBD > 0
351 if (OF_call_method("`usb-kbd-ihandles", stdin, 0, 1, &ukbds) >= 0 &&
352 ukbds != NULL && ukbds->ihandle != 0 &&
353 OF_instance_to_package(ukbds->ihandle) != -1) {
354 printf("usb-kbd-ihandles matches\n");
355 printf("console keyboard type: USB\n");
356 ukbd_cnattach();
357 goto kbd_found;
358 }
359 /* Try old method name. */
360 if (OF_call_method("`usb-kbd-ihandle", stdin, 0, 1, &ukbd) >= 0 &&
361 ukbd != 0 &&
362 OF_instance_to_package(ukbd) != -1) {
363 printf("usb-kbd-ihandle matches\n");
364 printf("console keyboard type: USB\n");
365 stdin = ukbd;
366 ukbd_cnattach();
367 goto kbd_found;
368 }
369 #endif
370
371 #if (NAKBD > 0) || (NADBKBD > 0)
372 if (OF_call_method("`adb-kbd-ihandle", stdin, 0, 1, &akbd) >= 0 &&
373 akbd != 0 &&
374 OF_instance_to_package(akbd) != -1) {
375 printf("adb-kbd-ihandle matches\n");
376 printf("console keyboard type: ADB\n");
377 stdin = akbd;
378 #if NAKBD > 0
379 akbd_cnattach();
380 #endif
381 #if NADBKBD > 0
382 adbkbd_cnattach();
383 #endif
384 goto kbd_found;
385 }
386 #endif
387
388 #if NUKBD > 0
389 /*
390 * XXX Old firmware does not have `usb-kbd-ihandles method. Assume
391 * XXX USB keyboard anyway.
392 */
393 printf("defaulting to USB...");
394 printf("console keyboard type: USB\n");
395 ukbd_cnattach();
396 goto kbd_found;
397 #endif
398
399 /*
400 * No keyboard is found. Just return.
401 */
402 printf("no console keyboard\n");
403 return;
404
405 kbd_found:;
406 #if NAKBD + NUKBD + NADBKBD > 0
407 /*
408 * XXX This is a little gross, but we don't get to call
409 * XXX wskbd_cnattach() twice.
410 */
411 ofkbd_ihandle = stdin;
412 #if NWSDISPLAY > 0
413 wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
414 #endif
415 #endif
416 }
417
418 /*
419 * Bootstrap console keyboard routines, using OpenFirmware I/O.
420 */
421 int
422 ofkbd_cngetc(dev_t dev)
423 {
424 u_char c = '\0';
425 int len;
426
427 do {
428 len = OF_read(ofkbd_ihandle, &c, 1);
429 } while (len != 1);
430
431 return c;
432 }
433
434 void
435 ofwoea_consinit(void)
436 {
437 static int initted = 0;
438
439 if (initted)
440 return;
441
442 initted = 1;
443 cninit();
444 }
445
446 static void
447 ofwoea_bootstrap_console(void)
448 {
449 int stdout, node;
450
451 chosen = OF_finddevice("/chosen");
452 if (chosen == -1)
453 goto nocons;
454
455 if (OF_getprop(chosen, "stdout", &stdout,
456 sizeof(stdout)) != sizeof(stdout))
457 goto nocons;
458 node = OF_instance_to_package(stdout);
459 console_node = node;
460 console_instance = stdout;
461
462 return;
463 nocons:
464 panic("No /chosen could be found!\n");
465 console_node = -1;
466 return;
467 }
468