#include <sys/types.h>
#include <sys/systm.h>
#include <sys/archsystm.h>
#include <sys/framebuffer.h>
#include <sys/boot_console.h>
#include <sys/panic.h>
#include <sys/ctype.h>
#include <sys/ascii.h>
#include <sys/vgareg.h>
#if defined(__xpv)
#include <sys/hypervisor.h>
#endif
#include "boot_console_impl.h"
#include "boot_serial.h"
#if defined(_BOOT)
#include <dboot/dboot_asm.h>
#include <dboot/dboot_xboot.h>
#else
#include <sys/bootconf.h>
#if defined(__xpv)
#include <sys/evtchn_impl.h>
#endif
static char *defcons_buf;
static char *defcons_cur;
#endif
#if defined(__xpv)
extern void bcons_init_xen(char *);
extern void bcons_putchar_xen(int);
extern int bcons_getchar_xen(void);
extern int bcons_ischar_xen(void);
#endif
fb_info_t fb_info;
static bcons_dev_t bcons_dev;
static int console = CONS_SCREEN_TEXT;
static int diag = CONS_INVALID;
static int tty_num = 0;
static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
static char *boot_line;
static struct boot_env {
char *be_env;
size_t be_size;
} boot_env;
typedef enum btem_state_type {
A_STATE_START,
A_STATE_ESC,
A_STATE_CSI,
A_STATE_CSI_QMARK,
A_STATE_CSI_EQUAL
} btem_state_type_t;
#define BTEM_MAXPARAMS 5
typedef struct btem_state {
btem_state_type_t btem_state;
boolean_t btem_gotparam;
int btem_curparam;
int btem_paramval;
int btem_params[BTEM_MAXPARAMS];
} btem_state_t;
static btem_state_t boot_tem;
static int serial_ischar(void);
static int serial_getchar(void);
static void serial_putchar(int);
static void serial_adjust_prop(void);
static void defcons_putchar(int);
#if !defined(_BOOT)
static boolean_t bootprop_set_tty_mode;
#endif
#if defined(__xpv)
static int console_hypervisor_redirect = B_FALSE;
static int console_hypervisor_device = CONS_INVALID;
static int console_hypervisor_tty_num = 0;
int
console_hypervisor_dev_type(int *tnum)
{
if (tnum != NULL)
*tnum = console_hypervisor_tty_num;
return (console_hypervisor_device);
}
#endif
static int port;
static void
serial_init(void)
{
port = tty_addr[tty_num];
outb(port + ISR, 0x20);
if (inb(port + ISR) & 0x20) {
outb(port + DAT+7, 0x04);
outb(port + ISR, 0x40);
outb(port + MCR, 0x08);
outb(port + DAT, 0x21);
outb(port + ISR, 0x00);
} else {
outb(port + FIFOR, 0x00);
outb(port + FIFOR, FIFO_ON);
outb(port + FIFOR, FIFO_ON|FIFORXFLSH);
outb(port + FIFOR,
FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80);
if ((inb(port + ISR) & 0xc0) != 0xc0) {
outb(port + FIFOR, 0x00);
}
}
outb(port + ICR, 0);
#if !defined(_BOOT)
if (IN_XPV_PANIC())
return;
#endif
serial_adjust_prop();
}
#define EAT_WHITE_SPACE(str) { \
while ((*str != '\0') && ISSPACE(*str)) \
str++; \
}
static char *
find_boot_line_prop(const char *name)
{
char *ptr;
char *ret = NULL;
char end_char;
size_t len;
if (boot_line == NULL)
return (NULL);
len = strlen(name);
for (ptr = boot_line; *ptr != '\0'; ptr++) {
EAT_WHITE_SPACE(ptr);
if (*ptr == '-') {
ptr++;
while ((*ptr != '\0') && (*ptr != 'B') &&
!ISSPACE(*ptr))
ptr++;
if (*ptr == '\0')
goto out;
else if (*ptr != 'B')
continue;
} else {
while ((*ptr != '\0') && !ISSPACE(*ptr))
ptr++;
if (*ptr == '\0')
goto out;
continue;
}
do {
ptr++;
EAT_WHITE_SPACE(ptr);
if ((strncmp(ptr, name, len) == 0) &&
(ptr[len] == '=')) {
ptr += len + 1;
if ((*ptr == '\'') || (*ptr == '"')) {
ret = ptr + 1;
end_char = *ptr;
ptr++;
} else {
ret = ptr;
end_char = ',';
}
goto consume_property;
}
while ((*ptr != '\0') && (*ptr != '=') &&
(*ptr != ',') && (!ISSPACE(*ptr)))
ptr++;
if (*ptr == '\0')
goto out;
else if (*ptr == ',')
continue;
else if (ISSPACE(*ptr))
break;
ptr++;
if ((*ptr == '\'') || (*ptr == '"')) {
end_char = *ptr;
ptr++;
} else {
end_char = ',';
}
consume_property:
for (; (*ptr != '\0') && (*ptr != end_char); ptr++) {
if ((end_char == ',') && ISSPACE(*ptr))
break;
}
if (*ptr && (*ptr != ',') && !ISSPACE(*ptr))
ptr++;
} while (*ptr == ',');
}
out:
return (ret);
}
static const char *
find_boot_env_prop(const char *name)
{
char *ptr;
size_t len;
uintptr_t size;
if (boot_env.be_env == NULL)
return (NULL);
ptr = boot_env.be_env;
len = strlen(name);
if (boot_env.be_size < len + 2)
return (NULL);
do {
if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) {
ptr += len + 1;
return (ptr);
}
while (*ptr != '\0') {
ptr++;
size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
if (size > boot_env.be_size)
return (NULL);
}
ptr++;
size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
if (boot_env.be_size - size < len + 2)
return (NULL);
} while (*ptr != '\0');
return (NULL);
}
const char *
find_boot_prop(const char *name)
{
const char *value = find_boot_line_prop(name);
if (value == NULL)
value = find_boot_env_prop(name);
return (value);
}
#define MATCHES(p, pat) \
(strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0)
#define SKIP(p, c) \
while (*(p) != 0 && *p != (c)) \
++(p); \
if (*(p) == (c)) \
++(p);
static const char *
get_mode_value(char *name)
{
if (boot_line != NULL) {
return (find_boot_prop(name));
}
#if defined(_BOOT)
return (NULL);
#else
{
static char propval[20];
propval[0] = 0;
if (do_bsys_getproplen(NULL, name) <= 0)
return (NULL);
(void) do_bsys_getprop(NULL, name, propval);
return (propval);
}
#endif
}
static void
serial_adjust_prop(void)
{
char propname[20];
const char *propval;
const char *p;
ulong_t baud;
uchar_t lcr = 0;
uchar_t mcr = DTR | RTS;
(void) strcpy(propname, "ttyX-mode");
propname[3] = 'a' + tty_num;
propval = get_mode_value(propname);
#if !defined(_BOOT)
if (propval != NULL)
bootprop_set_tty_mode = B_TRUE;
#endif
if (propval == NULL)
propval = "9600,8,n,1,-";
p = propval;
if (MATCHES(p, "110,"))
baud = ASY110;
else if (MATCHES(p, "150,"))
baud = ASY150;
else if (MATCHES(p, "300,"))
baud = ASY300;
else if (MATCHES(p, "600,"))
baud = ASY600;
else if (MATCHES(p, "1200,"))
baud = ASY1200;
else if (MATCHES(p, "2400,"))
baud = ASY2400;
else if (MATCHES(p, "4800,"))
baud = ASY4800;
else if (MATCHES(p, "19200,"))
baud = ASY19200;
else if (MATCHES(p, "38400,"))
baud = ASY38400;
else if (MATCHES(p, "57600,"))
baud = ASY57600;
else if (MATCHES(p, "115200,"))
baud = ASY115200;
else {
baud = ASY9600;
SKIP(p, ',');
}
outb(port + LCR, DLAB);
outb(port + DAT + DLL, baud & 0xff);
outb(port + DAT + DLH, (baud >> 8) & 0xff);
switch (*p) {
case '5':
lcr |= BITS5;
++p;
break;
case '6':
lcr |= BITS6;
++p;
break;
case '7':
lcr |= BITS7;
++p;
break;
case '8':
++p;
default:
lcr |= BITS8;
break;
}
SKIP(p, ',');
switch (*p) {
case 'n':
lcr |= PARITY_NONE;
++p;
break;
case 'o':
lcr |= PARITY_ODD;
++p;
break;
case 'e':
++p;
default:
lcr |= PARITY_EVEN;
break;
}
SKIP(p, ',');
switch (*p) {
case '1':
++p;
break;
default:
lcr |= STOP2;
break;
}
outb(port + LCR, lcr);
(void) strcpy(propname, "ttyX-rts-dtr-off");
propname[3] = 'a' + tty_num;
propval = get_mode_value(propname);
if (propval == NULL)
propval = "false";
if (propval[0] != 'f' && propval[0] != 'F')
mcr = 0;
outb(port + MCR, mcr | OUT2);
}
int
boot_console_type(int *tnum)
{
if (tnum != NULL)
*tnum = tty_num;
return (console);
}
typedef struct {
char *name;
int value;
} console_value_t;
console_value_t console_devices[] = {
{ "ttya", CONS_TTY },
{ "ttyb", CONS_TTY },
{ "ttyc", CONS_TTY },
{ "ttyd", CONS_TTY },
{ "text", CONS_SCREEN_TEXT },
{ "graphics", CONS_SCREEN_GRAPHICS },
#if defined(__xpv)
{ "hypervisor", CONS_HYPERVISOR },
#endif
#if !defined(_BOOT)
{ "usb-serial", CONS_USBSER },
#endif
{ NULL, CONS_INVALID }
};
static void
bcons_init_env(struct xboot_info *xbi)
{
uint32_t i;
struct boot_modules *modules;
modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
for (i = 0; i < xbi->bi_module_cnt; i++) {
if (modules[i].bm_type == BMT_ENV)
break;
}
if (i == xbi->bi_module_cnt)
return;
boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
boot_env.be_size = modules[i].bm_size;
}
int
boot_fb(struct xboot_info *xbi, int console)
{
if (xbi_fb_init(xbi, &bcons_dev) == B_FALSE)
return (console);
if (fb_info.paddr == 0)
return (CONS_TTY);
#if defined(_BOOT)
if (fb_info.paddr >= UINTPTR_MAX)
return (CONS_TTY);
#endif
fb_info.terminal.x = VGA_TEXT_COLS;
fb_info.terminal.y = VGA_TEXT_ROWS;
boot_fb_init(CONS_FRAMEBUFFER);
if (console == CONS_SCREEN_TEXT)
return (CONS_FRAMEBUFFER);
return (console);
}
static int
atoi(const char *p)
{
int n, c, neg = 0;
unsigned char *up = (unsigned char *)p;
if (!isdigit(c = *up)) {
while (isspace(c))
c = *++up;
switch (c) {
case '-':
neg++;
case '+':
c = *++up;
}
if (!isdigit(c))
return (0);
}
for (n = '0' - c; isdigit(c = *++up);) {
n *= 10;
n += '0' - c;
}
return (neg ? n : -n);
}
static void
bcons_init_fb(void)
{
const char *propval;
int intval;
fb_info.fg_color = CONS_COLOR;
fb_info.bg_color = 0;
fb_info.inverse = B_FALSE;
fb_info.inverse_screen = B_FALSE;
propval = find_boot_prop("tem.fg_color");
if (propval != NULL) {
intval = atoi(propval);
if (intval >= 0 && intval <= 255)
fb_info.fg_color = intval;
}
propval = find_boot_prop("tem.bg_color");
if (propval != NULL && ISDIGIT(*propval)) {
intval = atoi(propval);
if (intval >= 0 && intval <= 255)
fb_info.bg_color = intval;
}
propval = find_boot_prop("tem.inverse");
if (propval != NULL) {
if (*propval == '1' || MATCHES(propval, "true"))
fb_info.inverse = B_TRUE;
}
propval = find_boot_prop("tem.inverse-screen");
if (propval != NULL) {
if (*propval == '1' || MATCHES(propval, "true"))
fb_info.inverse_screen = B_TRUE;
}
#if defined(_BOOT)
propval = find_boot_prop("tem.cursor.row");
if (propval != NULL) {
intval = atoi(propval);
if (intval >= 0 && intval <= 0xFFFF)
fb_info.cursor.pos.y = intval;
}
propval = find_boot_prop("tem.cursor.col");
if (propval != NULL) {
intval = atoi(propval);
if (intval >= 0 && intval <= 0xFFFF)
fb_info.cursor.pos.x = intval;
}
#endif
}
static int
lookup_console_device(const char *cons_str, int *indexp)
{
int n, cons;
size_t len, cons_len;
console_value_t *consolep;
cons = CONS_INVALID;
if (cons_str != NULL) {
cons_len = strlen(cons_str);
for (n = 0; console_devices[n].name != NULL; n++) {
consolep = &console_devices[n];
len = strlen(consolep->name);
if ((len <= cons_len) && ((cons_str[len] == '\0') ||
(cons_str[len] == ',') || (cons_str[len] == '\'') ||
(cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
(strncmp(cons_str, consolep->name, len) == 0)) {
cons = consolep->value;
if (cons == CONS_TTY)
*indexp = n;
break;
}
}
}
return (cons);
}
void
bcons_init(struct xboot_info *xbi)
{
const char *cons_str;
#if !defined(_BOOT)
static char console_text[] = "text";
extern int post_fastreboot;
#endif
if (xbi == NULL) {
console = CONS_TTY;
serial_init();
return;
}
boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
bcons_init_env(xbi);
console = CONS_INVALID;
bcons_init_fb();
#if defined(__xpv)
bcons_init_xen(boot_line);
#endif
cons_str = find_boot_prop("diag-device");
if (cons_str != NULL)
diag = lookup_console_device(cons_str, &tty_num);
cons_str = find_boot_prop("console");
if (cons_str == NULL)
cons_str = find_boot_prop("output-device");
#if !defined(_BOOT)
if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
cons_str = console_text;
#endif
if (cons_str != NULL)
console = lookup_console_device(cons_str, &tty_num);
#if defined(__xpv)
if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
console = CONS_HYPERVISOR;
console_hypervisor_redirect = B_TRUE;
}
#endif
if (console == CONS_INVALID)
console = CONS_SCREEN_TEXT;
#if defined(__xpv)
if (DOMAIN_IS_INITDOMAIN(xen_info)) {
switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) {
case XEN_CONSOLE_COM1:
case XEN_CONSOLE_COM2:
console_hypervisor_device = CONS_TTY;
console_hypervisor_tty_num = tty_num;
break;
case XEN_CONSOLE_VGA:
default:
console_hypervisor_device = CONS_INVALID;
}
}
if (console == console_hypervisor_device) {
console = CONS_HYPERVISOR;
console_hypervisor_redirect = B_TRUE;
}
#endif
console = boot_fb(xbi, console);
switch (console) {
case CONS_TTY:
serial_init();
break;
case CONS_HYPERVISOR:
break;
#if !defined(_BOOT)
case CONS_USBSER:
break;
#endif
case CONS_SCREEN_GRAPHICS:
kb_init();
break;
case CONS_SCREEN_TEXT:
boot_vga_init(&bcons_dev);
default:
kb_init();
break;
}
switch (diag) {
case CONS_TTY:
if (console != CONS_TTY)
serial_init();
break;
case CONS_SCREEN_GRAPHICS:
case CONS_SCREEN_TEXT:
if (console != CONS_SCREEN_GRAPHICS &&
console != CONS_SCREEN_TEXT)
kb_init();
break;
default:
break;
}
}
static void
serial_putchar(int c)
{
int checks = 10000;
while (((inb(port + LSR) & XHRE) == 0) && checks--)
;
outb(port + DAT, (char)c);
}
static int
serial_getchar(void)
{
uchar_t lsr;
while (serial_ischar() == 0)
;
lsr = inb(port + LSR);
if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
SERIAL_PARITY | SERIAL_OVERRUN)) {
if (lsr & SERIAL_OVERRUN) {
return (inb(port + DAT));
} else {
(void) inb(port + DAT);
return (0);
}
}
return (inb(port + DAT));
}
static int
serial_ischar(void)
{
return (inb(port + LSR) & RCA);
}
static void
btem_control(btem_state_t *btem, int c)
{
int y, rows, cols;
rows = fb_info.cursor.pos.y;
cols = fb_info.cursor.pos.x;
btem->btem_state = A_STATE_START;
switch (c) {
case A_BS:
bcons_dev.bd_setpos(rows, cols - 1);
break;
case A_HT:
cols += 8 - (cols % 8);
if (cols >= fb_info.terminal.x)
cols = fb_info.terminal.x - 1;
bcons_dev.bd_setpos(rows, cols);
break;
case A_CR:
bcons_dev.bd_setpos(rows, 0);
break;
case A_FF:
for (y = 0; y < fb_info.terminal.y; y++) {
bcons_dev.bd_setpos(y, 0);
bcons_dev.bd_eraseline();
}
bcons_dev.bd_setpos(0, 0);
break;
case A_ESC:
btem->btem_state = A_STATE_ESC;
break;
default:
bcons_dev.bd_putchar(c);
break;
}
}
static void
btem_setparam(btem_state_t *btem, int count, int newparam)
{
int i;
for (i = 0; i < count; i++) {
if (btem->btem_params[i] == -1)
btem->btem_params[i] = newparam;
}
}
static void
btem_chkparam(btem_state_t *btem, int c)
{
int rows, cols;
rows = fb_info.cursor.pos.y;
cols = fb_info.cursor.pos.x;
switch (c) {
case '@':
btem_setparam(btem, 1, 1);
bcons_dev.bd_shift(btem->btem_params[0]);
break;
case 'A':
btem_setparam(btem, 1, 1);
bcons_dev.bd_setpos(rows - btem->btem_params[0], cols);
break;
case 'B':
btem_setparam(btem, 1, 1);
bcons_dev.bd_setpos(rows + btem->btem_params[0], cols);
break;
case 'C':
btem_setparam(btem, 1, 1);
bcons_dev.bd_setpos(rows, cols + btem->btem_params[0]);
break;
case 'D':
btem_setparam(btem, 1, 1);
bcons_dev.bd_setpos(rows, cols - btem->btem_params[0]);
break;
case 'K':
bcons_dev.bd_eraseline();
break;
default:
break;
}
btem->btem_state = A_STATE_START;
}
static void
btem_chkparam_qmark(btem_state_t *btem, int c)
{
switch (c) {
case 'h':
btem_setparam(btem, 1, 1);
switch (btem->btem_params[0]) {
case 25:
break;
}
break;
case 'l':
btem_setparam(btem, 1, 1);
switch (btem->btem_params[0]) {
case 25:
break;
}
break;
}
btem->btem_state = A_STATE_START;
}
static void
btem_getparams(btem_state_t *btem, int c)
{
if (isdigit(c)) {
btem->btem_paramval = btem->btem_paramval * 10 + c - '0';
btem->btem_gotparam = B_TRUE;
return;
}
if (btem->btem_curparam < BTEM_MAXPARAMS) {
if (btem->btem_gotparam == B_TRUE) {
btem->btem_params[btem->btem_curparam] =
btem->btem_paramval;
}
btem->btem_curparam++;
}
if (c == ';') {
btem->btem_gotparam = B_FALSE;
btem->btem_paramval = 0;
} else {
if (btem->btem_state == A_STATE_CSI_QMARK)
btem_chkparam_qmark(btem, c);
else
btem_chkparam(btem, c);
}
}
static void
btem_parse(btem_state_t *btem, int c)
{
int i;
if (btem->btem_state == A_STATE_START) {
if (c == A_CSI || c < ' ')
btem_control(btem, c);
else
bcons_dev.bd_putchar(c);
return;
}
if (btem->btem_state != A_STATE_ESC) {
if (btem->btem_state != A_STATE_CSI) {
btem_getparams(btem, c);
return;
}
switch (c) {
case '?':
btem->btem_state = A_STATE_CSI_QMARK;
return;
default:
btem_getparams(btem, c);
return;
}
}
switch (c) {
case '[':
btem->btem_curparam = 0;
btem->btem_paramval = 0;
btem->btem_gotparam = B_FALSE;
for (i = 0; i < BTEM_MAXPARAMS; i++)
btem->btem_params[i] = -1;
btem->btem_state = A_STATE_CSI;
return;
case 'Q':
case 'C':
btem->btem_state = A_STATE_START;
return;
default:
btem->btem_state = A_STATE_START;
break;
}
if (c < ' ')
btem_control(btem, c);
else
bcons_dev.bd_putchar(c);
}
static void
_doputchar(int device, int c)
{
switch (device) {
case CONS_TTY:
serial_putchar(c);
return;
case CONS_SCREEN_TEXT:
case CONS_FRAMEBUFFER:
bcons_dev.bd_cursor(B_FALSE);
btem_parse(&boot_tem, c);
bcons_dev.bd_cursor(B_TRUE);
return;
case CONS_SCREEN_GRAPHICS:
#if !defined(_BOOT)
case CONS_USBSER:
defcons_putchar(c);
#endif
default:
return;
}
}
void
bcons_putchar(int c)
{
#if defined(__xpv)
if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
console == CONS_HYPERVISOR) {
bcons_putchar_xen(c);
return;
}
#endif
if (c == '\n') {
_doputchar(console, '\r');
if (diag != console)
_doputchar(diag, '\r');
}
_doputchar(console, c);
if (diag != console)
_doputchar(diag, c);
}
int
bcons_getchar(void)
{
#if defined(__xpv)
if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
console == CONS_HYPERVISOR)
return (bcons_getchar_xen());
#endif
for (;;) {
if (console == CONS_TTY || diag == CONS_TTY) {
if (serial_ischar())
return (serial_getchar());
}
if (console != CONS_INVALID || diag != CONS_INVALID) {
if (kb_ischar())
return (kb_getchar());
}
}
}
#if !defined(_BOOT)
int
bcons_ischar(void)
{
int c = 0;
#if defined(__xpv)
if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
console == CONS_HYPERVISOR)
return (bcons_ischar_xen());
#endif
switch (console) {
case CONS_TTY:
c = serial_ischar();
break;
case CONS_INVALID:
break;
default:
c = kb_ischar();
}
if (c != 0)
return (c);
switch (diag) {
case CONS_TTY:
c = serial_ischar();
break;
case CONS_INVALID:
break;
default:
c = kb_ischar();
}
return (c);
}
void
bcons_post_bootenvrc(char *inputdev, char *outputdev, char *consoledev)
{
int cons = CONS_INVALID;
int ttyn;
char *devnames[] = { consoledev, outputdev, inputdev, NULL };
int i;
extern int post_fastreboot;
ttyn = 0;
if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
console = CONS_SCREEN_TEXT;
if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) {
extern void *defcons_init(size_t);
defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
return;
}
for (i = 0; devnames[i] != NULL; i++) {
cons = lookup_console_device(devnames[i], &ttyn);
if (cons != CONS_INVALID)
break;
}
if (cons == CONS_INVALID) {
if (console == CONS_TTY && !bootprop_set_tty_mode)
serial_init();
return;
}
#if defined(__xpv)
if (cons == console_hypervisor_device) {
cons = CONS_HYPERVISOR;
console_hypervisor_redirect = B_TRUE;
}
#endif
console = cons;
if (console == CONS_TTY) {
tty_num = ttyn;
serial_init();
}
}
#if defined(__xpv)
boolean_t
bcons_hypervisor_redirect(void)
{
return (console_hypervisor_redirect);
}
void
bcons_device_change(int new_console)
{
if (new_console < CONS_MIN || new_console > CONS_MAX)
return;
if (new_console == CONS_HYPERVISOR)
new_console = console_hypervisor_device;
console = new_console;
if (new_console == CONS_TTY) {
tty_num = console_hypervisor_tty_num;
serial_init();
}
}
#endif
static void
defcons_putchar(int c)
{
if (defcons_buf != NULL &&
defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
*defcons_cur++ = c;
*defcons_cur = 0;
}
}
#endif