1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * isa-specific console configuration routines 29 */ 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/cmn_err.h> 34 #include <sys/systm.h> 35 #include <sys/conf.h> 36 #include <sys/debug.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 #include <sys/sunndi.h> 40 #include <sys/esunddi.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/promif.h> 43 #include <sys/modctl.h> 44 #include <sys/termios.h> 45 #include <sys/pci.h> 46 #if defined(__xpv) 47 #include <sys/hypervisor.h> 48 #include <sys/boot_console.h> 49 #endif 50 51 extern int pseudo_isa; 52 53 int 54 plat_use_polled_debug() { 55 return (0); 56 } 57 58 int 59 plat_support_serial_kbd_and_ms() { 60 return (0); 61 } 62 63 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0])) 64 65 #define CONS_INVALID -1 66 #define CONS_SCREEN 0 67 #define CONS_TTYA 1 68 #define CONS_TTYB 2 69 #define CONS_USBSER 3 70 #define CONS_HYPERVISOR 4 71 72 char *plat_fbpath(void); 73 74 static int 75 console_type() 76 { 77 static int boot_console = CONS_INVALID; 78 79 char *cons; 80 dev_info_t *root; 81 82 if (boot_console != CONS_INVALID) 83 return (boot_console); 84 85 #if defined(__xpv) 86 if (!DOMAIN_IS_INITDOMAIN(xen_info) || bcons_hypervisor_redirect()) { 87 boot_console = CONS_HYPERVISOR; 88 return (boot_console); 89 } 90 #endif /* __xpv */ 91 92 /* 93 * console is defined by "console" property, with 94 * fallback on the old "input-device" property. 95 * If "input-device" is not defined either, also check "output-device". 96 */ 97 boot_console = CONS_SCREEN; /* default is screen/kb */ 98 root = ddi_root_node(); 99 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 100 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) || 101 (ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 102 DDI_PROP_DONTPASS, "input-device", &cons) == DDI_SUCCESS) || 103 (ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 104 DDI_PROP_DONTPASS, "output-device", &cons) == DDI_SUCCESS)) { 105 if (strcmp(cons, "ttya") == 0) { 106 boot_console = CONS_TTYA; 107 } else if (strcmp(cons, "ttyb") == 0) { 108 boot_console = CONS_TTYB; 109 } else if (strcmp(cons, "usb-serial") == 0) { 110 (void) i_ddi_attach_hw_nodes("ehci"); 111 (void) i_ddi_attach_hw_nodes("uhci"); 112 (void) i_ddi_attach_hw_nodes("ohci"); 113 /* 114 * USB device enumerate asynchronously. 115 * Wait 2 seconds for USB serial devices to attach. 116 */ 117 delay(drv_usectohz(2000000)); 118 boot_console = CONS_USBSER; 119 #if defined(__xpv) 120 } else if (strcmp(cons, "hypervisor") == 0) { 121 boot_console = CONS_HYPERVISOR; 122 #endif /* __xpv */ 123 } 124 ddi_prop_free(cons); 125 } 126 127 /* 128 * If the console is configured to use a framebuffer but none 129 * could be found, fallback to "ttya" since it's likely to exist 130 * and it matches longstanding behavior on SPARC. 131 */ 132 if (boot_console == CONS_SCREEN && plat_fbpath() == NULL) 133 boot_console = CONS_TTYA; 134 135 return (boot_console); 136 } 137 138 int 139 plat_stdin_is_keyboard(void) 140 { 141 return (console_type() == CONS_SCREEN); 142 } 143 144 int 145 plat_stdout_is_framebuffer(void) 146 { 147 return (console_type() == CONS_SCREEN); 148 } 149 150 static char * 151 plat_devpath(char *name, char *path) 152 { 153 major_t major; 154 dev_info_t *dip, *pdip; 155 156 if ((major = ddi_name_to_major(name)) == (major_t)-1) 157 return (NULL); 158 159 if ((dip = devnamesp[major].dn_head) == NULL) 160 return (NULL); 161 162 pdip = ddi_get_parent(dip); 163 if (i_ddi_attach_node_hierarchy(pdip) != DDI_SUCCESS) 164 return (NULL); 165 if (ddi_initchild(pdip, dip) != DDI_SUCCESS) 166 return (NULL); 167 168 (void) ddi_pathname(dip, path); 169 170 return (path); 171 } 172 173 /* 174 * Return generic path to keyboard device from the alias. 175 */ 176 char * 177 plat_kbdpath(void) 178 { 179 static char kbpath[MAXPATHLEN]; 180 181 /* 182 * Hardcode to isa keyboard path 183 * XXX make it settable via bootprop? 184 */ 185 if (pseudo_isa) 186 return ("/isa/i8042@1,60/keyboard@0"); 187 188 if (plat_devpath("kb8042", kbpath) == NULL) 189 return (NULL); 190 191 return (kbpath); 192 } 193 194 /* 195 * NOTE: this function is duplicated here and in gfx_private/vgatext while 196 * we work on a set of commitable interfaces to sunpci.c. 197 * 198 * Use the class code to determine if the device is a PCI-to-PCI bridge. 199 * Returns: B_TRUE if the device is a bridge. 200 * B_FALSE if the device is not a bridge or the property cannot be 201 * retrieved. 202 */ 203 static boolean_t 204 is_pci_bridge(dev_info_t *dip) 205 { 206 uint32_t class_code; 207 208 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 209 DDI_PROP_DONTPASS, "class-code", 0xffffffff); 210 211 if (class_code == 0xffffffff || class_code == DDI_PROP_NOT_FOUND) 212 return (B_FALSE); 213 214 class_code &= 0x00ffff00; 215 if (class_code == ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8))) 216 return (B_TRUE); 217 218 return (B_FALSE); 219 } 220 221 static int 222 find_fb_dev(dev_info_t *dip, void *found_dip) 223 { 224 char *dev_type; 225 dev_info_t *pdip; 226 char *parent_type; 227 228 if (dip == ddi_root_node()) 229 return (DDI_WALK_CONTINUE); 230 231 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 232 "device_type", &dev_type) != DDI_SUCCESS) 233 return (DDI_WALK_PRUNECHILD); 234 235 if ((strcmp(dev_type, "isa") == 0) || (strcmp(dev_type, "eisa") == 0)) { 236 ddi_prop_free(dev_type); 237 return (DDI_WALK_CONTINUE); 238 } 239 240 if ((strcmp(dev_type, "pci") == 0) || 241 (strcmp(dev_type, "pciex") == 0)) { 242 ddi_acc_handle_t pci_conf; 243 uint16_t data16; 244 char *nodename; 245 246 ddi_prop_free(dev_type); 247 248 nodename = ddi_node_name(dip); 249 250 /* 251 * If the node is not a PCI-to-PCI bridge, continue traversing 252 * (it could be the root node), otherwise, check for the 253 * VGAEnable bit to be set in the Bridge Control Register. 254 */ 255 if (strcmp(nodename, "pci") == 0) { 256 if (is_pci_bridge(dip) == B_FALSE) 257 return (DDI_WALK_CONTINUE); 258 } 259 260 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 261 return (DDI_WALK_PRUNECHILD); 262 263 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 264 return (DDI_WALK_PRUNECHILD); 265 266 data16 = pci_config_get16(pci_conf, PCI_BCNF_BCNTRL); 267 pci_config_teardown(&pci_conf); 268 269 if (data16 & PCI_BCNF_BCNTRL_VGA_ENABLE) 270 return (DDI_WALK_CONTINUE); 271 272 return (DDI_WALK_PRUNECHILD); 273 } 274 275 if (strcmp(dev_type, "display") != 0) { 276 ddi_prop_free(dev_type); 277 return (DDI_WALK_CONTINUE); 278 } 279 280 ddi_prop_free(dev_type); 281 282 if ((pdip = ddi_get_parent(dip)) == NULL) 283 return (DDI_WALK_PRUNECHILD); 284 285 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 286 "device_type", &parent_type) != DDI_SUCCESS) 287 return (DDI_WALK_PRUNECHILD); 288 289 if ((strcmp(parent_type, "isa") == 0) || 290 (strcmp(parent_type, "eisa") == 0)) { 291 *(dev_info_t **)found_dip = dip; 292 ddi_prop_free(parent_type); 293 return (DDI_WALK_TERMINATE); 294 } 295 296 if ((strcmp(parent_type, "pci") == 0) || 297 (strcmp(parent_type, "pciex") == 0)) { 298 ddi_acc_handle_t pci_conf; 299 uint16_t data16; 300 301 ddi_prop_free(parent_type); 302 303 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 304 return (DDI_WALK_PRUNECHILD); 305 306 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 307 return (DDI_WALK_PRUNECHILD); 308 309 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM); 310 pci_config_teardown(&pci_conf); 311 312 if (!(data16 & PCI_COMM_IO)) 313 return (DDI_WALK_PRUNECHILD); 314 315 *(dev_info_t **)found_dip = dip; 316 return (DDI_WALK_TERMINATE); 317 } 318 319 ddi_prop_free(parent_type); 320 return (DDI_WALK_PRUNECHILD); 321 } 322 323 /* 324 * Conduct a width-first traverse searching for a display device which 325 * has either: 326 * 1) a VGA device. 327 * 2) a PCI VGA compatible device whose IO space is enabled 328 * and the VGA Enable bit of any PCI-PCI bridge above it is set. 329 * 330 * Return the device path as the console fb path. 331 */ 332 char * 333 plat_fbpath(void) 334 { 335 dev_info_t *fb_dip = NULL; 336 static char *fbpath = NULL; 337 static char fbpath_buf[MAXPATHLEN]; 338 339 ddi_walk_devs(ddi_root_node(), find_fb_dev, &fb_dip); 340 341 if (fb_dip == NULL) 342 return (NULL); 343 344 (void) ddi_pathname(fb_dip, fbpath_buf); 345 fbpath = fbpath_buf; 346 347 return (fbpath); 348 } 349 350 char * 351 plat_mousepath(void) 352 { 353 static char mpath[MAXPATHLEN]; 354 355 /* 356 * Hardcode to isa mouse path 357 * XXX make it settable via bootprop? 358 */ 359 if (pseudo_isa) 360 return ("/isa/i8042@1,60/mouse@1"); 361 362 if (plat_devpath("mouse8042", mpath) == NULL) 363 return (NULL); 364 365 return (mpath); 366 } 367 368 /* return path of first usb serial device */ 369 static char * 370 plat_usbser_path(void) 371 { 372 extern dev_info_t *usbser_first_device(void); 373 374 dev_info_t *us_dip; 375 static char *us_path = NULL; 376 377 if (us_path) 378 return (us_path); 379 380 us_dip = usbser_first_device(); 381 if (us_dip == NULL) 382 return (NULL); 383 384 us_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 385 (void) ddi_pathname(us_dip, us_path); 386 ndi_rele_devi(us_dip); /* held from usbser_first_device */ 387 return (us_path); 388 } 389 390 static char * 391 plat_ttypath(int inum) 392 { 393 static char *defaultpath[] = { 394 "/isa/asy@1,3f8:a", 395 "/isa/asy@1,2f8:b" 396 }; 397 static char path[MAXPATHLEN]; 398 char *bp; 399 major_t major; 400 dev_info_t *dip; 401 402 if (pseudo_isa) 403 return (defaultpath[inum]); 404 405 if ((major = ddi_name_to_major("asy")) == (major_t)-1) 406 return (NULL); 407 408 if ((dip = devnamesp[major].dn_head) == NULL) 409 return (NULL); 410 411 for (; dip != NULL; dip = ddi_get_next(dip)) { 412 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 413 return (NULL); 414 415 if (DEVI(dip)->devi_minor->ddm_name[0] == ('a' + (char)inum)) 416 break; 417 } 418 if (dip == NULL) 419 return (NULL); 420 421 (void) ddi_pathname(dip, path); 422 bp = path + strlen(path); 423 (void) snprintf(bp, 3, ":%s", DEVI(dip)->devi_minor->ddm_name); 424 425 return (path); 426 } 427 428 /* 429 * Lacking support for com2 and com3, if that matters. 430 * Another possible enhancement could be to use properties 431 * for the port mapping rather than simply hard-code them. 432 */ 433 char * 434 plat_stdinpath(void) 435 { 436 switch (console_type()) { 437 #if defined(__xpv) 438 case CONS_HYPERVISOR: 439 return ("/xpvd/xencons@0"); 440 #endif /* __xpv */ 441 case CONS_TTYA: 442 return (plat_ttypath(0)); 443 case CONS_TTYB: 444 return (plat_ttypath(1)); 445 case CONS_USBSER: 446 return (plat_usbser_path()); 447 case CONS_SCREEN: 448 default: 449 break; 450 }; 451 return (plat_kbdpath()); 452 } 453 454 char * 455 plat_stdoutpath(void) 456 { 457 switch (console_type()) { 458 #if defined(__xpv) 459 case CONS_HYPERVISOR: 460 return ("/xpvd/xencons@0"); 461 #endif /* __xpv */ 462 case CONS_TTYA: 463 return (plat_ttypath(0)); 464 case CONS_TTYB: 465 return (plat_ttypath(1)); 466 case CONS_USBSER: 467 return (plat_usbser_path()); 468 case CONS_SCREEN: 469 default: 470 break; 471 }; 472 return (plat_fbpath()); 473 } 474 475 /* 476 * If VIS_PIXEL mode will be implemented on x86, these following 477 * functions should be re-considered. Now these functions are 478 * unused on x86. 479 */ 480 void 481 plat_tem_get_inverses(int *inverse, int *inverse_screen) 482 { 483 *inverse = 0; 484 *inverse_screen = 0; 485 } 486 487 void 488 plat_tem_get_prom_font_size(int *charheight, int *windowtop) 489 { 490 *charheight = 0; 491 *windowtop = 0; 492 } 493 494 /*ARGSUSED*/ 495 void 496 plat_tem_get_prom_size(size_t *height, size_t *width) 497 { 498 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 499 } 500 501 void 502 plat_tem_hide_prom_cursor(void) 503 { 504 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 505 } 506 507 /*ARGSUSED*/ 508 void 509 plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) 510 { 511 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 512 } 513