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