1 /* $NetBSD: ofw_consinit.c,v 1.29 2026/08/31 07:41:31 macallan 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.29 2026/08/31 07:41:31 macallan Exp $"); 34 35 #include "adb.h" 36 #include "adbkbd.h" 37 #include "akbd.h" 38 #include "isa.h" 39 #include "ofb.h" 40 #include "pckbc.h" 41 #include "ukbd.h" 42 #include "wsdisplay.h" 43 #include "zsc.h" 44 #include "zstty.h" 45 46 #include "opt_pscons.h" 47 48 #include <sys/param.h> 49 #include <sys/buf.h> 50 #include <sys/tty.h> 51 52 #include <prop/proplib.h> 53 54 #include <machine/autoconf.h> 55 #include <machine/trap.h> 56 #include <sys/bus.h> 57 58 #include <powerpc/ofw_cons.h> 59 #include <powerpc/ofw_machdep.h> 60 61 #include <dev/cons.h> 62 #include <dev/ofw/openfirm.h> 63 64 #include <dev/wscons/wsksymvar.h> 65 #include <dev/wscons/wscons_callbacks.h> 66 67 #if NZSC > 0 68 #include <machine/z8530var.h> 69 #endif 70 71 #if (NADB > 0) 72 #include <macppc/dev/adbvar.h> 73 #endif 74 75 #if (NUKBD > 0) 76 #include <dev/usb/ukbdvar.h> 77 struct usb_kbd_ihandles { 78 struct usb_kbd_ihandles *next; 79 int ihandle; 80 }; 81 #endif 82 83 #if (NZSTTY > 0) 84 #include <dev/ic/z8530reg.h> 85 extern struct consdev consdev_zs; 86 #endif 87 88 #ifdef PSC_CONSOLE 89 #include <powerpc/mpc5200/pscvar.h> 90 #endif 91 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; 99 100 int ofkbd_ihandle = -1; 101 102 static void ofwoea_cnprobe_keyboard(void); 103 104 /*#define OFDEBUG*/ 105 106 #ifdef OFDEBUG 107 108 #define OFPRINTF ofprint 109 #else 110 #define OFPRINTF while(0) printf 111 #endif 112 113 bool ofwoea_use_serial_console; 114 static struct consdev *selected_serial_consdev; 115 116 static int (*selected_keyboard)(void); 117 118 /* XXX Gross. */ 119 #if NPCKBC > 0 120 static int 121 ofwoea_pckbd_cnattach(void) 122 { 123 return pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP, 124 PCKBC_KBD_SLOT, 0); 125 } 126 #endif 127 128 void 129 ofwoea_cnprobe(void) 130 { 131 char name[32]; 132 133 OFPRINTF("console node: %08x\n", console_node); 134 135 if (console_node == -1) 136 return; 137 138 memset(name, 0, sizeof(name)); 139 if (OF_getprop(console_node, "device_type", name, sizeof(name)) == -1) 140 return; 141 142 OFPRINTF("console type: %s\n", name); 143 144 if (strcmp(name, "serial") == 0) { 145 ofwoea_use_serial_console = true; 146 #ifdef PMAC_G5 147 /* The MMU hasn't been initialized yet, use failsafe for now */ 148 extern struct consdev failsafe_cons; 149 selected_serial_consdev = &failsafe_cons; 150 aprint_verbose("Early G5 console selected " 151 "(keeping OF console for now)\n"); 152 return; 153 #endif /* PMAC_G5 */ 154 155 #ifdef PSC_CONSOLE 156 /* 157 * On MPC5200 boards the OpenFirmware serial console is always 158 * a PSC in UART mode, so use it. The exact "compatible" 159 * string varies. 160 */ 161 selected_serial_consdev = &psccons; 162 return; 163 #endif /* PSC_CONSOLE */ 164 165 #if (NZSTTY > 0) && !defined(MAMBO) 166 OF_getprop(console_node, "name", name, sizeof(name)); 167 if (strcmp(name, "ch-a") == 0 || strcmp(name, "ch-b") == 0) { 168 selected_serial_consdev = &consdev_zs; 169 } 170 return; 171 #endif /* NZTTY */ 172 173 /* fallback to OFW boot console (already set) */ 174 return; 175 } 176 177 /* 178 * We're going to use a display console. Probe for the keyboard 179 * we'll use. 180 */ 181 ofwoea_cnprobe_keyboard(); 182 } 183 184 /* 185 * XXX This routine is a complete disaster, filled with platform-specific 186 * XXX stuff. Fix, plz. 187 */ 188 static void 189 ofwoea_cnprobe_keyboard(void) 190 { 191 extern int ofw_stdin; 192 193 int node, kstdin = ofw_stdin; 194 char name[16]; 195 #if (NAKBD > 0) || (NADBKBD > 0) 196 int akbd; 197 #endif 198 #if NUKBD > 0 199 struct usb_kbd_ihandles *ukbds; 200 int ukbd; 201 #endif 202 203 /* 204 * We must determine which keyboard type we have. 205 */ 206 node = OF_instance_to_package(kstdin); 207 memset(name, 0, sizeof(name)); 208 OF_getprop(node, "name", name, sizeof(name)); 209 if (strcmp(name, "keyboard") != 0) { 210 ofprint("WARNING: stdin is not a keyboard: %s\n", name); 211 return; 212 } 213 214 memset(name, 0, sizeof(name)); 215 OF_getprop(OF_parent(node), "name", name, sizeof(name)); 216 #if NAKBD > 0 217 if (strcmp(name, "adb") == 0) { 218 ofprint("console keyboard type: ADB\n"); 219 selected_keyboard = akbd_cnattach; 220 goto kbd_found; 221 } 222 #endif 223 #if NADBKBD > 0 224 if (strcmp(name, "adb") == 0) { 225 ofprint("console keyboard type: ADB\n"); 226 selected_keyboard = adbkbd_cnattach; 227 goto kbd_found; 228 } 229 #endif 230 #if NPCKBC > 0 231 if ((strcmp(name, "isa") == 0) || strcmp(name, "8042") == 0) { 232 ofprint("console keyboard type: PC Keyboard\n"); 233 selected_keyboard = ofwoea_pckbd_cnattach; 234 goto kbd_found; 235 } 236 #endif 237 238 /* 239 * It is not obviously an ADB/PC keyboard. Could be USB, 240 * or ADB on some firmware versions (e.g.: iBook G4) 241 * This is not enough, we have a few more problems: 242 * 243 * (1) The stupid Macintosh firmware uses a 244 * `psuedo-hid' (no typo) or `pseudo-hid', 245 * which apparently merges all keyboards 246 * input into a single input stream. 247 * Because of this, we can't actually 248 * determine which controller or keyboard 249 * is really the console keyboard! 250 * 251 * (2) Even if we could, the keyboard can be USB, 252 * and this requires a lot of the kernel to 253 * be running in order for it to work. 254 * 255 * (3) If the keyboard is behind isa, we don't have enough 256 * kernel setup to use it yet, so punt to the ofroutines. 257 * 258 * So, what we do is this: 259 * 260 * (1) First check for OpenFirmware implementation 261 * that will not let us distinguish between 262 * USB and ADB. In that situation, try attaching 263 * anything as we can, and hope things get better 264 * at autoconfiguration time. 265 * 266 * (2) Assume the keyboard is USB. 267 * Tell the ukbd driver that it is the console. 268 * At autoconfiguration time, it will attach the 269 * first USB keyboard instance as the console 270 * keyboard. 271 * 272 * (3) Until then, so that we have _something_, we 273 * use the OpenFirmware I/O facilities to read 274 * the keyboard. 275 */ 276 277 /* 278 * stdin is /pseudo-hid/keyboard. There is no 279 * `adb-kbd-ihandle or `usb-kbd-ihandles methods 280 * available. Try attaching as ADB. 281 * But only if ADB support is actually present. 282 * 283 * XXX This must be called before pmap_bootstrap(). 284 */ 285 if (strcmp(name, "pseudo-hid") == 0) { 286 int adb_node; 287 288 adb_node = OF_finddevice("/pci/mac-io/via-pmu/adb"); 289 if (adb_node > 0) { 290 ofprint("ADB support found\n"); 291 #if NAKBD > 0 292 selected_keyboard = akbd_cnattach; 293 #endif 294 #if NADBKBD > 0 295 selected_keyboard = adbkbd_cnattach; 296 #endif 297 } else { 298 /* must be USB */ 299 ofprint("No ADB support present, assuming USB " 300 "keyboard\n"); 301 #if NUKBD > 0 302 selected_keyboard = ukbd_cnattach; 303 #endif 304 } 305 goto kbd_found; 306 } 307 308 /* 309 * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and 310 * `usb-kbd-ihandles to figure out the real keyboard(s). 311 * 312 * XXX This must be called before pmap_bootstrap(). 313 */ 314 315 #if NUKBD > 0 316 if (OF_call_method("`usb-kbd-ihandles", kstdin, 0, 1, &ukbds) >= 0 && 317 ukbds != NULL && ukbds->ihandle != 0 && 318 OF_instance_to_package(ukbds->ihandle) != -1) { 319 ofprint("usb-kbd-ihandles matches\n"); 320 ofprint("console keyboard type: USB\n"); 321 selected_keyboard = ukbd_cnattach; 322 goto kbd_found; 323 } 324 /* Try old method name. */ 325 if (OF_call_method("`usb-kbd-ihandle", kstdin, 0, 1, &ukbd) >= 0 && 326 ukbd != 0 && 327 OF_instance_to_package(ukbd) != -1) { 328 ofprint("usb-kbd-ihandle matches\n"); 329 ofprint("console keyboard type: USB\n"); 330 kstdin = ukbd; 331 selected_keyboard = ukbd_cnattach; 332 goto kbd_found; 333 } 334 #endif 335 336 #if (NAKBD > 0) || (NADBKBD > 0) 337 if (OF_call_method("`adb-kbd-ihandle", kstdin, 0, 1, &akbd) >= 0 && 338 akbd != 0 && 339 OF_instance_to_package(akbd) != -1) { 340 ofprint("adb-kbd-ihandle matches\n"); 341 ofprint("console keyboard type: ADB\n"); 342 kstdin = akbd; 343 #if NAKBD > 0 344 selected_keyboard = akbd_cnattach; 345 #endif 346 #if NADBKBD > 0 347 selected_keyboard = adbkbd_cnattach; 348 #endif 349 goto kbd_found; 350 } 351 #endif 352 353 #if NUKBD > 0 354 /* 355 * XXX Old firmware does not have `usb-kbd-ihandles method. Assume 356 * XXX USB keyboard anyway. 357 */ 358 ofprint("defaulting to USB..."); 359 ofprint("console keyboard type: USB\n"); 360 selected_keyboard = ukbd_cnattach; 361 goto kbd_found; 362 #endif 363 364 /* 365 * No keyboard is found. Just return. 366 */ 367 ofprint("no console keyboard\n"); 368 return; 369 370 kbd_found: 371 ofkbd_ihandle = kstdin; 372 } 373 374 /* 375 * Bootstrap console keyboard routines, using OpenFirmware I/O. 376 */ 377 int 378 ofkbd_cngetc(dev_t dev) 379 { 380 u_char c = '\0'; 381 int len; 382 383 KASSERT(ofkbd_ihandle != -1); 384 385 do { 386 len = OF_read(ofkbd_ihandle, &c, 1); 387 } while (len != 1); 388 389 return c; 390 } 391 392 void 393 cninit(void) 394 { 395 if (ofwoea_use_serial_console) { 396 if (selected_serial_consdev != NULL) { 397 cn_tab = selected_serial_consdev; 398 (*cn_tab->cn_probe)(cn_tab); 399 (*cn_tab->cn_init)(cn_tab); 400 } 401 return; 402 } 403 404 #if NWSDISPLAY > 0 405 rascons_cnattach(); 406 #endif 407 if (selected_keyboard != NULL) { 408 int res = (*selected_keyboard)(); 409 OFPRINTF("keyboard %d\n", res); 410 #if NWSDISPLAY > 0 411 /* 412 * XXX This is a little gross, but we don't get to call 413 * XXX wskbd_cnattach() twice. 414 */ 415 wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL); 416 #endif 417 } 418 } 419 420 void 421 ofwoea_consinit(void) 422 { 423 static int initted = 0; 424 425 if (initted) 426 return; 427 428 initted = 1; 429 cninit(); 430 } 431