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 * Copyright (c) 2012 Gary Mills 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/archsystm.h> 31 #include <sys/boot_console.h> 32 #include <sys/panic.h> 33 #include <sys/ctype.h> 34 #if defined(__xpv) 35 #include <sys/hypervisor.h> 36 #endif /* __xpv */ 37 38 #include "boot_serial.h" 39 #include "boot_vga.h" 40 41 #if defined(_BOOT) 42 #include <dboot/dboot_asm.h> 43 #include <dboot/dboot_xboot.h> 44 #else /* _BOOT */ 45 #include <sys/bootconf.h> 46 #if defined(__xpv) 47 #include <sys/evtchn_impl.h> 48 #endif /* __xpv */ 49 static char *defcons_buf; 50 static char *defcons_cur; 51 #endif /* _BOOT */ 52 53 #if defined(__xpv) 54 extern void bcons_init_xen(char *); 55 extern void bcons_putchar_xen(int); 56 extern int bcons_getchar_xen(void); 57 extern int bcons_ischar_xen(void); 58 #endif /* __xpv */ 59 60 static int cons_color = CONS_COLOR; 61 static int console = CONS_SCREEN_TEXT; 62 static int tty_num = 0; 63 static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; 64 #if defined(__xpv) 65 static int console_hypervisor_redirect = B_FALSE; 66 static int console_hypervisor_device = CONS_INVALID; 67 static int console_hypervisor_tty_num = 0; 68 69 /* Obtain the hypervisor console type */ 70 int 71 console_hypervisor_dev_type(int *tnum) 72 { 73 if (tnum != NULL) 74 *tnum = console_hypervisor_tty_num; 75 return (console_hypervisor_device); 76 } 77 #endif /* __xpv */ 78 79 static int serial_ischar(void); 80 static int serial_getchar(void); 81 static void serial_putchar(int); 82 static void serial_adjust_prop(void); 83 84 static char *boot_line = NULL; 85 86 #if !defined(_BOOT) 87 /* Set if the console or mode are expressed in the boot line */ 88 static int console_set, console_mode_set; 89 #endif 90 91 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */ 92 void 93 clear_screen(void) 94 { 95 /* 96 * XXX should set vga mode so we don't depend on the 97 * state left by the boot loader. Note that we have to 98 * enable the cursor before clearing the screen since 99 * the cursor position is dependant upon the cursor 100 * skew, which is initialized by vga_cursor_display() 101 */ 102 vga_cursor_display(); 103 vga_clear(cons_color); 104 vga_setpos(0, 0); 105 } 106 107 /* Put the character C on the screen. */ 108 static void 109 screen_putchar(int c) 110 { 111 int row, col; 112 113 vga_getpos(&row, &col); 114 switch (c) { 115 case '\t': 116 col += 8 - (col % 8); 117 if (col == VGA_TEXT_COLS) 118 col = 79; 119 vga_setpos(row, col); 120 break; 121 122 case '\r': 123 vga_setpos(row, 0); 124 break; 125 126 case '\b': 127 if (col > 0) 128 vga_setpos(row, col - 1); 129 break; 130 131 case '\n': 132 if (row < VGA_TEXT_ROWS - 1) 133 vga_setpos(row + 1, col); 134 else 135 vga_scroll(cons_color); 136 break; 137 138 default: 139 vga_drawc(c, cons_color); 140 if (col < VGA_TEXT_COLS -1) 141 vga_setpos(row, col + 1); 142 else if (row < VGA_TEXT_ROWS - 1) 143 vga_setpos(row + 1, 0); 144 else { 145 vga_setpos(row, 0); 146 vga_scroll(cons_color); 147 } 148 break; 149 } 150 } 151 152 static int port; 153 154 static void 155 serial_init(void) 156 { 157 port = tty_addr[tty_num]; 158 159 outb(port + ISR, 0x20); 160 if (inb(port + ISR) & 0x20) { 161 /* 162 * 82510 chip is present 163 */ 164 outb(port + DAT+7, 0x04); /* clear status */ 165 outb(port + ISR, 0x40); /* set to bank 2 */ 166 outb(port + MCR, 0x08); /* IMD */ 167 outb(port + DAT, 0x21); /* FMD */ 168 outb(port + ISR, 0x00); /* set to bank 0 */ 169 } else { 170 /* 171 * set the UART in FIFO mode if it has FIFO buffers. 172 * use 16550 fifo reset sequence specified in NS 173 * application note. disable fifos until chip is 174 * initialized. 175 */ 176 outb(port + FIFOR, 0x00); /* clear */ 177 outb(port + FIFOR, FIFO_ON); /* enable */ 178 outb(port + FIFOR, FIFO_ON|FIFORXFLSH); /* reset */ 179 outb(port + FIFOR, 180 FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80); 181 if ((inb(port + ISR) & 0xc0) != 0xc0) { 182 /* 183 * no fifo buffers so disable fifos. 184 * this is true for 8250's 185 */ 186 outb(port + FIFOR, 0x00); 187 } 188 } 189 190 /* disable interrupts */ 191 outb(port + ICR, 0); 192 193 #if !defined(_BOOT) 194 if (IN_XPV_PANIC()) 195 return; 196 #endif 197 198 /* adjust setting based on tty properties */ 199 serial_adjust_prop(); 200 201 #if defined(_BOOT) 202 /* 203 * Do a full reset to match console behavior. 204 * 0x1B + c - reset everything 205 */ 206 serial_putchar(0x1B); 207 serial_putchar('c'); 208 #endif 209 } 210 211 /* Advance str pointer past white space */ 212 #define EAT_WHITE_SPACE(str) { \ 213 while ((*str != '\0') && ISSPACE(*str)) \ 214 str++; \ 215 } 216 217 /* 218 * boot_line is set when we call here. Search it for the argument name, 219 * and if found, return a pointer to it. 220 */ 221 static char * 222 find_boot_line_prop(const char *name) 223 { 224 char *ptr; 225 char *ret = NULL; 226 char end_char; 227 size_t len; 228 229 if (boot_line == NULL) 230 return (NULL); 231 232 len = strlen(name); 233 234 /* 235 * We have two nested loops here: the outer loop discards all options 236 * except -B, and the inner loop parses the -B options looking for 237 * the one we're interested in. 238 */ 239 for (ptr = boot_line; *ptr != '\0'; ptr++) { 240 EAT_WHITE_SPACE(ptr); 241 242 if (*ptr == '-') { 243 ptr++; 244 while ((*ptr != '\0') && (*ptr != 'B') && 245 !ISSPACE(*ptr)) 246 ptr++; 247 if (*ptr == '\0') 248 goto out; 249 else if (*ptr != 'B') 250 continue; 251 } else { 252 while ((*ptr != '\0') && !ISSPACE(*ptr)) 253 ptr++; 254 if (*ptr == '\0') 255 goto out; 256 continue; 257 } 258 259 do { 260 ptr++; 261 EAT_WHITE_SPACE(ptr); 262 263 if ((strncmp(ptr, name, len) == 0) && 264 (ptr[len] == '=')) { 265 ptr += len + 1; 266 if ((*ptr == '\'') || (*ptr == '"')) { 267 ret = ptr + 1; 268 end_char = *ptr; 269 ptr++; 270 } else { 271 ret = ptr; 272 end_char = ','; 273 } 274 goto consume_property; 275 } 276 277 /* 278 * We have a property, and it's not the one we're 279 * interested in. Skip the property name. A name 280 * can end with '=', a comma, or white space. 281 */ 282 while ((*ptr != '\0') && (*ptr != '=') && 283 (*ptr != ',') && (!ISSPACE(*ptr))) 284 ptr++; 285 286 /* 287 * We only want to go through the rest of the inner 288 * loop if we have a comma. If we have a property 289 * name without a value, either continue or break. 290 */ 291 if (*ptr == '\0') 292 goto out; 293 else if (*ptr == ',') 294 continue; 295 else if (ISSPACE(*ptr)) 296 break; 297 ptr++; 298 299 /* 300 * Is the property quoted? 301 */ 302 if ((*ptr == '\'') || (*ptr == '"')) { 303 end_char = *ptr; 304 ptr++; 305 } else { 306 /* 307 * Not quoted, so the string ends at a comma 308 * or at white space. Deal with white space 309 * later. 310 */ 311 end_char = ','; 312 } 313 314 /* 315 * Now, we can ignore any characters until we find 316 * end_char. 317 */ 318 consume_property: 319 for (; (*ptr != '\0') && (*ptr != end_char); ptr++) { 320 if ((end_char == ',') && ISSPACE(*ptr)) 321 break; 322 } 323 if (*ptr && (*ptr != ',') && !ISSPACE(*ptr)) 324 ptr++; 325 } while (*ptr == ','); 326 } 327 out: 328 return (ret); 329 } 330 331 332 #define MATCHES(p, pat) \ 333 (strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0) 334 335 #define SKIP(p, c) \ 336 while (*(p) != 0 && *p != (c)) \ 337 ++(p); \ 338 if (*(p) == (c)) \ 339 ++(p); 340 341 /* 342 * find a tty mode property either from cmdline or from boot properties 343 */ 344 static char * 345 get_mode_value(char *name) 346 { 347 /* 348 * when specified on boot line it looks like "name" "=".... 349 */ 350 if (boot_line != NULL) { 351 return (find_boot_line_prop(name)); 352 } 353 354 #if defined(_BOOT) 355 return (NULL); 356 #else 357 /* 358 * if we're running in the full kernel we check the bootenv.rc settings 359 */ 360 { 361 static char propval[20]; 362 363 propval[0] = 0; 364 if (do_bsys_getproplen(NULL, name) <= 0) 365 return (NULL); 366 (void) do_bsys_getprop(NULL, name, propval); 367 return (propval); 368 } 369 #endif 370 } 371 372 /* 373 * adjust serial port based on properties 374 * These come either from the cmdline or from boot properties. 375 */ 376 static void 377 serial_adjust_prop(void) 378 { 379 char propname[20]; 380 char *propval; 381 char *p; 382 ulong_t baud; 383 uchar_t lcr = 0; 384 uchar_t mcr = DTR | RTS; 385 386 (void) strcpy(propname, "ttyX-mode"); 387 propname[3] = 'a' + tty_num; 388 propval = get_mode_value(propname); 389 if (propval == NULL) 390 propval = "9600,8,n,1,-"; 391 #if !defined(_BOOT) 392 else 393 console_mode_set = 1; 394 #endif 395 396 /* property is of the form: "9600,8,n,1,-" */ 397 p = propval; 398 if (MATCHES(p, "110,")) 399 baud = ASY110; 400 else if (MATCHES(p, "150,")) 401 baud = ASY150; 402 else if (MATCHES(p, "300,")) 403 baud = ASY300; 404 else if (MATCHES(p, "600,")) 405 baud = ASY600; 406 else if (MATCHES(p, "1200,")) 407 baud = ASY1200; 408 else if (MATCHES(p, "2400,")) 409 baud = ASY2400; 410 else if (MATCHES(p, "4800,")) 411 baud = ASY4800; 412 else if (MATCHES(p, "19200,")) 413 baud = ASY19200; 414 else if (MATCHES(p, "38400,")) 415 baud = ASY38400; 416 else if (MATCHES(p, "57600,")) 417 baud = ASY57600; 418 else if (MATCHES(p, "115200,")) 419 baud = ASY115200; 420 else { 421 baud = ASY9600; 422 SKIP(p, ','); 423 } 424 outb(port + LCR, DLAB); 425 outb(port + DAT + DLL, baud & 0xff); 426 outb(port + DAT + DLH, (baud >> 8) & 0xff); 427 428 switch (*p) { 429 case '5': 430 lcr |= BITS5; 431 ++p; 432 break; 433 case '6': 434 lcr |= BITS6; 435 ++p; 436 break; 437 case '7': 438 lcr |= BITS7; 439 ++p; 440 break; 441 case '8': 442 ++p; 443 default: 444 lcr |= BITS8; 445 break; 446 } 447 448 SKIP(p, ','); 449 450 switch (*p) { 451 case 'n': 452 lcr |= PARITY_NONE; 453 ++p; 454 break; 455 case 'o': 456 lcr |= PARITY_ODD; 457 ++p; 458 break; 459 case 'e': 460 ++p; 461 default: 462 lcr |= PARITY_EVEN; 463 break; 464 } 465 466 467 SKIP(p, ','); 468 469 switch (*p) { 470 case '1': 471 /* STOP1 is 0 */ 472 ++p; 473 break; 474 default: 475 lcr |= STOP2; 476 break; 477 } 478 /* set parity bits */ 479 outb(port + LCR, lcr); 480 481 (void) strcpy(propname, "ttyX-rts-dtr-off"); 482 propname[3] = 'a' + tty_num; 483 propval = get_mode_value(propname); 484 if (propval == NULL) 485 propval = "false"; 486 if (propval[0] != 'f' && propval[0] != 'F') 487 mcr = 0; 488 /* set modem control bits */ 489 outb(port + MCR, mcr | OUT2); 490 } 491 492 /* Obtain the console type */ 493 int 494 boot_console_type(int *tnum) 495 { 496 if (tnum != NULL) 497 *tnum = tty_num; 498 return (console); 499 } 500 501 /* 502 * A structure to map console names to values. 503 */ 504 typedef struct { 505 char *name; 506 int value; 507 } console_value_t; 508 509 console_value_t console_devices[] = { 510 { "ttya", CONS_TTY }, /* 0 */ 511 { "ttyb", CONS_TTY }, /* 1 */ 512 { "ttyc", CONS_TTY }, /* 2 */ 513 { "ttyd", CONS_TTY }, /* 3 */ 514 { "text", CONS_SCREEN_TEXT }, 515 { "graphics", CONS_SCREEN_GRAPHICS }, 516 #if defined(__xpv) 517 { "hypervisor", CONS_HYPERVISOR }, 518 #endif 519 #if !defined(_BOOT) 520 { "usb-serial", CONS_USBSER }, 521 #endif 522 { NULL, CONS_INVALID } 523 }; 524 525 void 526 bcons_init(char *bootstr) 527 { 528 console_value_t *consolep; 529 size_t len, cons_len; 530 char *cons_str; 531 #if !defined(_BOOT) 532 static char console_text[] = "text"; 533 extern int post_fastreboot; 534 #endif 535 536 boot_line = bootstr; 537 console = CONS_INVALID; 538 539 #if defined(__xpv) 540 bcons_init_xen(bootstr); 541 #endif /* __xpv */ 542 543 cons_str = find_boot_line_prop("console"); 544 if (cons_str == NULL) 545 cons_str = find_boot_line_prop("output-device"); 546 547 #if !defined(_BOOT) 548 if (post_fastreboot && strcmp(cons_str, "graphics") == 0) 549 cons_str = console_text; 550 #endif 551 552 /* 553 * Go through the console_devices array trying to match the string 554 * we were given. The string on the command line must end with 555 * a comma or white space. 556 */ 557 if (cons_str != NULL) { 558 int n; 559 560 cons_len = strlen(cons_str); 561 for (n = 0; console_devices[n].name != NULL; n++) { 562 consolep = &console_devices[n]; 563 len = strlen(consolep->name); 564 if ((len <= cons_len) && ((cons_str[len] == '\0') || 565 (cons_str[len] == ',') || (cons_str[len] == '\'') || 566 (cons_str[len] == '"') || ISSPACE(cons_str[len])) && 567 (strncmp(cons_str, consolep->name, len) == 0)) { 568 console = consolep->value; 569 if (console == CONS_TTY) 570 tty_num = n; 571 break; 572 } 573 } 574 } 575 576 #if defined(__xpv) 577 /* 578 * domU's always use the hypervisor regardless of what 579 * the console variable may be set to. 580 */ 581 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 582 console = CONS_HYPERVISOR; 583 console_hypervisor_redirect = B_TRUE; 584 } 585 #endif /* __xpv */ 586 587 /* 588 * If no console device specified, default to text. 589 * Remember what was specified for second phase. 590 */ 591 if (console == CONS_INVALID) 592 console = CONS_SCREEN_TEXT; 593 #if !defined(_BOOT) 594 else 595 console_set = 1; 596 #endif 597 598 #if defined(__xpv) 599 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 600 switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) { 601 case XEN_CONSOLE_COM1: 602 case XEN_CONSOLE_COM2: 603 console_hypervisor_device = CONS_TTY; 604 console_hypervisor_tty_num = tty_num; 605 break; 606 case XEN_CONSOLE_VGA: 607 /* 608 * Currently xen doesn't really support 609 * keyboard/display console devices. 610 * What this setting means is that 611 * "vga=keep" has been enabled, which is 612 * more of a xen debugging tool that a 613 * true console mode. Hence, we're going 614 * to ignore this xen "console" setting. 615 */ 616 /*FALLTHROUGH*/ 617 default: 618 console_hypervisor_device = CONS_INVALID; 619 } 620 } 621 622 /* 623 * if the hypervisor is using the currently selected serial 624 * port then default to using the hypervisor as the console 625 * device. 626 */ 627 if (console == console_hypervisor_device) { 628 console = CONS_HYPERVISOR; 629 console_hypervisor_redirect = B_TRUE; 630 } 631 #endif /* __xpv */ 632 633 switch (console) { 634 case CONS_TTY: 635 serial_init(); 636 break; 637 638 case CONS_HYPERVISOR: 639 break; 640 641 #if !defined(_BOOT) 642 case CONS_USBSER: 643 /* 644 * We can't do anything with the usb serial 645 * until we have memory management. 646 */ 647 break; 648 #endif 649 case CONS_SCREEN_GRAPHICS: 650 kb_init(); 651 break; 652 case CONS_SCREEN_TEXT: 653 default: 654 #if defined(_BOOT) 655 clear_screen(); /* clears the grub or xen screen */ 656 #endif /* _BOOT */ 657 kb_init(); 658 break; 659 } 660 boot_line = NULL; 661 } 662 663 #if !defined(_BOOT) 664 /* 665 * 2nd part of console initialization. 666 * In the kernel (ie. fakebop), this can be used only to switch to 667 * using a serial port instead of screen based on the contents 668 * of the bootenv.rc file. 669 */ 670 /*ARGSUSED*/ 671 void 672 bcons_init2(char *inputdev, char *outputdev, char *consoledev) 673 { 674 int cons = CONS_INVALID; 675 int ttyn; 676 char *devnames[] = { consoledev, outputdev, inputdev, NULL }; 677 console_value_t *consolep; 678 int i; 679 extern int post_fastreboot; 680 681 if (post_fastreboot && console == CONS_SCREEN_GRAPHICS) 682 console = CONS_SCREEN_TEXT; 683 684 if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) { 685 if (console_set) { 686 /* 687 * If the console was set on the command line, 688 * but the ttyX-mode was not, we only need to 689 * check bootenv.rc for that setting. 690 */ 691 if ((!console_mode_set) && (console == CONS_TTY)) 692 serial_init(); 693 return; 694 } 695 696 for (i = 0; devnames[i] != NULL; i++) { 697 int n; 698 699 for (n = 0; console_devices[n].name != NULL; n++) { 700 consolep = &console_devices[n]; 701 if (strcmp(devnames[i], consolep->name) == 0) { 702 cons = consolep->value; 703 if (cons == CONS_TTY) 704 ttyn = n; 705 } 706 } 707 if (cons != CONS_INVALID) 708 break; 709 } 710 711 #if defined(__xpv) 712 /* 713 * if the hypervisor is using the currently selected console 714 * device then default to using the hypervisor as the console 715 * device. 716 */ 717 if (cons == console_hypervisor_device) { 718 cons = CONS_HYPERVISOR; 719 console_hypervisor_redirect = B_TRUE; 720 } 721 #endif /* __xpv */ 722 723 if ((cons == CONS_INVALID) || (cons == console)) { 724 /* 725 * we're sticking with whatever the current setting is 726 */ 727 return; 728 } 729 730 console = cons; 731 if (cons == CONS_TTY) { 732 tty_num = ttyn; 733 serial_init(); 734 return; 735 } 736 } else { 737 /* 738 * USB serial and GRAPHICS console 739 * we just collect data into a buffer 740 */ 741 extern void *defcons_init(size_t); 742 defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE); 743 } 744 } 745 746 #if defined(__xpv) 747 boolean_t 748 bcons_hypervisor_redirect(void) 749 { 750 return (console_hypervisor_redirect); 751 } 752 753 void 754 bcons_device_change(int new_console) 755 { 756 if (new_console < CONS_MIN || new_console > CONS_MAX) 757 return; 758 759 /* 760 * If we are asked to switch the console to the hypervisor, that 761 * really means to switch the console to whichever device the 762 * hypervisor is/was using. 763 */ 764 if (new_console == CONS_HYPERVISOR) 765 new_console = console_hypervisor_device; 766 767 console = new_console; 768 769 if (new_console == CONS_TTY) { 770 tty_num = console_hypervisor_tty_num; 771 serial_init(); 772 } 773 } 774 #endif /* __xpv */ 775 776 static void 777 defcons_putchar(int c) 778 { 779 if (defcons_buf != NULL && 780 defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) { 781 *defcons_cur++ = c; 782 *defcons_cur = 0; 783 } 784 } 785 #endif /* _BOOT */ 786 787 static void 788 serial_putchar(int c) 789 { 790 int checks = 10000; 791 792 while (((inb(port + LSR) & XHRE) == 0) && checks--) 793 ; 794 outb(port + DAT, (char)c); 795 } 796 797 static int 798 serial_getchar(void) 799 { 800 uchar_t lsr; 801 802 while (serial_ischar() == 0) 803 ; 804 805 lsr = inb(port + LSR); 806 if (lsr & (SERIAL_BREAK | SERIAL_FRAME | 807 SERIAL_PARITY | SERIAL_OVERRUN)) { 808 if (lsr & SERIAL_OVERRUN) { 809 return (inb(port + DAT)); 810 } else { 811 /* Toss the garbage */ 812 (void) inb(port + DAT); 813 return (0); 814 } 815 } 816 return (inb(port + DAT)); 817 } 818 819 static int 820 serial_ischar(void) 821 { 822 return (inb(port + LSR) & RCA); 823 } 824 825 static void 826 _doputchar(int c) 827 { 828 switch (console) { 829 case CONS_TTY: 830 serial_putchar(c); 831 return; 832 case CONS_SCREEN_TEXT: 833 screen_putchar(c); 834 return; 835 case CONS_SCREEN_GRAPHICS: 836 #if !defined(_BOOT) 837 case CONS_USBSER: 838 defcons_putchar(c); 839 #endif /* _BOOT */ 840 return; 841 } 842 } 843 844 void 845 bcons_putchar(int c) 846 { 847 static int bhcharpos = 0; 848 849 #if defined(__xpv) 850 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 851 console == CONS_HYPERVISOR) { 852 bcons_putchar_xen(c); 853 return; 854 } 855 #endif /* __xpv */ 856 857 if (c == '\t') { 858 do { 859 _doputchar(' '); 860 } while (++bhcharpos % 8); 861 return; 862 } else if (c == '\n' || c == '\r') { 863 bhcharpos = 0; 864 _doputchar('\r'); 865 _doputchar(c); 866 return; 867 } else if (c == '\b') { 868 if (bhcharpos) 869 bhcharpos--; 870 _doputchar(c); 871 return; 872 } 873 874 bhcharpos++; 875 _doputchar(c); 876 } 877 878 /* 879 * kernel character input functions 880 */ 881 int 882 bcons_getchar(void) 883 { 884 #if defined(__xpv) 885 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 886 console == CONS_HYPERVISOR) 887 return (bcons_getchar_xen()); 888 #endif /* __xpv */ 889 890 switch (console) { 891 case CONS_TTY: 892 return (serial_getchar()); 893 default: 894 return (kb_getchar()); 895 } 896 } 897 898 #if !defined(_BOOT) 899 900 int 901 bcons_ischar(void) 902 { 903 904 #if defined(__xpv) 905 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 906 console == CONS_HYPERVISOR) 907 return (bcons_ischar_xen()); 908 #endif /* __xpv */ 909 910 switch (console) { 911 case CONS_TTY: 912 return (serial_ischar()); 913 default: 914 return (kb_ischar()); 915 } 916 } 917 918 #endif /* _BOOT */ 919