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