Changeset View
Changeset View
Standalone View
Standalone View
head/sys/boot/efi/libefi/efi_console.c
Show All 29 Lines | |||||
#include <efi.h> | #include <efi.h> | ||||
#include <efilib.h> | #include <efilib.h> | ||||
#include "bootstrap.h" | #include "bootstrap.h" | ||||
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; | static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; | ||||
static SIMPLE_INPUT_INTERFACE *conin; | static SIMPLE_INPUT_INTERFACE *conin; | ||||
#ifdef TERM_EMU | |||||
#define DEFAULT_FGCOLOR EFI_LIGHTGRAY | |||||
#define DEFAULT_BGCOLOR EFI_BLACK | |||||
#define MAXARGS 8 | |||||
static int args[MAXARGS], argc; | |||||
static int fg_c, bg_c, curx, cury; | |||||
static int esc; | |||||
void get_pos(int *x, int *y); | |||||
void curs_move(int *_x, int *_y, int x, int y); | |||||
static void CL(int); | |||||
#endif | |||||
static void efi_cons_probe(struct console *); | |||||
static int efi_cons_init(int); | |||||
void efi_cons_putchar(int); | |||||
int efi_cons_getchar(void); | |||||
void efi_cons_efiputchar(int); | |||||
int efi_cons_poll(void); | |||||
struct console efi_console = { | |||||
"efi", | |||||
"EFI console", | |||||
0, | |||||
efi_cons_probe, | |||||
efi_cons_init, | |||||
efi_cons_putchar, | |||||
efi_cons_getchar, | |||||
efi_cons_poll | |||||
}; | |||||
#ifdef TERM_EMU | |||||
/* Get cursor position. */ | |||||
void | |||||
get_pos(int *x, int *y) | |||||
{ | |||||
*x = conout->Mode->CursorColumn; | |||||
*y = conout->Mode->CursorRow; | |||||
} | |||||
/* Move cursor to x rows and y cols (0-based). */ | |||||
void | |||||
curs_move(int *_x, int *_y, int x, int y) | |||||
{ | |||||
conout->SetCursorPosition(conout, x, y); | |||||
if (_x != NULL) | |||||
*_x = conout->Mode->CursorColumn; | |||||
if (_y != NULL) | |||||
*_y = conout->Mode->CursorRow; | |||||
} | |||||
/* Clear internal state of the terminal emulation code. */ | |||||
void | |||||
end_term(void) | |||||
{ | |||||
esc = 0; | |||||
argc = -1; | |||||
} | |||||
#endif | |||||
static void | static void | ||||
efi_cons_probe(struct console *cp) | efi_cons_probe(struct console *cp) | ||||
{ | { | ||||
conout = ST->ConOut; | conout = ST->ConOut; | ||||
conin = ST->ConIn; | conin = ST->ConIn; | ||||
cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; | cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; | ||||
} | } | ||||
static int | static int | ||||
efi_cons_init(int arg) | efi_cons_init(int arg) | ||||
{ | { | ||||
conout->SetAttribute(conout, EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK)); | conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, | ||||
DEFAULT_BGCOLOR)); | |||||
#ifdef TERM_EMU | |||||
end_term(); | |||||
get_pos(&curx, &cury); | |||||
curs_move(&curx, &cury, curx, cury); | |||||
fg_c = DEFAULT_FGCOLOR; | |||||
bg_c = DEFAULT_BGCOLOR; | |||||
#endif | |||||
conout->EnableCursor(conout, TRUE); | |||||
return 0; | return 0; | ||||
} | } | ||||
void | static void | ||||
efi_cons_putchar(int c) | efi_cons_rawputchar(int c) | ||||
{ | { | ||||
CHAR16 buf[2]; | int i; | ||||
UINTN x, y; | |||||
conout->QueryMode(conout, conout->Mode->Mode, &x, &y); | |||||
if (c == '\t') | |||||
/* XXX lame tab expansion */ | |||||
for (i = 0; i < 8; i++) | |||||
efi_cons_rawputchar(' '); | |||||
else { | |||||
#ifndef TERM_EMU | |||||
if (c == '\n') | if (c == '\n') | ||||
efi_cons_putchar('\r'); | efi_cons_efiputchar('\r'); | ||||
else | |||||
efi_cons_efiputchar(c); | |||||
#else | |||||
switch (c) { | |||||
case '\r': | |||||
curx = 0; | |||||
curs_move(&curx, &cury, curx, cury); | |||||
return; | |||||
case '\n': | |||||
cury++; | |||||
if (cury >= y) { | |||||
efi_cons_efiputchar('\n'); | |||||
cury--; | |||||
} else | |||||
curs_move(&curx, &cury, curx, cury); | |||||
return; | |||||
case '\b': | |||||
if (curx > 0) { | |||||
curx--; | |||||
curs_move(&curx, &cury, curx, cury); | |||||
} | |||||
return; | |||||
default: | |||||
efi_cons_efiputchar(c); | |||||
curx++; | |||||
if (curx > x-1) { | |||||
curx = 0; | |||||
cury++; | |||||
} | |||||
if (cury > y-1) { | |||||
curx = 0; | |||||
cury--; | |||||
} | |||||
} | |||||
curs_move(&curx, &cury, curx, cury); | |||||
#endif | |||||
} | |||||
} | |||||
buf[0] = c; | /* Gracefully exit ESC-sequence processing in case of misunderstanding. */ | ||||
buf[1] = 0; | static void | ||||
bail_out(int c) | |||||
{ | |||||
char buf[16], *ch; | |||||
int i; | |||||
conout->OutputString(conout, buf); | if (esc) { | ||||
efi_cons_rawputchar('\033'); | |||||
if (esc != '\033') | |||||
efi_cons_rawputchar(esc); | |||||
for (i = 0; i <= argc; ++i) { | |||||
sprintf(buf, "%d", args[i]); | |||||
ch = buf; | |||||
while (*ch) | |||||
efi_cons_rawputchar(*ch++); | |||||
} | } | ||||
} | |||||
efi_cons_rawputchar(c); | |||||
end_term(); | |||||
} | |||||
/* Clear display from current position to end of screen. */ | |||||
static void | |||||
CD(void) { | |||||
int i; | |||||
UINTN x, y; | |||||
get_pos(&curx, &cury); | |||||
if (curx == 0 && cury == 0) { | |||||
conout->ClearScreen(conout); | |||||
end_term(); | |||||
return; | |||||
} | |||||
conout->QueryMode(conout, conout->Mode->Mode, &x, &y); | |||||
CL(0); /* clear current line from cursor to end */ | |||||
for (i = cury + 1; i < y-1; i++) { | |||||
curs_move(NULL, NULL, 0, i); | |||||
CL(0); | |||||
} | |||||
curs_move(NULL, NULL, curx, cury); | |||||
end_term(); | |||||
} | |||||
/* | |||||
* Absolute cursor move to args[0] rows and args[1] columns | |||||
* (the coordinates are 1-based). | |||||
*/ | |||||
static void | |||||
CM(void) | |||||
{ | |||||
if (args[0] > 0) | |||||
args[0]--; | |||||
if (args[1] > 0) | |||||
args[1]--; | |||||
curs_move(&curx, &cury, args[1], args[0]); | |||||
end_term(); | |||||
} | |||||
/* Home cursor (left top corner), also called from mode command. */ | |||||
void | |||||
HO(void) | |||||
{ | |||||
argc = 1; | |||||
args[0] = args[1] = 1; | |||||
CM(); | |||||
} | |||||
/* Clear line from current position to end of line */ | |||||
static void | |||||
CL(int direction) | |||||
{ | |||||
int i, len; | |||||
UINTN x, y; | |||||
CHAR16 *line; | |||||
conout->QueryMode(conout, conout->Mode->Mode, &x, &y); | |||||
switch (direction) { | |||||
case 0: /* from cursor to end */ | |||||
len = x - curx + 1; | |||||
break; | |||||
case 1: /* from beginning to cursor */ | |||||
len = curx; | |||||
break; | |||||
case 2: /* entire line */ | |||||
len = x; | |||||
break; | |||||
} | |||||
if (cury == y - 1) | |||||
len--; | |||||
line = malloc(len * sizeof (CHAR16)); | |||||
if (line == NULL) { | |||||
printf("out of memory\n"); | |||||
return; | |||||
} | |||||
for (i = 0; i < len; i++) | |||||
line[i] = ' '; | |||||
line[len-1] = 0; | |||||
if (direction != 0) | |||||
curs_move(NULL, NULL, 0, cury); | |||||
conout->OutputString(conout, line); | |||||
/* restore cursor position */ | |||||
curs_move(NULL, NULL, curx, cury); | |||||
free(line); | |||||
end_term(); | |||||
} | |||||
static void | |||||
get_arg(int c) | |||||
{ | |||||
if (argc < 0) | |||||
argc = 0; | |||||
args[argc] *= 10; | |||||
args[argc] += c - '0'; | |||||
} | |||||
/* Emulate basic capabilities of cons25 terminal */ | |||||
static void | |||||
efi_term_emu(int c) | |||||
{ | |||||
static int ansi_col[] = { | |||||
0, 4, 2, 6, 1, 5, 3, 7 | |||||
}; | |||||
int t, i; | |||||
switch (esc) { | |||||
case 0: | |||||
switch (c) { | |||||
case '\033': | |||||
esc = c; | |||||
break; | |||||
default: | |||||
efi_cons_rawputchar(c); | |||||
break; | |||||
} | |||||
break; | |||||
case '\033': | |||||
switch (c) { | |||||
case '[': | |||||
esc = c; | |||||
args[0] = 0; | |||||
argc = -1; | |||||
break; | |||||
default: | |||||
bail_out(c); | |||||
break; | |||||
} | |||||
break; | |||||
case '[': | |||||
switch (c) { | |||||
case ';': | |||||
if (argc < 0) | |||||
argc = 0; | |||||
else if (argc + 1 >= MAXARGS) | |||||
bail_out(c); | |||||
else | |||||
args[++argc] = 0; | |||||
break; | |||||
case 'H': /* ho = \E[H */ | |||||
if (argc < 0) | |||||
HO(); | |||||
else if (argc == 1) | |||||
CM(); | |||||
else | |||||
bail_out(c); | |||||
break; | |||||
case 'J': /* cd = \E[J */ | |||||
if (argc < 0) | |||||
CD(); | |||||
else | |||||
bail_out(c); | |||||
break; | |||||
case 'm': | |||||
if (argc < 0) { | |||||
fg_c = DEFAULT_FGCOLOR; | |||||
bg_c = DEFAULT_BGCOLOR; | |||||
} | |||||
for (i = 0; i <= argc; ++i) { | |||||
switch (args[i]) { | |||||
case 0: /* back to normal */ | |||||
fg_c = DEFAULT_FGCOLOR; | |||||
bg_c = DEFAULT_BGCOLOR; | |||||
break; | |||||
case 1: /* bold */ | |||||
fg_c |= 0x8; | |||||
break; | |||||
case 4: /* underline */ | |||||
case 5: /* blink */ | |||||
bg_c |= 0x8; | |||||
break; | |||||
case 7: /* reverse */ | |||||
t = fg_c; | |||||
fg_c = bg_c; | |||||
bg_c = t; | |||||
break; | |||||
case 30: case 31: case 32: case 33: | |||||
case 34: case 35: case 36: case 37: | |||||
fg_c = ansi_col[args[i] - 30]; | |||||
break; | |||||
case 39: /* normal */ | |||||
fg_c = DEFAULT_FGCOLOR; | |||||
break; | |||||
case 40: case 41: case 42: case 43: | |||||
case 44: case 45: case 46: case 47: | |||||
bg_c = ansi_col[args[i] - 40]; | |||||
break; | |||||
case 49: /* normal */ | |||||
bg_c = DEFAULT_BGCOLOR; | |||||
break; | |||||
} | |||||
} | |||||
conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); | |||||
end_term(); | |||||
break; | |||||
default: | |||||
if (isdigit(c)) | |||||
get_arg(c); | |||||
else | |||||
bail_out(c); | |||||
break; | |||||
} | |||||
break; | |||||
default: | |||||
bail_out(c); | |||||
break; | |||||
} | |||||
} | |||||
void | |||||
efi_cons_putchar(int c) | |||||
{ | |||||
#ifdef TERM_EMU | |||||
efi_term_emu(c); | |||||
#else | |||||
efi_cons_rawputchar(c); | |||||
#endif | |||||
} | |||||
int | int | ||||
efi_cons_getchar() | efi_cons_getchar() | ||||
{ | { | ||||
EFI_INPUT_KEY key; | EFI_INPUT_KEY key; | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
UINTN junk; | UINTN junk; | ||||
/* Try to read a key stroke. We wait for one if none is pending. */ | /* Try to read a key stroke. We wait for one if none is pending. */ | ||||
status = conin->ReadKeyStroke(conin, &key); | status = conin->ReadKeyStroke(conin, &key); | ||||
if (status == EFI_NOT_READY) { | if (status == EFI_NOT_READY) { | ||||
BS->WaitForEvent(1, &conin->WaitForKey, &junk); | BS->WaitForEvent(1, &conin->WaitForKey, &junk); | ||||
status = conin->ReadKeyStroke(conin, &key); | status = conin->ReadKeyStroke(conin, &key); | ||||
} | } | ||||
switch (key.ScanCode) { | |||||
case 0x17: /* ESC */ | |||||
return (0x1b); /* esc */ | |||||
} | |||||
/* this can return */ | |||||
return (key.UnicodeChar); | return (key.UnicodeChar); | ||||
} | } | ||||
int | int | ||||
efi_cons_poll() | efi_cons_poll() | ||||
{ | { | ||||
/* This can clear the signaled state. */ | /* This can clear the signaled state. */ | ||||
return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); | return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); | ||||
} | } | ||||
struct console efi_console = { | /* Plain direct access to EFI OutputString(). */ | ||||
"efi", | void | ||||
"EFI console", | efi_cons_efiputchar(int c) | ||||
0, | { | ||||
efi_cons_probe, | CHAR16 buf[2]; | ||||
efi_cons_init, | |||||
efi_cons_putchar, | /* | ||||
efi_cons_getchar, | * translate box chars to unicode | ||||
efi_cons_poll | */ | ||||
}; | switch (c) { | ||||
/* single frame */ | |||||
case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; | |||||
case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; | |||||
case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; | |||||
case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; | |||||
case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; | |||||
case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; | |||||
/* double frame */ | |||||
case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; | |||||
case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; | |||||
case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; | |||||
case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; | |||||
case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; | |||||
case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; | |||||
default: | |||||
buf[0] = c; | |||||
} | |||||
buf[1] = 0; /* terminate string */ | |||||
conout->OutputString(conout, buf); | |||||
} |