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
console_hypervisor_dev_type(int * tnum)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
clear_screen(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
screen_putchar(int c)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
serial_init(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 *
find_boot_line_prop(const char * name)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 *
get_mode_value(char * name)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
serial_adjust_prop(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
boot_console_type(int * tnum)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
bcons_init(char * bootstr)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
bcons_init2(char * inputdev,char * outputdev,char * consoledev)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
bcons_hypervisor_redirect(void)748 bcons_hypervisor_redirect(void)
749 {
750 return (console_hypervisor_redirect);
751 }
752
753 void
bcons_device_change(int new_console)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
defcons_putchar(int c)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
serial_putchar(int c)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
serial_getchar(void)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
serial_ischar(void)820 serial_ischar(void)
821 {
822 return (inb(port + LSR) & RCA);
823 }
824
825 static void
_doputchar(int c)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
bcons_putchar(int c)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
bcons_getchar(void)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
bcons_ischar(void)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