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 #if defined(__xpv) 46 #include <sys/hypervisor.h> 47 #include <sys/boot_console.h> 48 #endif 49 50 extern int pseudo_isa; 51 52 /* The names of currently supported graphics drivers on x86 */ 53 static char * 54 gfxdrv_name[] = { 55 "radeon", 56 "vgatext", 57 "i915", 58 "atiatom", 59 "nvidia", 60 }; 61 62 int 63 plat_use_polled_debug() { 64 return (0); 65 } 66 67 int 68 plat_support_serial_kbd_and_ms() { 69 return (0); 70 } 71 72 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0])) 73 74 #define CONS_INVALID -1 75 #define CONS_SCREEN 0 76 #define CONS_TTYA 1 77 #define CONS_TTYB 2 78 #define CONS_USBSER 3 79 #define CONS_HYPERVISOR 4 80 81 char *plat_fbpath(void); 82 83 static int 84 console_type() 85 { 86 static int boot_console = CONS_INVALID; 87 88 char *cons; 89 dev_info_t *root; 90 91 if (boot_console != CONS_INVALID) 92 return (boot_console); 93 94 #if defined(__xpv) 95 if (!DOMAIN_IS_INITDOMAIN(xen_info) || bcons_hypervisor_redirect()) { 96 boot_console = CONS_HYPERVISOR; 97 return (boot_console); 98 } 99 #endif /* __xpv */ 100 101 /* 102 * console is defined by "console" property, with 103 * fallback on the old "input-device" property. 104 * If "input-device" is not defined either, also check "output-device". 105 */ 106 boot_console = CONS_SCREEN; /* default is screen/kb */ 107 root = ddi_root_node(); 108 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 109 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) || 110 (ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 111 DDI_PROP_DONTPASS, "input-device", &cons) == DDI_SUCCESS) || 112 (ddi_prop_lookup_string(DDI_DEV_T_ANY, root, 113 DDI_PROP_DONTPASS, "output-device", &cons) == DDI_SUCCESS)) { 114 if (strcmp(cons, "ttya") == 0) { 115 boot_console = CONS_TTYA; 116 } else if (strcmp(cons, "ttyb") == 0) { 117 boot_console = CONS_TTYB; 118 } else if (strcmp(cons, "usb-serial") == 0) { 119 (void) i_ddi_attach_hw_nodes("ehci"); 120 (void) i_ddi_attach_hw_nodes("uhci"); 121 (void) i_ddi_attach_hw_nodes("ohci"); 122 /* 123 * USB device enumerate asynchronously. 124 * Wait 2 seconds for USB serial devices to attach. 125 */ 126 delay(drv_usectohz(2000000)); 127 boot_console = CONS_USBSER; 128 #if defined(__xpv) 129 } else if (strcmp(cons, "hypervisor") == 0) { 130 boot_console = CONS_HYPERVISOR; 131 #endif /* __xpv */ 132 } 133 ddi_prop_free(cons); 134 } 135 136 /* 137 * If the console is configured to use a framebuffer but none 138 * could be found, fallback to "ttya" since it's likely to exist 139 * and it matches longstanding behavior on SPARC. 140 */ 141 if (boot_console == CONS_SCREEN && plat_fbpath() == NULL) 142 boot_console = CONS_TTYA; 143 144 return (boot_console); 145 } 146 147 int 148 plat_stdin_is_keyboard(void) 149 { 150 return (console_type() == CONS_SCREEN); 151 } 152 153 int 154 plat_stdout_is_framebuffer(void) 155 { 156 return (console_type() == CONS_SCREEN); 157 } 158 159 static char * 160 plat_devpath(char *name, char *path) 161 { 162 major_t major; 163 dev_info_t *dip, *pdip; 164 165 if ((major = ddi_name_to_major(name)) == (major_t)-1) 166 return (NULL); 167 168 if ((dip = devnamesp[major].dn_head) == NULL) 169 return (NULL); 170 171 pdip = ddi_get_parent(dip); 172 if (i_ddi_attach_node_hierarchy(pdip) != DDI_SUCCESS) 173 return (NULL); 174 if (ddi_initchild(pdip, dip) != DDI_SUCCESS) 175 return (NULL); 176 177 (void) ddi_pathname(dip, path); 178 179 return (path); 180 } 181 182 /* 183 * Return generic path to keyboard device from the alias. 184 */ 185 char * 186 plat_kbdpath(void) 187 { 188 static char kbpath[MAXPATHLEN]; 189 190 /* 191 * Hardcode to isa keyboard path 192 * XXX make it settable via bootprop? 193 */ 194 if (pseudo_isa) 195 return ("/isa/i8042@1,60/keyboard@0"); 196 197 if (plat_devpath("kb8042", kbpath) == NULL) 198 return (NULL); 199 200 return (kbpath); 201 } 202 203 /* 204 * Return generic path to display device from the alias. 205 */ 206 char * 207 plat_fbpath(void) 208 { 209 static char *fbpath = NULL; 210 static char fbpath_buf[MAXPATHLEN]; 211 major_t major; 212 dev_info_t *dip, *dip_pseudo = NULL; 213 int i; 214 215 /* lookup the dip for the pseudo device */ 216 (void) resolve_pathname("/pseudo", &dip_pseudo, NULL, NULL); 217 218 for (i = 0; i < A_CNT(gfxdrv_name); i++) { 219 /* 220 * look for first instance of each driver 221 */ 222 if ((major = ddi_name_to_major(gfxdrv_name[i])) == (major_t)-1) 223 continue; 224 225 if ((dip = devnamesp[major].dn_head) == NULL) 226 continue; 227 228 /* 229 * We're looking for a real hardware device here so skip 230 * any pseudo devices. When could a framebuffer hardware 231 * driver also have a pseudo node? Well, some framebuffer 232 * hardware drivers (nvidia) also create pseudo nodes for 233 * administration purposes, and these nodes will exist 234 * regardless of if the actual associated hardware 235 * is present or not. 236 */ 237 if (ddi_get_parent(dip) == dip_pseudo) 238 continue; 239 240 if (i_ddi_attach_node_hierarchy(dip) == DDI_SUCCESS) { 241 (void) ddi_pathname(dip, fbpath_buf); 242 fbpath = fbpath_buf; 243 } 244 245 if (fbpath) 246 break; 247 } 248 249 if (dip_pseudo != NULL) 250 ddi_release_devi(dip_pseudo); 251 252 /* No screen found */ 253 return (fbpath); 254 } 255 256 char * 257 plat_mousepath(void) 258 { 259 static char mpath[MAXPATHLEN]; 260 261 /* 262 * Hardcode to isa mouse path 263 * XXX make it settable via bootprop? 264 */ 265 if (pseudo_isa) 266 return ("/isa/i8042@1,60/mouse@1"); 267 268 if (plat_devpath("mouse8042", mpath) == NULL) 269 return (NULL); 270 271 return (mpath); 272 } 273 274 /* return path of first usb serial device */ 275 static char * 276 plat_usbser_path(void) 277 { 278 extern dev_info_t *usbser_first_device(void); 279 280 dev_info_t *us_dip; 281 static char *us_path = NULL; 282 283 if (us_path) 284 return (us_path); 285 286 us_dip = usbser_first_device(); 287 if (us_dip == NULL) 288 return (NULL); 289 290 us_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 291 (void) ddi_pathname(us_dip, us_path); 292 ndi_rele_devi(us_dip); /* held from usbser_first_device */ 293 return (us_path); 294 } 295 296 static char * 297 plat_ttypath(int inum) 298 { 299 static char *defaultpath[] = { 300 "/isa/asy@1,3f8:a", 301 "/isa/asy@1,2f8:b" 302 }; 303 static char path[MAXPATHLEN]; 304 char *bp; 305 major_t major; 306 dev_info_t *dip; 307 308 if (pseudo_isa) 309 return (defaultpath[inum]); 310 311 if ((major = ddi_name_to_major("asy")) == (major_t)-1) 312 return (NULL); 313 314 if ((dip = devnamesp[major].dn_head) == NULL) 315 return (NULL); 316 317 while (inum-- > 0) { 318 if ((dip = ddi_get_next(dip)) == NULL) 319 return (NULL); 320 } 321 322 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) 323 return (NULL); 324 325 (void) ddi_pathname(dip, path); 326 bp = path + strlen(path); 327 (void) snprintf(bp, 3, ":%s", DEVI(dip)->devi_minor->ddm_name); 328 329 return (path); 330 } 331 332 /* 333 * Lacking support for com2 and com3, if that matters. 334 * Another possible enhancement could be to use properties 335 * for the port mapping rather than simply hard-code them. 336 */ 337 char * 338 plat_stdinpath(void) 339 { 340 switch (console_type()) { 341 #if defined(__xpv) 342 case CONS_HYPERVISOR: 343 return ("/xpvd/xencons@0"); 344 #endif /* __xpv */ 345 case CONS_TTYA: 346 return (plat_ttypath(0)); 347 case CONS_TTYB: 348 return (plat_ttypath(1)); 349 case CONS_USBSER: 350 return (plat_usbser_path()); 351 case CONS_SCREEN: 352 default: 353 break; 354 }; 355 return (plat_kbdpath()); 356 } 357 358 char * 359 plat_stdoutpath(void) 360 { 361 switch (console_type()) { 362 #if defined(__xpv) 363 case CONS_HYPERVISOR: 364 return ("/xpvd/xencons@0"); 365 #endif /* __xpv */ 366 case CONS_TTYA: 367 return (plat_ttypath(0)); 368 case CONS_TTYB: 369 return (plat_ttypath(1)); 370 case CONS_USBSER: 371 return (plat_usbser_path()); 372 case CONS_SCREEN: 373 default: 374 break; 375 }; 376 return (plat_fbpath()); 377 } 378 379 /* 380 * If VIS_PIXEL mode will be implemented on x86, these following 381 * functions should be re-considered. Now these functions are 382 * unused on x86. 383 */ 384 void 385 plat_tem_get_inverses(int *inverse, int *inverse_screen) 386 { 387 *inverse = 0; 388 *inverse_screen = 0; 389 } 390 391 void 392 plat_tem_get_prom_font_size(int *charheight, int *windowtop) 393 { 394 *charheight = 0; 395 *windowtop = 0; 396 } 397 398 /*ARGSUSED*/ 399 void 400 plat_tem_get_prom_size(size_t *height, size_t *width) 401 { 402 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 403 } 404 405 void 406 plat_tem_hide_prom_cursor(void) 407 { 408 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 409 } 410 411 /*ARGSUSED*/ 412 void 413 plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) 414 { 415 panic("unimplemented at line %d of %s", __LINE__, __FILE__); 416 } 417