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 2009 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 static int 195 find_fb_dev(dev_info_t *dip, void *found_dip) 196 { 197 char *dev_type; 198 dev_info_t *pdip; 199 char *parent_type; 200 201 if (dip == ddi_root_node()) 202 return (DDI_WALK_CONTINUE); 203 204 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 205 "device_type", &dev_type) != DDI_SUCCESS) 206 return (DDI_WALK_PRUNECHILD); 207 208 if ((strcmp(dev_type, "isa") == 0) || (strcmp(dev_type, "eisa") == 0)) { 209 ddi_prop_free(dev_type); 210 return (DDI_WALK_CONTINUE); 211 } 212 213 if ((strcmp(dev_type, "pci") == 0) || 214 (strcmp(dev_type, "pciex") == 0)) { 215 ddi_acc_handle_t pci_conf; 216 uint16_t data16; 217 char *nodename; 218 219 ddi_prop_free(dev_type); 220 221 nodename = ddi_node_name(dip); 222 223 if (strcmp(nodename, "pci") == 0) { 224 /* pci root dip */ 225 return (DDI_WALK_CONTINUE); 226 } 227 228 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 229 return (DDI_WALK_PRUNECHILD); 230 231 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 232 return (DDI_WALK_PRUNECHILD); 233 234 data16 = pci_config_get16(pci_conf, PCI_BCNF_BCNTRL); 235 pci_config_teardown(&pci_conf); 236 237 if (data16 & PCI_BCNF_BCNTRL_VGA_ENABLE) 238 return (DDI_WALK_CONTINUE); 239 240 return (DDI_WALK_PRUNECHILD); 241 } 242 243 if (strcmp(dev_type, "display") != 0) { 244 ddi_prop_free(dev_type); 245 return (DDI_WALK_CONTINUE); 246 } 247 248 ddi_prop_free(dev_type); 249 250 if ((pdip = ddi_get_parent(dip)) == NULL) 251 return (DDI_WALK_PRUNECHILD); 252 253 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 254 "device_type", &parent_type) != DDI_SUCCESS) 255 return (DDI_WALK_PRUNECHILD); 256 257 if ((strcmp(parent_type, "isa") == 0) || 258 (strcmp(parent_type, "eisa") == 0)) { 259 *(dev_info_t **)found_dip = dip; 260 ddi_prop_free(parent_type); 261 return (DDI_WALK_TERMINATE); 262 } 263 264 if ((strcmp(parent_type, "pci") == 0) || 265 (strcmp(parent_type, "pciex") == 0)) { 266 ddi_acc_handle_t pci_conf; 267 uint16_t data16; 268 269 ddi_prop_free(parent_type); 270 271 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 272 return (DDI_WALK_PRUNECHILD); 273 274 if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) 275 return (DDI_WALK_PRUNECHILD); 276 277 data16 = pci_config_get16(pci_conf, PCI_CONF_COMM); 278 pci_config_teardown(&pci_conf); 279 280 if (!(data16 & PCI_COMM_IO)) 281 return (DDI_WALK_PRUNECHILD); 282 283 *(dev_info_t **)found_dip = dip; 284 return (DDI_WALK_TERMINATE); 285 } 286 287 ddi_prop_free(parent_type); 288 return (DDI_WALK_PRUNECHILD); 289 } 290 291 /* 292 * Conduct a width-first traverse searching for a display device which 293 * has either: 294 * 1) a VGA device. 295 * 2) a PCI VGA compatible device whose IO space is enabled 296 * and the VGA Enable bit of any PCI-PCI bridge above it is set. 297 * 298 * Return the device path as the console fb path. 299 */ 300 char * 301 plat_fbpath(void) 302 { 303 dev_info_t *fb_dip = NULL; 304 static char *fbpath = NULL; 305 static char fbpath_buf[MAXPATHLEN]; 306 307 ddi_walk_devs(ddi_root_node(), find_fb_dev, &fb_dip); 308 309 if (fb_dip == NULL) 310 return (NULL); 311 312 (void) ddi_pathname(fb_dip, fbpath_buf); 313 fbpath = fbpath_buf; 314 315 return (fbpath); 316 } 317 318 char * 319 plat_mousepath(void) 320 { 321 static char mpath[MAXPATHLEN]; 322 323 /* 324 * Hardcode to isa mouse path 325 * XXX make it settable via bootprop? 326 */ 327 if (pseudo_isa) 328 return ("/isa/i8042@1,60/mouse@1"); 329 330 if (plat_devpath("mouse8042", mpath) == NULL) 331 return (NULL); 332 333 return (mpath); 334 } 335 336 /* return path of first usb serial device */ 337 static char * 338 plat_usbser_path(void) 339 { 340 extern dev_info_t *usbser_first_device(void); 341 342 dev_info_t *us_dip; 343 static char *us_path = NULL; 344 345 if (us_path) 346 return (us_path); 347 348 us_dip = usbser_first_device(); 349 if (us_dip == NULL) 350 return (NULL); 351 352 us_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 353 (void) ddi_pathname(us_dip, us_path); 354 ndi_rele_devi(us_dip); /* held from usbser_first_device */ 355 return (us_path); 356 } 357 358 static char * 359 plat_ttypath(int inum) 360 { 361 static char *defaultpath[] = { 362 "/isa/asy@1,3f8:a", 363 "/isa/asy@1,2f8:b" 364 }; 365 static char path[MAXPATHLEN]; 366 char *bp; 367 major_t major; 368 dev_info_t *dip; 369 370 if (pseudo_isa) 371 return (defaultpath[inum]); 372 373 if ((major = ddi_name_to_major("asy")) == (major_t)-1) 374 return (NULL); 375 376 if ((dip = devnamesp[major].dn_head) == NULL) 377 return (NULL); 378 379 for (; dip != NULL; dip = ddi_get_next(dip)) { 380 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 381 return (NULL); 382 383 if (DEVI(dip)->devi_minor->ddm_name[0] == ('a' + (char)inum)) 384 break; 385 } 386 if (dip == NULL) 387 return (NULL); 388 389 (void) ddi_pathname(dip, path); 390 bp = path + strlen(path); 391 (void) snprintf(bp, 3, ":%s", DEVI(dip)->devi_minor->ddm_name); 392 393 return (path); 394 } 395 396 /* 397 * Lacking support for com2 and com3, if that matters. 398 * Another possible enhancement could be to use properties 399 * for the port mapping rather than simply hard-code them. 400 */ 401 char * 402 plat_stdinpath(void) 403 { 404 switch (console_type()) { 405 #if defined(__xpv) 406 case CONS_HYPERVISOR: 407 return ("/xpvd/xencons@0"); 408 #endif /* __xpv */ 409 case CONS_TTYA: 410 return (plat_ttypath(0)); 411 case CONS_TTYB: 412 return (plat_ttypath(1)); 413 case CONS_USBSER: 414 return (plat_usbser_path()); 415 case CONS_SCREEN: 416 default: 417 break; 418 }; 419 return (plat_kbdpath()); 420 } 421 422 char * 423 plat_stdoutpath(void) 424 { 425 switch (console_type()) { 426 #if defined(__xpv) 427 case CONS_HYPERVISOR: 428 return ("/xpvd/xencons@0"); 429 #endif /* __xpv */ 430 case CONS_TTYA: 431 return (plat_ttypath(0)); 432 case CONS_TTYB: 433 return (plat_ttypath(1)); 434 case CONS_USBSER: 435 return (plat_usbser_path()); 436 case CONS_SCREEN: 437 default: 438 break; 439 }; 440 return (plat_fbpath()); 441 } 442 443 /* 444 * If VIS_PIXEL mode will be implemented on x86, these following 445 * functions should be re-considered. Now these functions are 446 * unused on x86. 447 */ 448 void 449 plat_tem_get_inverses(int *inverse, int *inverse_screen) 450 { 451 *inverse = 0; 452 *inverse_screen = 0; 453 } 454 455 void 456 plat_tem_get_prom_font_size(int *charheight, int *windowtop) 457 { 458 *charheight = 0; 459 *windowtop = 0; 460 } 461 462 /*ARGSUSED*/ 463 void 464 plat_tem_get_prom_size(size_t *height, size_t *width) 465 { 466 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 467 } 468 469 void 470 plat_tem_hide_prom_cursor(void) 471 { 472 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 473 } 474 475 /*ARGSUSED*/ 476 void 477 plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) 478 { 479 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 480 } 481