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