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