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