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 /* 222 * Type for the parameter of find_fb_dev() 223 */ 224 struct find_fb_dev_param 225 { 226 dev_info_t *found_dip; /* dip found for VGA console */ 227 int vga_enable; /* check PCI_BCNF_BCNTRL_VGA_ENABLE or not */ 228 }; 229 230 /* 231 * The VGA device could be under a subtractive PCI bridge on some systems. 232 * Though the PCI_BCNF_BCNTRL_VGA_ENABLE bit is not set on such subtractive 233 * PCI bridge, the subtractive PCI bridge can forward VGA access if no other 234 * agent claims the access. 235 * The vga_enable element in param acts as a flag, if not set, ignore the 236 * checking for the PCI_BCNF_BCNTRL_VGA_ENABLE bit of the PCI bridge during 237 * the search. 238 */ 239 static int 240 find_fb_dev(dev_info_t *dip, void *param) 241 { 242 struct find_fb_dev_param *p = param; 243 char *dev_type; 244 dev_info_t *pdip; 245 char *parent_type; 246 247 if (dip == ddi_root_node()) 248 return (DDI_WALK_CONTINUE); 249 250 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 251 "device_type", &dev_type) != DDI_SUCCESS) 252 return (DDI_WALK_PRUNECHILD); 253 254 if ((strcmp(dev_type, "isa") == 0) || (strcmp(dev_type, "eisa") == 0)) { 255 ddi_prop_free(dev_type); 256 return (DDI_WALK_CONTINUE); 257 } 258 259 if ((strcmp(dev_type, "pci") == 0) || 260 (strcmp(dev_type, "pciex") == 0)) { 261 ddi_acc_handle_t pci_conf; 262 uint16_t data16; 263 char *nodename; 264 265 ddi_prop_free(dev_type); 266 267 if (!p->vga_enable) 268 return (DDI_WALK_CONTINUE); 269 270 nodename = ddi_node_name(dip); 271 272 /* 273 * If the node is not a PCI-to-PCI bridge, continue traversing 274 * (it could be the root node), otherwise, check for the 275 * VGAEnable bit to be set in the Bridge Control Register. 276 */ 277 if (strcmp(nodename, "pci") == 0) { 278 if (is_pci_bridge(dip) == B_FALSE) 279 return (DDI_WALK_CONTINUE); 280 } 281 282 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 283 return (DDI_WALK_PRUNECHILD); 284 285 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 286 return (DDI_WALK_PRUNECHILD); 287 288 data16 = pci_config_get16(pci_conf, PCI_BCNF_BCNTRL); 289 pci_config_teardown(&pci_conf); 290 291 if (data16 & PCI_BCNF_BCNTRL_VGA_ENABLE) 292 return (DDI_WALK_CONTINUE); 293 294 return (DDI_WALK_PRUNECHILD); 295 } 296 297 if (strcmp(dev_type, "display") != 0) { 298 ddi_prop_free(dev_type); 299 return (DDI_WALK_CONTINUE); 300 } 301 302 ddi_prop_free(dev_type); 303 304 if ((pdip = ddi_get_parent(dip)) == NULL) 305 return (DDI_WALK_PRUNECHILD); 306 307 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 308 "device_type", &parent_type) != DDI_SUCCESS) 309 return (DDI_WALK_PRUNECHILD); 310 311 if ((strcmp(parent_type, "isa") == 0) || 312 (strcmp(parent_type, "eisa") == 0)) { 313 p->found_dip = dip; 314 ddi_prop_free(parent_type); 315 return (DDI_WALK_TERMINATE); 316 } 317 318 if ((strcmp(parent_type, "pci") == 0) || 319 (strcmp(parent_type, "pciex") == 0)) { 320 ddi_acc_handle_t pci_conf; 321 uint16_t data16; 322 323 ddi_prop_free(parent_type); 324 325 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 326 return (DDI_WALK_PRUNECHILD); 327 328 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 329 return (DDI_WALK_PRUNECHILD); 330 331 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM); 332 pci_config_teardown(&pci_conf); 333 334 if (!(data16 & PCI_COMM_IO)) 335 return (DDI_WALK_PRUNECHILD); 336 337 p->found_dip = dip; 338 return (DDI_WALK_TERMINATE); 339 } 340 341 ddi_prop_free(parent_type); 342 return (DDI_WALK_PRUNECHILD); 343 } 344 345 /* 346 * The first round search is to find: 347 * 1) a VGA device. 348 * 2) a PCI VGA compatible device whose IO space is enabled 349 * and the VGA Enable bit of any PCI-PCI bridge above it is set. 350 * If the first round search succeeds, prune the second round search. 351 * 352 * The second round seach does not check the VGA Enable bit. 353 * 354 * Return the device path as the console fb path. 355 */ 356 char * 357 plat_fbpath(void) 358 { 359 struct find_fb_dev_param param; 360 static char *fbpath = NULL; 361 static char fbpath_buf[MAXPATHLEN]; 362 363 /* first round search */ 364 param.found_dip = NULL; 365 param.vga_enable = 1; 366 ddi_walk_devs(ddi_root_node(), find_fb_dev, ¶m); 367 368 if (param.found_dip != NULL) { 369 (void) ddi_pathname(param.found_dip, fbpath_buf); 370 fbpath = fbpath_buf; 371 return (fbpath); 372 } 373 374 /* 375 * second round search, do not check the 376 * PCI_BCNF_BCNTRL_VGA_ENABLE bit 377 */ 378 param.found_dip = NULL; 379 param.vga_enable = 0; 380 ddi_walk_devs(ddi_root_node(), find_fb_dev, ¶m); 381 382 if (param.found_dip == NULL) 383 return (NULL); 384 385 (void) ddi_pathname(param.found_dip, fbpath_buf); 386 fbpath = fbpath_buf; 387 return (fbpath); 388 } 389 390 char * 391 plat_mousepath(void) 392 { 393 static char mpath[MAXPATHLEN]; 394 395 /* 396 * Hardcode to isa mouse path 397 * XXX make it settable via bootprop? 398 */ 399 if (pseudo_isa) 400 return ("/isa/i8042@1,60/mouse@1"); 401 402 if (plat_devpath("mouse8042", mpath) == NULL) 403 return (NULL); 404 405 return (mpath); 406 } 407 408 /* return path of first usb serial device */ 409 static char * 410 plat_usbser_path(void) 411 { 412 extern dev_info_t *usbser_first_device(void); 413 414 dev_info_t *us_dip; 415 static char *us_path = NULL; 416 417 if (us_path) 418 return (us_path); 419 420 us_dip = usbser_first_device(); 421 if (us_dip == NULL) 422 return (NULL); 423 424 us_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 425 (void) ddi_pathname(us_dip, us_path); 426 ndi_rele_devi(us_dip); /* held from usbser_first_device */ 427 return (us_path); 428 } 429 430 static char * 431 plat_ttypath(int inum) 432 { 433 static char *defaultpath[] = { 434 "/isa/asy@1,3f8:a", 435 "/isa/asy@1,2f8:b" 436 }; 437 static char path[MAXPATHLEN]; 438 char *bp; 439 major_t major; 440 dev_info_t *dip; 441 442 if (pseudo_isa) 443 return (defaultpath[inum]); 444 445 if ((major = ddi_name_to_major("asy")) == (major_t)-1) 446 return (NULL); 447 448 if ((dip = devnamesp[major].dn_head) == NULL) 449 return (NULL); 450 451 for (; dip != NULL; dip = ddi_get_next(dip)) { 452 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 453 return (NULL); 454 455 if (DEVI(dip)->devi_minor->ddm_name[0] == ('a' + (char)inum)) 456 break; 457 } 458 if (dip == NULL) 459 return (NULL); 460 461 (void) ddi_pathname(dip, path); 462 bp = path + strlen(path); 463 (void) snprintf(bp, 3, ":%s", DEVI(dip)->devi_minor->ddm_name); 464 465 return (path); 466 } 467 468 /* 469 * Lacking support for com2 and com3, if that matters. 470 * Another possible enhancement could be to use properties 471 * for the port mapping rather than simply hard-code them. 472 */ 473 char * 474 plat_stdinpath(void) 475 { 476 switch (console_type()) { 477 #if defined(__xpv) 478 case CONS_HYPERVISOR: 479 return ("/xpvd/xencons@0"); 480 #endif /* __xpv */ 481 case CONS_TTYA: 482 return (plat_ttypath(0)); 483 case CONS_TTYB: 484 return (plat_ttypath(1)); 485 case CONS_USBSER: 486 return (plat_usbser_path()); 487 case CONS_SCREEN: 488 default: 489 break; 490 }; 491 return (plat_kbdpath()); 492 } 493 494 char * 495 plat_stdoutpath(void) 496 { 497 switch (console_type()) { 498 #if defined(__xpv) 499 case CONS_HYPERVISOR: 500 return ("/xpvd/xencons@0"); 501 #endif /* __xpv */ 502 case CONS_TTYA: 503 return (plat_ttypath(0)); 504 case CONS_TTYB: 505 return (plat_ttypath(1)); 506 case CONS_USBSER: 507 return (plat_usbser_path()); 508 case CONS_SCREEN: 509 default: 510 break; 511 }; 512 return (plat_fbpath()); 513 } 514 515 /* 516 * If VIS_PIXEL mode will be implemented on x86, these following 517 * functions should be re-considered. Now these functions are 518 * unused on x86. 519 */ 520 void 521 plat_tem_get_inverses(int *inverse, int *inverse_screen) 522 { 523 *inverse = 0; 524 *inverse_screen = 0; 525 } 526 527 void 528 plat_tem_get_prom_font_size(int *charheight, int *windowtop) 529 { 530 *charheight = 0; 531 *windowtop = 0; 532 } 533 534 /*ARGSUSED*/ 535 void 536 plat_tem_get_prom_size(size_t *height, size_t *width) 537 { 538 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 539 } 540 541 void 542 plat_tem_hide_prom_cursor(void) 543 { 544 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 545 } 546 547 /*ARGSUSED*/ 548 void 549 plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) 550 { 551 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 552 } 553