1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 2000 Doug Rabson 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7ca987d46SWarner Losh * are met: 8ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13ca987d46SWarner Losh * 14ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca987d46SWarner Losh * SUCH DAMAGE. 25ca987d46SWarner Losh */ 26ca987d46SWarner Losh 273630506bSToomas Soome #include <sys/param.h> 28ca987d46SWarner Losh #include <efi.h> 29ca987d46SWarner Losh #include <efilib.h> 3056758831SToomas Soome #include <teken.h> 31b9f745fdSToomas Soome #include <sys/reboot.h> 323630506bSToomas Soome #include <machine/metadata.h> 333630506bSToomas Soome #include <gfx_fb.h> 3450180d2bSToomas Soome #include <framebuffer.h> 35ca987d46SWarner Losh #include "bootstrap.h" 36ca987d46SWarner Losh 373630506bSToomas Soome extern EFI_GUID gop_guid; 38305ef653SWarner Losh 39305ef653SWarner Losh bool boot_services_active = true; /* boot services active first thing in main */ 40305ef653SWarner Losh 4105b24e86SToomas Soome static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; 42ca987d46SWarner Losh static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 43ca987d46SWarner Losh static SIMPLE_INPUT_INTERFACE *conin; 4405b24e86SToomas Soome static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; 453630506bSToomas Soome static bool efi_started; 46b9f745fdSToomas Soome static int mode; /* Does ConOut have serial console? */ 47b9f745fdSToomas Soome 48b9f745fdSToomas Soome static uint32_t utf8_left; 49b9f745fdSToomas Soome static uint32_t utf8_partial; 50b9f745fdSToomas Soome #ifdef TERM_EMU 51b9f745fdSToomas Soome #define DEFAULT_FGCOLOR EFI_LIGHTGRAY 52b9f745fdSToomas Soome #define DEFAULT_BGCOLOR EFI_BLACK 53b9f745fdSToomas Soome 54b9f745fdSToomas Soome #define MAXARGS 8 55b9f745fdSToomas Soome static int args[MAXARGS], argc; 56b9f745fdSToomas Soome static int fg_c, bg_c, curx, cury; 57b9f745fdSToomas Soome static int esc; 58b9f745fdSToomas Soome 59b9f745fdSToomas Soome void get_pos(int *x, int *y); 60b9f745fdSToomas Soome void curs_move(int *_x, int *_y, int x, int y); 61b9f745fdSToomas Soome static void CL(int); 62b9f745fdSToomas Soome void HO(void); 63b9f745fdSToomas Soome void end_term(void); 64b9f745fdSToomas Soome #endif 65b9f745fdSToomas Soome 66*3b68c491SAhmad Khalifa #define TEXT_ROWS 25 673630506bSToomas Soome #define TEXT_COLS 80 683630506bSToomas Soome 6956758831SToomas Soome static tf_bell_t efi_cons_bell; 7056758831SToomas Soome static tf_cursor_t efi_text_cursor; 7156758831SToomas Soome static tf_putchar_t efi_text_putchar; 7256758831SToomas Soome static tf_fill_t efi_text_fill; 7356758831SToomas Soome static tf_copy_t efi_text_copy; 7456758831SToomas Soome static tf_param_t efi_text_param; 7556758831SToomas Soome static tf_respond_t efi_cons_respond; 76ca987d46SWarner Losh 7756758831SToomas Soome static teken_funcs_t tf = { 7856758831SToomas Soome .tf_bell = efi_cons_bell, 7956758831SToomas Soome .tf_cursor = efi_text_cursor, 8056758831SToomas Soome .tf_putchar = efi_text_putchar, 8156758831SToomas Soome .tf_fill = efi_text_fill, 8256758831SToomas Soome .tf_copy = efi_text_copy, 8356758831SToomas Soome .tf_param = efi_text_param, 8456758831SToomas Soome .tf_respond = efi_cons_respond, 8556758831SToomas Soome }; 86ca987d46SWarner Losh 873630506bSToomas Soome static teken_funcs_t tfx = { 883630506bSToomas Soome .tf_bell = efi_cons_bell, 893630506bSToomas Soome .tf_cursor = gfx_fb_cursor, 903630506bSToomas Soome .tf_putchar = gfx_fb_putchar, 913630506bSToomas Soome .tf_fill = gfx_fb_fill, 923630506bSToomas Soome .tf_copy = gfx_fb_copy, 933630506bSToomas Soome .tf_param = gfx_fb_param, 943630506bSToomas Soome .tf_respond = efi_cons_respond, 9556758831SToomas Soome }; 9656758831SToomas Soome 97fb0df666SToomas Soome #define KEYBUFSZ 10 98fb0df666SToomas Soome static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ 99ca987d46SWarner Losh static int key_pending; 100ca987d46SWarner Losh 10156758831SToomas Soome static const unsigned char teken_color_to_efi_color[16] = { 10256758831SToomas Soome EFI_BLACK, 10356758831SToomas Soome EFI_RED, 10456758831SToomas Soome EFI_GREEN, 10556758831SToomas Soome EFI_BROWN, 10656758831SToomas Soome EFI_BLUE, 10756758831SToomas Soome EFI_MAGENTA, 10856758831SToomas Soome EFI_CYAN, 10956758831SToomas Soome EFI_LIGHTGRAY, 11056758831SToomas Soome EFI_DARKGRAY, 11156758831SToomas Soome EFI_LIGHTRED, 11256758831SToomas Soome EFI_LIGHTGREEN, 11356758831SToomas Soome EFI_YELLOW, 11456758831SToomas Soome EFI_LIGHTBLUE, 11556758831SToomas Soome EFI_LIGHTMAGENTA, 11656758831SToomas Soome EFI_LIGHTCYAN, 11756758831SToomas Soome EFI_WHITE 11856758831SToomas Soome }; 11956758831SToomas Soome 120ca987d46SWarner Losh static void efi_cons_probe(struct console *); 121ca987d46SWarner Losh static int efi_cons_init(int); 122ca987d46SWarner Losh void efi_cons_putchar(int); 123ca987d46SWarner Losh int efi_cons_getchar(void); 124ca987d46SWarner Losh void efi_cons_efiputchar(int); 125ca987d46SWarner Losh int efi_cons_poll(void); 1263630506bSToomas Soome static void cons_draw_frame(teken_attr_t *); 127ca987d46SWarner Losh 128ca987d46SWarner Losh struct console efi_console = { 129b3551da9SWarner Losh .c_name = "efi", 130b3551da9SWarner Losh .c_desc = "EFI console", 131b3551da9SWarner Losh .c_flags = C_WIDEOUT, 132b3551da9SWarner Losh .c_probe = efi_cons_probe, 133b3551da9SWarner Losh .c_init = efi_cons_init, 134b3551da9SWarner Losh .c_out = efi_cons_putchar, 135b3551da9SWarner Losh .c_in = efi_cons_getchar, 136b3551da9SWarner Losh .c_ready = efi_cons_poll 137ca987d46SWarner Losh }; 138ca987d46SWarner Losh 13956758831SToomas Soome /* 1403630506bSToomas Soome * This function is used to mark a rectangular image area so the scrolling 1413630506bSToomas Soome * will know we need to copy the data from there. 1423630506bSToomas Soome */ 1433630506bSToomas Soome void 1443630506bSToomas Soome term_image_display(teken_gfx_t *state, const teken_rect_t *r) 1453630506bSToomas Soome { 1463630506bSToomas Soome teken_pos_t p; 1473630506bSToomas Soome int idx; 1483630506bSToomas Soome 14989632acbSToomas Soome if (screen_buffer == NULL) 15089632acbSToomas Soome return; 15189632acbSToomas Soome 1523630506bSToomas Soome for (p.tp_row = r->tr_begin.tp_row; 1533630506bSToomas Soome p.tp_row < r->tr_end.tp_row; p.tp_row++) { 1543630506bSToomas Soome for (p.tp_col = r->tr_begin.tp_col; 1553630506bSToomas Soome p.tp_col < r->tr_end.tp_col; p.tp_col++) { 1563630506bSToomas Soome idx = p.tp_col + p.tp_row * state->tg_tp.tp_col; 1573630506bSToomas Soome if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) 1583630506bSToomas Soome return; 1593630506bSToomas Soome screen_buffer[idx].a.ta_format |= TF_IMAGE; 1603630506bSToomas Soome } 1613630506bSToomas Soome } 1623630506bSToomas Soome } 1633630506bSToomas Soome 1643630506bSToomas Soome /* 16556758831SToomas Soome * Not implemented. 16656758831SToomas Soome */ 16756758831SToomas Soome static void 16856758831SToomas Soome efi_cons_bell(void *s __unused) 169ca987d46SWarner Losh { 170ca987d46SWarner Losh } 171ca987d46SWarner Losh 17256758831SToomas Soome static void 1733630506bSToomas Soome efi_text_cursor(void *arg, const teken_pos_t *p) 174ca987d46SWarner Losh { 1753630506bSToomas Soome teken_gfx_t *state = arg; 1763630506bSToomas Soome UINTN col, row; 17756758831SToomas Soome 178305ef653SWarner Losh if (!boot_services_active) 1794c7a3a70SToomas Soome return; 1804c7a3a70SToomas Soome 18156758831SToomas Soome row = p->tp_row; 1823630506bSToomas Soome if (p->tp_row >= state->tg_tp.tp_row) 1833630506bSToomas Soome row = state->tg_tp.tp_row - 1; 1843630506bSToomas Soome 1853630506bSToomas Soome col = p->tp_col; 1863630506bSToomas Soome if (p->tp_col >= state->tg_tp.tp_col) 1873630506bSToomas Soome col = state->tg_tp.tp_col - 1; 18856758831SToomas Soome 18956758831SToomas Soome conout->SetCursorPosition(conout, col, row); 190ca987d46SWarner Losh } 191ca987d46SWarner Losh 19256758831SToomas Soome static void 1933630506bSToomas Soome efi_text_printchar(teken_gfx_t *state, const teken_pos_t *p, bool autoscroll) 194ca987d46SWarner Losh { 19556758831SToomas Soome UINTN a, attr; 19656758831SToomas Soome struct text_pixel *px; 19756758831SToomas Soome teken_color_t fg, bg, tmp; 19856758831SToomas Soome 1993630506bSToomas Soome px = screen_buffer + p->tp_col + p->tp_row * state->tg_tp.tp_col; 20056758831SToomas Soome a = conout->Mode->Attribute; 20156758831SToomas Soome 20256758831SToomas Soome fg = teken_256to16(px->a.ta_fgcolor); 20356758831SToomas Soome bg = teken_256to16(px->a.ta_bgcolor); 20456758831SToomas Soome if (px->a.ta_format & TF_BOLD) 20556758831SToomas Soome fg |= TC_LIGHT; 20656758831SToomas Soome if (px->a.ta_format & TF_BLINK) 20756758831SToomas Soome bg |= TC_LIGHT; 20856758831SToomas Soome 20956758831SToomas Soome if (px->a.ta_format & TF_REVERSE) { 21056758831SToomas Soome tmp = fg; 21156758831SToomas Soome fg = bg; 21256758831SToomas Soome bg = tmp; 213ca987d46SWarner Losh } 214ca987d46SWarner Losh 21556758831SToomas Soome attr = EFI_TEXT_ATTR(teken_color_to_efi_color[fg], 21621388f5cSToomas Soome teken_color_to_efi_color[bg] & 0x7); 21756758831SToomas Soome 21856758831SToomas Soome conout->SetCursorPosition(conout, p->tp_col, p->tp_row); 21956758831SToomas Soome 2203630506bSToomas Soome /* to prevent autoscroll, skip print of lower right char */ 22103c9cdf7SToomas Soome if (!autoscroll && 2223630506bSToomas Soome p->tp_row == state->tg_tp.tp_row - 1 && 2233630506bSToomas Soome p->tp_col == state->tg_tp.tp_col - 1) 22456758831SToomas Soome return; 22556758831SToomas Soome 22656758831SToomas Soome (void) conout->SetAttribute(conout, attr); 22756758831SToomas Soome efi_cons_efiputchar(px->c); 22856758831SToomas Soome (void) conout->SetAttribute(conout, a); 22956758831SToomas Soome } 23056758831SToomas Soome 23156758831SToomas Soome static void 2323630506bSToomas Soome efi_text_putchar(void *s, const teken_pos_t *p, teken_char_t c, 23356758831SToomas Soome const teken_attr_t *a) 23456758831SToomas Soome { 2353630506bSToomas Soome teken_gfx_t *state = s; 23656758831SToomas Soome EFI_STATUS status; 23756758831SToomas Soome int idx; 23856758831SToomas Soome 239305ef653SWarner Losh if (!boot_services_active) 2404c7a3a70SToomas Soome return; 2414c7a3a70SToomas Soome 2423630506bSToomas Soome idx = p->tp_col + p->tp_row * state->tg_tp.tp_col; 2433630506bSToomas Soome if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) 2443630506bSToomas Soome return; 2453630506bSToomas Soome 2463630506bSToomas Soome screen_buffer[idx].c = c; 2473630506bSToomas Soome screen_buffer[idx].a = *a; 2483630506bSToomas Soome 2493630506bSToomas Soome efi_text_printchar(s, p, false); 25056758831SToomas Soome } 25156758831SToomas Soome 25256758831SToomas Soome static void 2533630506bSToomas Soome efi_text_fill(void *arg, const teken_rect_t *r, teken_char_t c, 25456758831SToomas Soome const teken_attr_t *a) 25556758831SToomas Soome { 2563630506bSToomas Soome teken_gfx_t *state = arg; 25756758831SToomas Soome teken_pos_t p; 25856758831SToomas Soome 259305ef653SWarner Losh if (!boot_services_active) 2604c7a3a70SToomas Soome return; 2614c7a3a70SToomas Soome 2623630506bSToomas Soome if (state->tg_cursor_visible) 26356758831SToomas Soome conout->EnableCursor(conout, FALSE); 26456758831SToomas Soome for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; 26556758831SToomas Soome p.tp_row++) 26656758831SToomas Soome for (p.tp_col = r->tr_begin.tp_col; 26756758831SToomas Soome p.tp_col < r->tr_end.tp_col; p.tp_col++) 2683630506bSToomas Soome efi_text_putchar(state, &p, c, a); 2693630506bSToomas Soome if (state->tg_cursor_visible) 27056758831SToomas Soome conout->EnableCursor(conout, TRUE); 27156758831SToomas Soome } 27256758831SToomas Soome 2733630506bSToomas Soome static void 2743630506bSToomas Soome efi_text_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s, 2753630506bSToomas Soome teken_pos_t *d, bool scroll) 27656758831SToomas Soome { 2773630506bSToomas Soome unsigned soffset, doffset; 2783630506bSToomas Soome teken_pos_t sp, dp; 2793630506bSToomas Soome int x; 28056758831SToomas Soome 2813630506bSToomas Soome soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col; 2823630506bSToomas Soome doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col; 28356758831SToomas Soome 2843630506bSToomas Soome sp = *s; 2853630506bSToomas Soome dp = *d; 2863630506bSToomas Soome for (x = 0; x < ncol; x++) { 2873630506bSToomas Soome sp.tp_col = s->tp_col + x; 2883630506bSToomas Soome dp.tp_col = d->tp_col + x; 2893630506bSToomas Soome if (!is_same_pixel(&screen_buffer[soffset + x], 2903630506bSToomas Soome &screen_buffer[doffset + x])) { 2913630506bSToomas Soome screen_buffer[doffset + x] = 2923630506bSToomas Soome screen_buffer[soffset + x]; 2933630506bSToomas Soome if (!scroll) 2943630506bSToomas Soome efi_text_printchar(state, &dp, false); 2953630506bSToomas Soome } else if (scroll) { 2963630506bSToomas Soome /* Draw last char and trigger scroll. */ 2973630506bSToomas Soome if (dp.tp_col + 1 == state->tg_tp.tp_col && 2983630506bSToomas Soome dp.tp_row + 1 == state->tg_tp.tp_row) { 2993630506bSToomas Soome efi_text_printchar(state, &dp, true); 3003630506bSToomas Soome } 3013630506bSToomas Soome } 3023630506bSToomas Soome } 30356758831SToomas Soome } 30456758831SToomas Soome 30556758831SToomas Soome static void 3063630506bSToomas Soome efi_text_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) 30756758831SToomas Soome { 3083630506bSToomas Soome teken_gfx_t *state = arg; 3093630506bSToomas Soome unsigned doffset, soffset; 31056758831SToomas Soome teken_pos_t d, s; 3113630506bSToomas Soome int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ 31203c9cdf7SToomas Soome bool scroll = false; 31356758831SToomas Soome 314305ef653SWarner Losh if (!boot_services_active) 3154c7a3a70SToomas Soome return; 3164c7a3a70SToomas Soome 31756758831SToomas Soome /* 31856758831SToomas Soome * Copying is a little tricky. We must make sure we do it in 31956758831SToomas Soome * correct order, to make sure we don't overwrite our own data. 32056758831SToomas Soome */ 32156758831SToomas Soome 32256758831SToomas Soome nrow = r->tr_end.tp_row - r->tr_begin.tp_row; 32356758831SToomas Soome ncol = r->tr_end.tp_col - r->tr_begin.tp_col; 32456758831SToomas Soome 32503c9cdf7SToomas Soome /* 32603c9cdf7SToomas Soome * Check if we do copy whole screen. 32703c9cdf7SToomas Soome */ 32803c9cdf7SToomas Soome if (p->tp_row == 0 && p->tp_col == 0 && 3293630506bSToomas Soome nrow == state->tg_tp.tp_row - 2 && ncol == state->tg_tp.tp_col - 2) 33003c9cdf7SToomas Soome scroll = true; 33103c9cdf7SToomas Soome 3323630506bSToomas Soome soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col; 3333630506bSToomas Soome doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col; 3343630506bSToomas Soome 3353630506bSToomas Soome /* remove the cursor */ 3363630506bSToomas Soome if (state->tg_cursor_visible) 33756758831SToomas Soome conout->EnableCursor(conout, FALSE); 33856758831SToomas Soome 33903c9cdf7SToomas Soome /* 3403630506bSToomas Soome * Copy line by line. 34103c9cdf7SToomas Soome */ 3423630506bSToomas Soome if (doffset <= soffset) { 3433630506bSToomas Soome s = r->tr_begin; 3443630506bSToomas Soome d = *p; 3453630506bSToomas Soome for (y = 0; y < nrow; y++) { 3463630506bSToomas Soome s.tp_row = r->tr_begin.tp_row + y; 3473630506bSToomas Soome d.tp_row = p->tp_row + y; 3483630506bSToomas Soome 3493630506bSToomas Soome efi_text_copy_line(state, ncol, &s, &d, scroll); 35056758831SToomas Soome } 35156758831SToomas Soome } else { 35256758831SToomas Soome for (y = nrow - 1; y >= 0; y--) { 35356758831SToomas Soome s.tp_row = r->tr_begin.tp_row + y; 35456758831SToomas Soome d.tp_row = p->tp_row + y; 35556758831SToomas Soome 3563630506bSToomas Soome efi_text_copy_line(state, ncol, &s, &d, false); 35756758831SToomas Soome } 35856758831SToomas Soome } 3593630506bSToomas Soome 3603630506bSToomas Soome /* display the cursor */ 3613630506bSToomas Soome if (state->tg_cursor_visible) 36256758831SToomas Soome conout->EnableCursor(conout, TRUE); 36356758831SToomas Soome } 36456758831SToomas Soome 36556758831SToomas Soome static void 3663630506bSToomas Soome efi_text_param(void *arg, int cmd, unsigned int value) 36756758831SToomas Soome { 3683630506bSToomas Soome teken_gfx_t *state = arg; 3693630506bSToomas Soome 370305ef653SWarner Losh if (!boot_services_active) 3714c7a3a70SToomas Soome return; 3724c7a3a70SToomas Soome 37356758831SToomas Soome switch (cmd) { 37456758831SToomas Soome case TP_SETLOCALCURSOR: 37556758831SToomas Soome /* 37656758831SToomas Soome * 0 means normal (usually block), 1 means hidden, and 37756758831SToomas Soome * 2 means blinking (always block) for compatibility with 37856758831SToomas Soome * syscons. We don't support any changes except hiding, 37956758831SToomas Soome * so must map 2 to 0. 38056758831SToomas Soome */ 38156758831SToomas Soome value = (value == 1) ? 0 : 1; 38256758831SToomas Soome /* FALLTHROUGH */ 38356758831SToomas Soome case TP_SHOWCURSOR: 3843630506bSToomas Soome if (value != 0) { 38556758831SToomas Soome conout->EnableCursor(conout, TRUE); 3863630506bSToomas Soome state->tg_cursor_visible = true; 3873630506bSToomas Soome } else { 38856758831SToomas Soome conout->EnableCursor(conout, FALSE); 3893630506bSToomas Soome state->tg_cursor_visible = false; 3903630506bSToomas Soome } 39156758831SToomas Soome break; 39256758831SToomas Soome default: 39356758831SToomas Soome /* Not yet implemented */ 39456758831SToomas Soome break; 39556758831SToomas Soome } 39656758831SToomas Soome } 39756758831SToomas Soome 39856758831SToomas Soome /* 39956758831SToomas Soome * Not implemented. 40056758831SToomas Soome */ 40156758831SToomas Soome static void 40256758831SToomas Soome efi_cons_respond(void *s __unused, const void *buf __unused, 40356758831SToomas Soome size_t len __unused) 40456758831SToomas Soome { 40556758831SToomas Soome } 406ca987d46SWarner Losh 407ebe8cd79SToomas Soome /* 408ebe8cd79SToomas Soome * Set up conin/conout/coninex to make sure we have input ready. 409ebe8cd79SToomas Soome */ 410ca987d46SWarner Losh static void 411ca987d46SWarner Losh efi_cons_probe(struct console *cp) 412ca987d46SWarner Losh { 413ebe8cd79SToomas Soome EFI_STATUS status; 414ebe8cd79SToomas Soome 415ebe8cd79SToomas Soome conout = ST->ConOut; 416ebe8cd79SToomas Soome conin = ST->ConIn; 417ebe8cd79SToomas Soome 418db316236SToomas Soome /* 419db316236SToomas Soome * Call SetMode to work around buggy firmware. 420db316236SToomas Soome */ 421db316236SToomas Soome status = conout->SetMode(conout, conout->Mode->Mode); 422db316236SToomas Soome 423db316236SToomas Soome if (coninex == NULL) { 424db316236SToomas Soome status = BS->OpenProtocol(ST->ConsoleInHandle, 425db316236SToomas Soome &simple_input_ex_guid, (void **)&coninex, 426db316236SToomas Soome IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 427ebe8cd79SToomas Soome if (status != EFI_SUCCESS) 428ebe8cd79SToomas Soome coninex = NULL; 429db316236SToomas Soome } 430ebe8cd79SToomas Soome 431ca987d46SWarner Losh cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; 432ca987d46SWarner Losh } 433ca987d46SWarner Losh 434233ab015SToomas Soome static bool 435233ab015SToomas Soome color_name_to_teken(const char *name, int *val) 436233ab015SToomas Soome { 437425e57e7SEd Maste int light = 0; 438425e57e7SEd Maste if (strncasecmp(name, "light", 5) == 0) { 439425e57e7SEd Maste name += 5; 440425e57e7SEd Maste light = TC_LIGHT; 441425e57e7SEd Maste } else if (strncasecmp(name, "bright", 6) == 0) { 442425e57e7SEd Maste name += 6; 443425e57e7SEd Maste light = TC_LIGHT; 444425e57e7SEd Maste } 445233ab015SToomas Soome if (strcasecmp(name, "black") == 0) { 446425e57e7SEd Maste *val = TC_BLACK | light; 447233ab015SToomas Soome return (true); 448233ab015SToomas Soome } 449233ab015SToomas Soome if (strcasecmp(name, "red") == 0) { 450425e57e7SEd Maste *val = TC_RED | light; 451233ab015SToomas Soome return (true); 452233ab015SToomas Soome } 453233ab015SToomas Soome if (strcasecmp(name, "green") == 0) { 454425e57e7SEd Maste *val = TC_GREEN | light; 455233ab015SToomas Soome return (true); 456233ab015SToomas Soome } 457e9249ef9SEd Maste if (strcasecmp(name, "yellow") == 0 || strcasecmp(name, "brown") == 0) { 458cf8880d5SEd Maste *val = TC_YELLOW | light; 459233ab015SToomas Soome return (true); 460233ab015SToomas Soome } 461233ab015SToomas Soome if (strcasecmp(name, "blue") == 0) { 462425e57e7SEd Maste *val = TC_BLUE | light; 463233ab015SToomas Soome return (true); 464233ab015SToomas Soome } 465233ab015SToomas Soome if (strcasecmp(name, "magenta") == 0) { 466425e57e7SEd Maste *val = TC_MAGENTA | light; 467233ab015SToomas Soome return (true); 468233ab015SToomas Soome } 469233ab015SToomas Soome if (strcasecmp(name, "cyan") == 0) { 470425e57e7SEd Maste *val = TC_CYAN | light; 471233ab015SToomas Soome return (true); 472233ab015SToomas Soome } 473233ab015SToomas Soome if (strcasecmp(name, "white") == 0) { 474425e57e7SEd Maste *val = TC_WHITE | light; 475233ab015SToomas Soome return (true); 476233ab015SToomas Soome } 477233ab015SToomas Soome return (false); 478233ab015SToomas Soome } 479233ab015SToomas Soome 480233ab015SToomas Soome static int 481233ab015SToomas Soome efi_set_colors(struct env_var *ev, int flags, const void *value) 482233ab015SToomas Soome { 483233ab015SToomas Soome int val = 0; 484425e57e7SEd Maste char buf[3]; 485233ab015SToomas Soome const void *evalue; 486233ab015SToomas Soome const teken_attr_t *ap; 487233ab015SToomas Soome teken_attr_t a; 488233ab015SToomas Soome 489233ab015SToomas Soome if (value == NULL) 490233ab015SToomas Soome return (CMD_OK); 491233ab015SToomas Soome 492233ab015SToomas Soome if (color_name_to_teken(value, &val)) { 493233ab015SToomas Soome snprintf(buf, sizeof (buf), "%d", val); 494233ab015SToomas Soome evalue = buf; 495233ab015SToomas Soome } else { 496233ab015SToomas Soome char *end; 497425e57e7SEd Maste long lval; 498233ab015SToomas Soome 499233ab015SToomas Soome errno = 0; 500425e57e7SEd Maste lval = strtol(value, &end, 0); 501425e57e7SEd Maste if (errno != 0 || *end != '\0' || lval < 0 || lval > 15) { 502233ab015SToomas Soome printf("Allowed values are either ansi color name or " 503425e57e7SEd Maste "number from range [0-15].\n"); 504233ab015SToomas Soome return (CMD_OK); 505233ab015SToomas Soome } 506425e57e7SEd Maste val = (int)lval; 507233ab015SToomas Soome evalue = value; 508233ab015SToomas Soome } 509233ab015SToomas Soome 5103630506bSToomas Soome ap = teken_get_defattr(&gfx_state.tg_teken); 511233ab015SToomas Soome a = *ap; 512233ab015SToomas Soome if (strcmp(ev->ev_name, "teken.fg_color") == 0) { 513233ab015SToomas Soome /* is it already set? */ 514233ab015SToomas Soome if (ap->ta_fgcolor == val) 515233ab015SToomas Soome return (CMD_OK); 516233ab015SToomas Soome a.ta_fgcolor = val; 517233ab015SToomas Soome } 518233ab015SToomas Soome if (strcmp(ev->ev_name, "teken.bg_color") == 0) { 519233ab015SToomas Soome /* is it already set? */ 520233ab015SToomas Soome if (ap->ta_bgcolor == val) 521233ab015SToomas Soome return (CMD_OK); 522233ab015SToomas Soome a.ta_bgcolor = val; 523233ab015SToomas Soome } 5243630506bSToomas Soome 5253630506bSToomas Soome /* Improve visibility */ 5263630506bSToomas Soome if (a.ta_bgcolor == TC_WHITE) 5273630506bSToomas Soome a.ta_bgcolor |= TC_LIGHT; 5283630506bSToomas Soome 5293630506bSToomas Soome teken_set_defattr(&gfx_state.tg_teken, &a); 5303630506bSToomas Soome cons_draw_frame(&a); 531233ab015SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); 5323630506bSToomas Soome teken_input(&gfx_state.tg_teken, "\e[2J", 4); 533233ab015SToomas Soome return (CMD_OK); 534233ab015SToomas Soome } 535233ab015SToomas Soome 536b9f745fdSToomas Soome #ifdef TERM_EMU 537b9f745fdSToomas Soome /* Get cursor position. */ 538b9f745fdSToomas Soome void 539b9f745fdSToomas Soome get_pos(int *x, int *y) 540b9f745fdSToomas Soome { 541b9f745fdSToomas Soome *x = conout->Mode->CursorColumn; 542b9f745fdSToomas Soome *y = conout->Mode->CursorRow; 543b9f745fdSToomas Soome } 544b9f745fdSToomas Soome 545b9f745fdSToomas Soome /* Move cursor to x rows and y cols (0-based). */ 546b9f745fdSToomas Soome void 547b9f745fdSToomas Soome curs_move(int *_x, int *_y, int x, int y) 548b9f745fdSToomas Soome { 549b9f745fdSToomas Soome conout->SetCursorPosition(conout, x, y); 550b9f745fdSToomas Soome if (_x != NULL) 551b9f745fdSToomas Soome *_x = conout->Mode->CursorColumn; 552b9f745fdSToomas Soome if (_y != NULL) 553b9f745fdSToomas Soome *_y = conout->Mode->CursorRow; 554b9f745fdSToomas Soome } 555b9f745fdSToomas Soome 556b9f745fdSToomas Soome /* Clear internal state of the terminal emulation code. */ 557b9f745fdSToomas Soome void 558b9f745fdSToomas Soome end_term(void) 559b9f745fdSToomas Soome { 560b9f745fdSToomas Soome esc = 0; 561b9f745fdSToomas Soome argc = -1; 562b9f745fdSToomas Soome } 563b9f745fdSToomas Soome #endif 564b9f745fdSToomas Soome 565b9f745fdSToomas Soome static void 566b9f745fdSToomas Soome efi_cons_rawputchar(int c) 567b9f745fdSToomas Soome { 568b9f745fdSToomas Soome int i; 569b9f745fdSToomas Soome UINTN x, y; 570b9f745fdSToomas Soome conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 571b9f745fdSToomas Soome 572b9f745fdSToomas Soome if (c == '\t') { 573b9f745fdSToomas Soome int n; 574b9f745fdSToomas Soome 575b9f745fdSToomas Soome n = 8 - ((conout->Mode->CursorColumn + 8) % 8); 576b9f745fdSToomas Soome for (i = 0; i < n; i++) 577b9f745fdSToomas Soome efi_cons_rawputchar(' '); 578b9f745fdSToomas Soome } else { 579b9f745fdSToomas Soome #ifndef TERM_EMU 580b9f745fdSToomas Soome if (c == '\n') 581b9f745fdSToomas Soome efi_cons_efiputchar('\r'); 582b9f745fdSToomas Soome efi_cons_efiputchar(c); 583b9f745fdSToomas Soome #else 584b9f745fdSToomas Soome switch (c) { 585b9f745fdSToomas Soome case '\r': 586b9f745fdSToomas Soome curx = 0; 587b9f745fdSToomas Soome efi_cons_efiputchar('\r'); 588b9f745fdSToomas Soome return; 589b9f745fdSToomas Soome case '\n': 590b9f745fdSToomas Soome efi_cons_efiputchar('\n'); 591b9f745fdSToomas Soome efi_cons_efiputchar('\r'); 592b9f745fdSToomas Soome cury++; 593b9f745fdSToomas Soome if (cury >= y) 594b9f745fdSToomas Soome cury--; 595b9f745fdSToomas Soome curx = 0; 596b9f745fdSToomas Soome return; 597b9f745fdSToomas Soome case '\b': 598b9f745fdSToomas Soome if (curx > 0) { 599b9f745fdSToomas Soome efi_cons_efiputchar('\b'); 600b9f745fdSToomas Soome curx--; 601b9f745fdSToomas Soome } 602b9f745fdSToomas Soome return; 603b9f745fdSToomas Soome default: 604b9f745fdSToomas Soome efi_cons_efiputchar(c); 605b9f745fdSToomas Soome curx++; 606b9f745fdSToomas Soome if (curx > x-1) { 607b9f745fdSToomas Soome curx = 0; 608b9f745fdSToomas Soome cury++; 609b9f745fdSToomas Soome } 610b9f745fdSToomas Soome if (cury > y-1) { 611b9f745fdSToomas Soome curx = 0; 612b9f745fdSToomas Soome cury--; 613b9f745fdSToomas Soome } 614b9f745fdSToomas Soome } 615b9f745fdSToomas Soome #endif 616b9f745fdSToomas Soome } 617b9f745fdSToomas Soome conout->EnableCursor(conout, TRUE); 618b9f745fdSToomas Soome } 619b9f745fdSToomas Soome 620b9f745fdSToomas Soome #ifdef TERM_EMU 621b9f745fdSToomas Soome /* Gracefully exit ESC-sequence processing in case of misunderstanding. */ 622b9f745fdSToomas Soome static void 623b9f745fdSToomas Soome bail_out(int c) 624b9f745fdSToomas Soome { 625b9f745fdSToomas Soome char buf[16], *ch; 626b9f745fdSToomas Soome int i; 627b9f745fdSToomas Soome 628b9f745fdSToomas Soome if (esc) { 629b9f745fdSToomas Soome efi_cons_rawputchar('\033'); 630b9f745fdSToomas Soome if (esc != '\033') 631b9f745fdSToomas Soome efi_cons_rawputchar(esc); 632b9f745fdSToomas Soome for (i = 0; i <= argc; ++i) { 633b9f745fdSToomas Soome sprintf(buf, "%d", args[i]); 634b9f745fdSToomas Soome ch = buf; 635b9f745fdSToomas Soome while (*ch) 636b9f745fdSToomas Soome efi_cons_rawputchar(*ch++); 637b9f745fdSToomas Soome } 638b9f745fdSToomas Soome } 639b9f745fdSToomas Soome efi_cons_rawputchar(c); 640b9f745fdSToomas Soome end_term(); 641b9f745fdSToomas Soome } 642b9f745fdSToomas Soome 643b9f745fdSToomas Soome /* Clear display from current position to end of screen. */ 644b9f745fdSToomas Soome static void 645b9f745fdSToomas Soome CD(void) 646b9f745fdSToomas Soome { 647b9f745fdSToomas Soome int i; 648b9f745fdSToomas Soome UINTN x, y; 649b9f745fdSToomas Soome 650b9f745fdSToomas Soome get_pos(&curx, &cury); 651b9f745fdSToomas Soome if (curx == 0 && cury == 0) { 652b9f745fdSToomas Soome conout->ClearScreen(conout); 653b9f745fdSToomas Soome end_term(); 654b9f745fdSToomas Soome return; 655b9f745fdSToomas Soome } 656b9f745fdSToomas Soome 657b9f745fdSToomas Soome conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 658b9f745fdSToomas Soome CL(0); /* clear current line from cursor to end */ 659b9f745fdSToomas Soome for (i = cury + 1; i < y-1; i++) { 660b9f745fdSToomas Soome curs_move(NULL, NULL, 0, i); 661b9f745fdSToomas Soome CL(0); 662b9f745fdSToomas Soome } 663b9f745fdSToomas Soome curs_move(NULL, NULL, curx, cury); 664b9f745fdSToomas Soome end_term(); 665b9f745fdSToomas Soome } 666b9f745fdSToomas Soome 667b9f745fdSToomas Soome /* 668b9f745fdSToomas Soome * Absolute cursor move to args[0] rows and args[1] columns 669b9f745fdSToomas Soome * (the coordinates are 1-based). 670b9f745fdSToomas Soome */ 671b9f745fdSToomas Soome static void 672b9f745fdSToomas Soome CM(void) 673b9f745fdSToomas Soome { 674b9f745fdSToomas Soome if (args[0] > 0) 675b9f745fdSToomas Soome args[0]--; 676b9f745fdSToomas Soome if (args[1] > 0) 677b9f745fdSToomas Soome args[1]--; 678b9f745fdSToomas Soome curs_move(&curx, &cury, args[1], args[0]); 679b9f745fdSToomas Soome end_term(); 680b9f745fdSToomas Soome } 681b9f745fdSToomas Soome 682b9f745fdSToomas Soome /* Home cursor (left top corner), also called from mode command. */ 683b9f745fdSToomas Soome void 684b9f745fdSToomas Soome HO(void) 685b9f745fdSToomas Soome { 686b9f745fdSToomas Soome argc = 1; 687b9f745fdSToomas Soome args[0] = args[1] = 1; 688b9f745fdSToomas Soome CM(); 689b9f745fdSToomas Soome } 690b9f745fdSToomas Soome 691b9f745fdSToomas Soome /* Clear line from current position to end of line */ 692b9f745fdSToomas Soome static void 693b9f745fdSToomas Soome CL(int direction) 694b9f745fdSToomas Soome { 695b9f745fdSToomas Soome int i, len; 696b9f745fdSToomas Soome UINTN x, y; 697b9f745fdSToomas Soome CHAR16 *line; 698b9f745fdSToomas Soome 699b9f745fdSToomas Soome conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 700b9f745fdSToomas Soome switch (direction) { 701b9f745fdSToomas Soome case 0: /* from cursor to end */ 702b9f745fdSToomas Soome len = x - curx + 1; 703b9f745fdSToomas Soome break; 704b9f745fdSToomas Soome case 1: /* from beginning to cursor */ 705b9f745fdSToomas Soome len = curx; 706b9f745fdSToomas Soome break; 707b9f745fdSToomas Soome case 2: /* entire line */ 708b9f745fdSToomas Soome len = x; 709b9f745fdSToomas Soome break; 710b9f745fdSToomas Soome default: /* NOTREACHED */ 711b9f745fdSToomas Soome __unreachable(); 712b9f745fdSToomas Soome } 713b9f745fdSToomas Soome 714b9f745fdSToomas Soome if (cury == y - 1) 715b9f745fdSToomas Soome len--; 716b9f745fdSToomas Soome 717b9f745fdSToomas Soome line = malloc(len * sizeof (CHAR16)); 718b9f745fdSToomas Soome if (line == NULL) { 719b9f745fdSToomas Soome printf("out of memory\n"); 720b9f745fdSToomas Soome return; 721b9f745fdSToomas Soome } 722b9f745fdSToomas Soome for (i = 0; i < len; i++) 723b9f745fdSToomas Soome line[i] = ' '; 724b9f745fdSToomas Soome line[len-1] = 0; 725b9f745fdSToomas Soome 726b9f745fdSToomas Soome if (direction != 0) 727b9f745fdSToomas Soome curs_move(NULL, NULL, 0, cury); 728b9f745fdSToomas Soome 729b9f745fdSToomas Soome conout->OutputString(conout, line); 730b9f745fdSToomas Soome /* restore cursor position */ 731b9f745fdSToomas Soome curs_move(NULL, NULL, curx, cury); 732b9f745fdSToomas Soome free(line); 733b9f745fdSToomas Soome end_term(); 734b9f745fdSToomas Soome } 735b9f745fdSToomas Soome 736b9f745fdSToomas Soome static void 737b9f745fdSToomas Soome get_arg(int c) 738b9f745fdSToomas Soome { 739b9f745fdSToomas Soome if (argc < 0) 740b9f745fdSToomas Soome argc = 0; 741b9f745fdSToomas Soome args[argc] *= 10; 742b9f745fdSToomas Soome args[argc] += c - '0'; 743b9f745fdSToomas Soome } 744b9f745fdSToomas Soome #endif 745b9f745fdSToomas Soome 746b9f745fdSToomas Soome /* Emulate basic capabilities of cons25 terminal */ 747b9f745fdSToomas Soome static void 748b9f745fdSToomas Soome efi_term_emu(int c) 749b9f745fdSToomas Soome { 750305ef653SWarner Losh if (!boot_services_active) 751305ef653SWarner Losh return; 752b9f745fdSToomas Soome #ifdef TERM_EMU 753b9f745fdSToomas Soome static int ansi_col[] = { 754b9f745fdSToomas Soome 0, 4, 2, 6, 1, 5, 3, 7 755b9f745fdSToomas Soome }; 756b9f745fdSToomas Soome int t, i; 757b9f745fdSToomas Soome EFI_STATUS status; 758b9f745fdSToomas Soome 759b9f745fdSToomas Soome switch (esc) { 760b9f745fdSToomas Soome case 0: 761b9f745fdSToomas Soome switch (c) { 762b9f745fdSToomas Soome case '\033': 763b9f745fdSToomas Soome esc = c; 764b9f745fdSToomas Soome break; 765b9f745fdSToomas Soome default: 766b9f745fdSToomas Soome efi_cons_rawputchar(c); 767b9f745fdSToomas Soome break; 768b9f745fdSToomas Soome } 769b9f745fdSToomas Soome break; 770b9f745fdSToomas Soome case '\033': 771b9f745fdSToomas Soome switch (c) { 772b9f745fdSToomas Soome case '[': 773b9f745fdSToomas Soome esc = c; 774b9f745fdSToomas Soome args[0] = 0; 775b9f745fdSToomas Soome argc = -1; 776b9f745fdSToomas Soome break; 777b9f745fdSToomas Soome default: 778b9f745fdSToomas Soome bail_out(c); 779b9f745fdSToomas Soome break; 780b9f745fdSToomas Soome } 781b9f745fdSToomas Soome break; 782b9f745fdSToomas Soome case '[': 783b9f745fdSToomas Soome switch (c) { 784b9f745fdSToomas Soome case ';': 785b9f745fdSToomas Soome if (argc < 0) 786b9f745fdSToomas Soome argc = 0; 787b9f745fdSToomas Soome else if (argc + 1 >= MAXARGS) 788b9f745fdSToomas Soome bail_out(c); 789b9f745fdSToomas Soome else 790b9f745fdSToomas Soome args[++argc] = 0; 791b9f745fdSToomas Soome break; 792b9f745fdSToomas Soome case 'H': /* ho = \E[H */ 793b9f745fdSToomas Soome if (argc < 0) 794b9f745fdSToomas Soome HO(); 795b9f745fdSToomas Soome else if (argc == 1) 796b9f745fdSToomas Soome CM(); 797b9f745fdSToomas Soome else 798b9f745fdSToomas Soome bail_out(c); 799b9f745fdSToomas Soome break; 800b9f745fdSToomas Soome case 'J': /* cd = \E[J */ 801b9f745fdSToomas Soome if (argc < 0) 802b9f745fdSToomas Soome CD(); 803b9f745fdSToomas Soome else 804b9f745fdSToomas Soome bail_out(c); 805b9f745fdSToomas Soome break; 806b9f745fdSToomas Soome case 'm': 807b9f745fdSToomas Soome if (argc < 0) { 808b9f745fdSToomas Soome fg_c = DEFAULT_FGCOLOR; 809b9f745fdSToomas Soome bg_c = DEFAULT_BGCOLOR; 810b9f745fdSToomas Soome } 811b9f745fdSToomas Soome for (i = 0; i <= argc; ++i) { 812b9f745fdSToomas Soome switch (args[i]) { 813b9f745fdSToomas Soome case 0: /* back to normal */ 814b9f745fdSToomas Soome fg_c = DEFAULT_FGCOLOR; 815b9f745fdSToomas Soome bg_c = DEFAULT_BGCOLOR; 816b9f745fdSToomas Soome break; 817b9f745fdSToomas Soome case 1: /* bold */ 818b9f745fdSToomas Soome fg_c |= 0x8; 819b9f745fdSToomas Soome break; 820b9f745fdSToomas Soome case 4: /* underline */ 821b9f745fdSToomas Soome case 5: /* blink */ 822b9f745fdSToomas Soome bg_c |= 0x8; 823b9f745fdSToomas Soome break; 824b9f745fdSToomas Soome case 7: /* reverse */ 825b9f745fdSToomas Soome t = fg_c; 826b9f745fdSToomas Soome fg_c = bg_c; 827b9f745fdSToomas Soome bg_c = t; 828b9f745fdSToomas Soome break; 829b9f745fdSToomas Soome case 22: /* normal intensity */ 830b9f745fdSToomas Soome fg_c &= ~0x8; 831b9f745fdSToomas Soome break; 832b9f745fdSToomas Soome case 24: /* not underline */ 833b9f745fdSToomas Soome case 25: /* not blinking */ 834b9f745fdSToomas Soome bg_c &= ~0x8; 835b9f745fdSToomas Soome break; 836b9f745fdSToomas Soome case 30: case 31: case 32: case 33: 837b9f745fdSToomas Soome case 34: case 35: case 36: case 37: 838b9f745fdSToomas Soome fg_c = ansi_col[args[i] - 30]; 839b9f745fdSToomas Soome break; 840b9f745fdSToomas Soome case 39: /* normal */ 841b9f745fdSToomas Soome fg_c = DEFAULT_FGCOLOR; 842b9f745fdSToomas Soome break; 843b9f745fdSToomas Soome case 40: case 41: case 42: case 43: 844b9f745fdSToomas Soome case 44: case 45: case 46: case 47: 845b9f745fdSToomas Soome bg_c = ansi_col[args[i] - 40]; 846b9f745fdSToomas Soome break; 847b9f745fdSToomas Soome case 49: /* normal */ 848b9f745fdSToomas Soome bg_c = DEFAULT_BGCOLOR; 849b9f745fdSToomas Soome break; 850b9f745fdSToomas Soome } 851b9f745fdSToomas Soome } 852b9f745fdSToomas Soome conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); 853b9f745fdSToomas Soome end_term(); 854b9f745fdSToomas Soome break; 855b9f745fdSToomas Soome default: 856b9f745fdSToomas Soome if (isdigit(c)) 857b9f745fdSToomas Soome get_arg(c); 858b9f745fdSToomas Soome else 859b9f745fdSToomas Soome bail_out(c); 860b9f745fdSToomas Soome break; 861b9f745fdSToomas Soome } 862b9f745fdSToomas Soome break; 863b9f745fdSToomas Soome default: 864b9f745fdSToomas Soome bail_out(c); 865b9f745fdSToomas Soome break; 866b9f745fdSToomas Soome } 867b9f745fdSToomas Soome #else 868b9f745fdSToomas Soome efi_cons_rawputchar(c); 869b9f745fdSToomas Soome #endif 870b9f745fdSToomas Soome } 871b9f745fdSToomas Soome 8723630506bSToomas Soome static int 8733630506bSToomas Soome env_screen_nounset(struct env_var *ev __unused) 8743630506bSToomas Soome { 8753630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 8763630506bSToomas Soome return (0); 8773630506bSToomas Soome return (EPERM); 8783630506bSToomas Soome } 8793630506bSToomas Soome 8803630506bSToomas Soome static void 8813630506bSToomas Soome cons_draw_frame(teken_attr_t *a) 8823630506bSToomas Soome { 8833630506bSToomas Soome teken_attr_t attr = *a; 8843630506bSToomas Soome teken_color_t fg = a->ta_fgcolor; 8853630506bSToomas Soome 8863630506bSToomas Soome attr.ta_fgcolor = attr.ta_bgcolor; 8873630506bSToomas Soome teken_set_defattr(&gfx_state.tg_teken, &attr); 8883630506bSToomas Soome 8893630506bSToomas Soome gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width, 8903630506bSToomas Soome gfx_state.tg_origin.tp_row, 1); 8913630506bSToomas Soome gfx_fb_drawrect(0, 8923630506bSToomas Soome gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 8933630506bSToomas Soome gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1); 8943630506bSToomas Soome gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row, 8953630506bSToomas Soome gfx_state.tg_origin.tp_col, 8963630506bSToomas Soome gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1); 8973630506bSToomas Soome gfx_fb_drawrect( 8983630506bSToomas Soome gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1, 8993630506bSToomas Soome gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width, 9003630506bSToomas Soome gfx_state.tg_fb.fb_height, 1); 9013630506bSToomas Soome 9023630506bSToomas Soome attr.ta_fgcolor = fg; 9033630506bSToomas Soome teken_set_defattr(&gfx_state.tg_teken, &attr); 9043630506bSToomas Soome } 9053630506bSToomas Soome 90656758831SToomas Soome bool 9073630506bSToomas Soome cons_update_mode(bool use_gfx_mode) 90856758831SToomas Soome { 90956758831SToomas Soome UINTN cols, rows; 91056758831SToomas Soome const teken_attr_t *a; 911a536ed41SToomas Soome teken_attr_t attr; 91256758831SToomas Soome EFI_STATUS status; 9133630506bSToomas Soome char env[10], *ptr; 9143630506bSToomas Soome 91561c50cbcSToomas Soome if (!efi_started) 91661c50cbcSToomas Soome return (false); 91761c50cbcSToomas Soome 9183630506bSToomas Soome /* 91950180d2bSToomas Soome * Despite the use_gfx_mode, we want to make sure we call 92050180d2bSToomas Soome * efi_find_framebuffer(). This will populate the fb data, 92150180d2bSToomas Soome * which will be passed to kernel. 9223630506bSToomas Soome */ 92350180d2bSToomas Soome if (efi_find_framebuffer(&gfx_state) == 0 && use_gfx_mode) { 9243630506bSToomas Soome int roff, goff, boff; 9253630506bSToomas Soome 92650180d2bSToomas Soome roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1; 92750180d2bSToomas Soome goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1; 92850180d2bSToomas Soome boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; 9293630506bSToomas Soome 9303630506bSToomas Soome (void) generate_cons_palette(cmap, COLOR_FORMAT_RGB, 93150180d2bSToomas Soome gfx_state.tg_fb.fb_mask_red >> roff, roff, 93250180d2bSToomas Soome gfx_state.tg_fb.fb_mask_green >> goff, goff, 93350180d2bSToomas Soome gfx_state.tg_fb.fb_mask_blue >> boff, boff); 9343630506bSToomas Soome } else { 93550180d2bSToomas Soome /* 93650180d2bSToomas Soome * Either text mode was asked by user or we failed to 93750180d2bSToomas Soome * find frame buffer. 93850180d2bSToomas Soome */ 9393630506bSToomas Soome gfx_state.tg_fb_type = FB_TEXT; 9403630506bSToomas Soome } 94156758831SToomas Soome 94256758831SToomas Soome status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); 943db316236SToomas Soome if (EFI_ERROR(status) || cols * rows == 0) { 9443630506bSToomas Soome cols = TEXT_COLS; 9453630506bSToomas Soome rows = TEXT_ROWS; 94656758831SToomas Soome } 94756758831SToomas Soome 948b9f745fdSToomas Soome /* 949b9f745fdSToomas Soome * When we have serial port listed in ConOut, use pre-teken emulator, 950b9f745fdSToomas Soome * if built with. 951b9f745fdSToomas Soome * The problem is, we can not output text on efi and comconsole when 952b9f745fdSToomas Soome * efi also has comconsole bound. But then again, we need to have 953b9f745fdSToomas Soome * terminal emulator for efi text mode to support the menu. 954b9f745fdSToomas Soome * While teken is too expensive to be used on serial console, the 955b9f745fdSToomas Soome * pre-teken emulator is light enough to be used on serial console. 9563c5a4af6SWarner Losh * 9573c5a4af6SWarner Losh * When doing multiple consoles (both serial and video), 9583c5a4af6SWarner Losh * also just use the old emulator. RB_MULTIPLE also implies 9593c5a4af6SWarner Losh * we're using a serial console. 960b9f745fdSToomas Soome */ 961b9f745fdSToomas Soome mode = parse_uefi_con_out(); 9623c5a4af6SWarner Losh if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) { 9633630506bSToomas Soome conout->EnableCursor(conout, FALSE); 9643630506bSToomas Soome gfx_state.tg_cursor_visible = false; 9653630506bSToomas Soome 9663630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) { 9673630506bSToomas Soome 9683630506bSToomas Soome gfx_state.tg_functions = &tf; 9693630506bSToomas Soome /* ensure the following are not set for text mode */ 9703630506bSToomas Soome unsetenv("screen.height"); 9713630506bSToomas Soome unsetenv("screen.width"); 9723630506bSToomas Soome unsetenv("screen.depth"); 97356758831SToomas Soome } else { 9743630506bSToomas Soome uint32_t fb_height, fb_width; 9753630506bSToomas Soome 9763630506bSToomas Soome fb_height = gfx_state.tg_fb.fb_height; 9773630506bSToomas Soome fb_width = gfx_state.tg_fb.fb_width; 9783630506bSToomas Soome 9793630506bSToomas Soome /* 9803630506bSToomas Soome * setup_font() can adjust terminal size. 981becaac39SToomas Soome * We can see two kind of bad happening. 982becaac39SToomas Soome * We either can get too small console font - requested 983becaac39SToomas Soome * terminal size is large, display resolution is 984becaac39SToomas Soome * large, and we get very small font. 985becaac39SToomas Soome * Or, we can get too large font - requested 986becaac39SToomas Soome * terminal size is small and this will cause large 987becaac39SToomas Soome * font to be selected. 988becaac39SToomas Soome * Now, the setup_font() is updated to consider 989becaac39SToomas Soome * display density and this should give us mostly 990becaac39SToomas Soome * acceptable font. However, the catch is, not all 991becaac39SToomas Soome * display devices will give us display density. 992becaac39SToomas Soome * Still, we do hope, external monitors do - this is 993becaac39SToomas Soome * where the display size will matter the most. 994becaac39SToomas Soome * And for laptop screens, we should still get good 995becaac39SToomas Soome * results by requesting 80x25 terminal. 9963630506bSToomas Soome */ 997becaac39SToomas Soome gfx_state.tg_tp.tp_row = 25; 998becaac39SToomas Soome gfx_state.tg_tp.tp_col = 80; 9993630506bSToomas Soome setup_font(&gfx_state, fb_height, fb_width); 10003630506bSToomas Soome rows = gfx_state.tg_tp.tp_row; 10013630506bSToomas Soome cols = gfx_state.tg_tp.tp_col; 10023630506bSToomas Soome /* Point of origin in pixels. */ 10033630506bSToomas Soome gfx_state.tg_origin.tp_row = (fb_height - 10043630506bSToomas Soome (rows * gfx_state.tg_font.vf_height)) / 2; 10053630506bSToomas Soome gfx_state.tg_origin.tp_col = (fb_width - 10063630506bSToomas Soome (cols * gfx_state.tg_font.vf_width)) / 2; 10073630506bSToomas Soome 10083630506bSToomas Soome /* UEFI gop has depth 32. */ 10093630506bSToomas Soome gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height * 10103630506bSToomas Soome gfx_state.tg_font.vf_width * 4; 10113630506bSToomas Soome free(gfx_state.tg_glyph); 10123630506bSToomas Soome gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size); 10133630506bSToomas Soome if (gfx_state.tg_glyph == NULL) 10143630506bSToomas Soome return (false); 10153630506bSToomas Soome 10163630506bSToomas Soome gfx_state.tg_functions = &tfx; 10173630506bSToomas Soome snprintf(env, sizeof (env), "%d", fb_height); 10183630506bSToomas Soome env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK, 10193630506bSToomas Soome env, env_noset, env_screen_nounset); 10203630506bSToomas Soome snprintf(env, sizeof (env), "%d", fb_width); 10213630506bSToomas Soome env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK, 10223630506bSToomas Soome env, env_noset, env_screen_nounset); 10233630506bSToomas Soome snprintf(env, sizeof (env), "%d", 10243630506bSToomas Soome gfx_state.tg_fb.fb_bpp); 10253630506bSToomas Soome env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK, 10263630506bSToomas Soome env, env_noset, env_screen_nounset); 102756758831SToomas Soome } 102856758831SToomas Soome 10293630506bSToomas Soome /* Record our terminal screen size. */ 10303630506bSToomas Soome gfx_state.tg_tp.tp_row = rows; 10313630506bSToomas Soome gfx_state.tg_tp.tp_col = cols; 10323630506bSToomas Soome 10333630506bSToomas Soome teken_init(&gfx_state.tg_teken, gfx_state.tg_functions, 10343630506bSToomas Soome &gfx_state); 10353630506bSToomas Soome 10363630506bSToomas Soome free(screen_buffer); 10373630506bSToomas Soome screen_buffer = malloc(rows * cols * sizeof(*screen_buffer)); 10383630506bSToomas Soome if (screen_buffer != NULL) { 10393630506bSToomas Soome teken_set_winsize(&gfx_state.tg_teken, 10403630506bSToomas Soome &gfx_state.tg_tp); 10413630506bSToomas Soome a = teken_get_defattr(&gfx_state.tg_teken); 1042a536ed41SToomas Soome attr = *a; 104356758831SToomas Soome 1044a536ed41SToomas Soome /* 1045a536ed41SToomas Soome * On first run, we set up the efi_set_colors() 1046a536ed41SToomas Soome * callback. If the env is already set, we 1047a536ed41SToomas Soome * pick up fg and bg color values from the environment. 1048a536ed41SToomas Soome */ 1049a536ed41SToomas Soome ptr = getenv("teken.fg_color"); 1050a536ed41SToomas Soome if (ptr != NULL) { 1051a536ed41SToomas Soome attr.ta_fgcolor = strtol(ptr, NULL, 10); 1052a536ed41SToomas Soome ptr = getenv("teken.bg_color"); 1053a536ed41SToomas Soome attr.ta_bgcolor = strtol(ptr, NULL, 10); 1054a536ed41SToomas Soome 10553630506bSToomas Soome teken_set_defattr(&gfx_state.tg_teken, &attr); 1056a536ed41SToomas Soome } else { 1057a536ed41SToomas Soome snprintf(env, sizeof(env), "%d", 1058a536ed41SToomas Soome attr.ta_fgcolor); 105934edaae6SToomas Soome env_setenv("teken.fg_color", EV_VOLATILE, env, 106034edaae6SToomas Soome efi_set_colors, env_nounset); 1061a536ed41SToomas Soome snprintf(env, sizeof(env), "%d", 1062a536ed41SToomas Soome attr.ta_bgcolor); 106334edaae6SToomas Soome env_setenv("teken.bg_color", EV_VOLATILE, env, 106434edaae6SToomas Soome efi_set_colors, env_nounset); 1065a536ed41SToomas Soome } 106634edaae6SToomas Soome } 106734edaae6SToomas Soome } 106834edaae6SToomas Soome 10693630506bSToomas Soome if (screen_buffer == NULL) { 10703630506bSToomas Soome conout->EnableCursor(conout, TRUE); 1071b9f745fdSToomas Soome #ifdef TERM_EMU 1072b9f745fdSToomas Soome conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, 1073b9f745fdSToomas Soome DEFAULT_BGCOLOR)); 1074b9f745fdSToomas Soome end_term(); 1075b9f745fdSToomas Soome get_pos(&curx, &cury); 1076b9f745fdSToomas Soome curs_move(&curx, &cury, curx, cury); 1077b9f745fdSToomas Soome fg_c = DEFAULT_FGCOLOR; 1078b9f745fdSToomas Soome bg_c = DEFAULT_BGCOLOR; 107934edaae6SToomas Soome #endif 10803630506bSToomas Soome } else { 10813630506bSToomas Soome /* Improve visibility */ 10823630506bSToomas Soome if (attr.ta_bgcolor == TC_WHITE) 10833630506bSToomas Soome attr.ta_bgcolor |= TC_LIGHT; 10843630506bSToomas Soome teken_set_defattr(&gfx_state.tg_teken, &attr); 10853630506bSToomas Soome 10863630506bSToomas Soome /* Draw frame around terminal area. */ 10873630506bSToomas Soome cons_draw_frame(&attr); 10883630506bSToomas Soome /* 10893630506bSToomas Soome * Erase display, this will also fill our screen 10903630506bSToomas Soome * buffer. 10913630506bSToomas Soome */ 10923630506bSToomas Soome teken_input(&gfx_state.tg_teken, "\e[2J", 4); 10933630506bSToomas Soome gfx_state.tg_functions->tf_param(&gfx_state, 10943630506bSToomas Soome TP_SHOWCURSOR, 1); 10953630506bSToomas Soome } 109656758831SToomas Soome 109756758831SToomas Soome snprintf(env, sizeof (env), "%u", (unsigned)rows); 109856758831SToomas Soome setenv("LINES", env, 1); 109956758831SToomas Soome snprintf(env, sizeof (env), "%u", (unsigned)cols); 110056758831SToomas Soome setenv("COLUMNS", env, 1); 110156758831SToomas Soome 110256758831SToomas Soome return (true); 110356758831SToomas Soome } 110456758831SToomas Soome 1105ca987d46SWarner Losh static int 1106ca987d46SWarner Losh efi_cons_init(int arg) 1107ca987d46SWarner Losh { 110805b24e86SToomas Soome EFI_STATUS status; 110905b24e86SToomas Soome 11103630506bSToomas Soome if (efi_started) 11113630506bSToomas Soome return (0); 11123630506bSToomas Soome 11133630506bSToomas Soome efi_started = true; 11143630506bSToomas Soome 11153630506bSToomas Soome gfx_framework_init(); 11163630506bSToomas Soome if (cons_update_mode(gfx_state.tg_fb_type != FB_TEXT)) 111705b24e86SToomas Soome return (0); 1118ca987d46SWarner Losh 111956758831SToomas Soome return (1); 1120ca987d46SWarner Losh } 1121ca987d46SWarner Losh 1122b9f745fdSToomas Soome static void 1123b9f745fdSToomas Soome input_partial(void) 1124b9f745fdSToomas Soome { 1125b9f745fdSToomas Soome unsigned i; 1126b9f745fdSToomas Soome uint32_t c; 1127b9f745fdSToomas Soome 1128b9f745fdSToomas Soome if (utf8_left == 0) 1129b9f745fdSToomas Soome return; 1130b9f745fdSToomas Soome 1131b9f745fdSToomas Soome for (i = 0; i < sizeof(utf8_partial); i++) { 1132b9f745fdSToomas Soome c = (utf8_partial >> (24 - (i << 3))) & 0xff; 1133b9f745fdSToomas Soome if (c != 0) 1134b9f745fdSToomas Soome efi_term_emu(c); 1135b9f745fdSToomas Soome } 1136b9f745fdSToomas Soome utf8_left = 0; 1137b9f745fdSToomas Soome utf8_partial = 0; 1138b9f745fdSToomas Soome } 1139b9f745fdSToomas Soome 1140b9f745fdSToomas Soome static void 1141b9f745fdSToomas Soome input_byte(uint8_t c) 1142b9f745fdSToomas Soome { 1143b9f745fdSToomas Soome if ((c & 0x80) == 0x00) { 1144b9f745fdSToomas Soome /* One-byte sequence. */ 1145b9f745fdSToomas Soome input_partial(); 1146b9f745fdSToomas Soome efi_term_emu(c); 1147b9f745fdSToomas Soome return; 1148b9f745fdSToomas Soome } 1149b9f745fdSToomas Soome if ((c & 0xe0) == 0xc0) { 1150b9f745fdSToomas Soome /* Two-byte sequence. */ 1151b9f745fdSToomas Soome input_partial(); 1152b9f745fdSToomas Soome utf8_left = 1; 1153b9f745fdSToomas Soome utf8_partial = c; 1154b9f745fdSToomas Soome return; 1155b9f745fdSToomas Soome } 1156b9f745fdSToomas Soome if ((c & 0xf0) == 0xe0) { 1157b9f745fdSToomas Soome /* Three-byte sequence. */ 1158b9f745fdSToomas Soome input_partial(); 1159b9f745fdSToomas Soome utf8_left = 2; 1160b9f745fdSToomas Soome utf8_partial = c; 1161b9f745fdSToomas Soome return; 1162b9f745fdSToomas Soome } 1163b9f745fdSToomas Soome if ((c & 0xf8) == 0xf0) { 1164b9f745fdSToomas Soome /* Four-byte sequence. */ 1165b9f745fdSToomas Soome input_partial(); 1166b9f745fdSToomas Soome utf8_left = 3; 1167b9f745fdSToomas Soome utf8_partial = c; 1168b9f745fdSToomas Soome return; 1169b9f745fdSToomas Soome } 1170b9f745fdSToomas Soome if ((c & 0xc0) == 0x80) { 1171b9f745fdSToomas Soome /* Invalid state? */ 1172b9f745fdSToomas Soome if (utf8_left == 0) { 1173b9f745fdSToomas Soome efi_term_emu(c); 1174b9f745fdSToomas Soome return; 1175b9f745fdSToomas Soome } 1176b9f745fdSToomas Soome utf8_left--; 1177b9f745fdSToomas Soome utf8_partial = (utf8_partial << 8) | c; 1178b9f745fdSToomas Soome if (utf8_left == 0) { 1179b9f745fdSToomas Soome uint32_t v, u; 1180b9f745fdSToomas Soome uint8_t b; 1181b9f745fdSToomas Soome 1182b9f745fdSToomas Soome v = 0; 1183b9f745fdSToomas Soome u = utf8_partial; 1184b9f745fdSToomas Soome b = (u >> 24) & 0xff; 1185b9f745fdSToomas Soome if (b != 0) { /* Four-byte sequence */ 1186b9f745fdSToomas Soome v = b & 0x07; 1187b9f745fdSToomas Soome b = (u >> 16) & 0xff; 1188b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1189b9f745fdSToomas Soome b = (u >> 8) & 0xff; 1190b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1191b9f745fdSToomas Soome b = u & 0xff; 1192b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1193b9f745fdSToomas Soome } else if ((b = (u >> 16) & 0xff) != 0) { 1194b9f745fdSToomas Soome v = b & 0x0f; /* Three-byte sequence */ 1195b9f745fdSToomas Soome b = (u >> 8) & 0xff; 1196b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1197b9f745fdSToomas Soome b = u & 0xff; 1198b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1199b9f745fdSToomas Soome } else if ((b = (u >> 8) & 0xff) != 0) { 1200b9f745fdSToomas Soome v = b & 0x1f; /* Two-byte sequence */ 1201b9f745fdSToomas Soome b = u & 0xff; 1202b9f745fdSToomas Soome v = (v << 6) | (b & 0x3f); 1203b9f745fdSToomas Soome } 1204b9f745fdSToomas Soome /* Send unicode char directly to console. */ 1205b9f745fdSToomas Soome efi_cons_efiputchar(v); 1206b9f745fdSToomas Soome utf8_partial = 0; 1207b9f745fdSToomas Soome } 1208b9f745fdSToomas Soome return; 1209b9f745fdSToomas Soome } 1210b9f745fdSToomas Soome /* Anything left is illegal in UTF-8 sequence. */ 1211b9f745fdSToomas Soome input_partial(); 1212b9f745fdSToomas Soome efi_term_emu(c); 1213b9f745fdSToomas Soome } 1214b9f745fdSToomas Soome 1215ca987d46SWarner Losh void 1216ca987d46SWarner Losh efi_cons_putchar(int c) 1217ca987d46SWarner Losh { 121856758831SToomas Soome unsigned char ch = c; 121956758831SToomas Soome 12203c5a4af6SWarner Losh /* 12213c5a4af6SWarner Losh * Don't use Teken when we're doing pure serial, or a multiple console 12223c5a4af6SWarner Losh * with video "primary" because that's also serial. 12233c5a4af6SWarner Losh */ 12243630506bSToomas Soome if ((mode & (RB_SERIAL | RB_MULTIPLE)) != 0 || screen_buffer == NULL) { 1225b9f745fdSToomas Soome input_byte(ch); 1226b9f745fdSToomas Soome return; 1227b9f745fdSToomas Soome } 1228b9f745fdSToomas Soome 12293630506bSToomas Soome teken_input(&gfx_state.tg_teken, &ch, sizeof (ch)); 1230ca987d46SWarner Losh } 1231ca987d46SWarner Losh 1232fb0df666SToomas Soome static int 1233fb0df666SToomas Soome keybuf_getchar(void) 1234ca987d46SWarner Losh { 1235fb0df666SToomas Soome int i, c = 0; 1236ca987d46SWarner Losh 1237fb0df666SToomas Soome for (i = 0; i < KEYBUFSZ; i++) { 1238fb0df666SToomas Soome if (keybuf[i] != 0) { 1239fb0df666SToomas Soome c = keybuf[i]; 1240fb0df666SToomas Soome keybuf[i] = 0; 1241fb0df666SToomas Soome break; 1242ca987d46SWarner Losh } 1243ca987d46SWarner Losh } 1244ca987d46SWarner Losh 1245fb0df666SToomas Soome return (c); 1246ca987d46SWarner Losh } 1247ca987d46SWarner Losh 1248fb0df666SToomas Soome static bool 1249fb0df666SToomas Soome keybuf_ischar(void) 1250ca987d46SWarner Losh { 1251fb0df666SToomas Soome int i; 1252ca987d46SWarner Losh 1253fb0df666SToomas Soome for (i = 0; i < KEYBUFSZ; i++) { 1254fb0df666SToomas Soome if (keybuf[i] != 0) 1255fb0df666SToomas Soome return (true); 1256fb0df666SToomas Soome } 1257fb0df666SToomas Soome return (false); 1258fb0df666SToomas Soome } 1259fb0df666SToomas Soome 1260fb0df666SToomas Soome /* 1261fb0df666SToomas Soome * We are not reading input before keybuf is empty, so we are safe 1262fb0df666SToomas Soome * just to fill keybuf from the beginning. 1263fb0df666SToomas Soome */ 1264fb0df666SToomas Soome static void 1265fb0df666SToomas Soome keybuf_inschar(EFI_INPUT_KEY *key) 1266fb0df666SToomas Soome { 1267fb0df666SToomas Soome 1268fb0df666SToomas Soome switch (key->ScanCode) { 1269591d5f0eSToomas Soome case SCAN_UP: /* UP */ 1270fb0df666SToomas Soome keybuf[0] = 0x1b; /* esc */ 1271fb0df666SToomas Soome keybuf[1] = '['; 1272fb0df666SToomas Soome keybuf[2] = 'A'; 1273fb0df666SToomas Soome break; 1274591d5f0eSToomas Soome case SCAN_DOWN: /* DOWN */ 1275fb0df666SToomas Soome keybuf[0] = 0x1b; /* esc */ 1276fb0df666SToomas Soome keybuf[1] = '['; 1277fb0df666SToomas Soome keybuf[2] = 'B'; 1278fb0df666SToomas Soome break; 1279591d5f0eSToomas Soome case SCAN_RIGHT: /* RIGHT */ 1280fb0df666SToomas Soome keybuf[0] = 0x1b; /* esc */ 1281fb0df666SToomas Soome keybuf[1] = '['; 1282fb0df666SToomas Soome keybuf[2] = 'C'; 1283fb0df666SToomas Soome break; 1284591d5f0eSToomas Soome case SCAN_LEFT: /* LEFT */ 1285fb0df666SToomas Soome keybuf[0] = 0x1b; /* esc */ 1286fb0df666SToomas Soome keybuf[1] = '['; 1287fb0df666SToomas Soome keybuf[2] = 'D'; 1288fb0df666SToomas Soome break; 1289591d5f0eSToomas Soome case SCAN_DELETE: 1290591d5f0eSToomas Soome keybuf[0] = CHAR_BACKSPACE; 1291591d5f0eSToomas Soome break; 1292591d5f0eSToomas Soome case SCAN_ESC: 1293fb0df666SToomas Soome keybuf[0] = 0x1b; /* esc */ 1294fb0df666SToomas Soome break; 1295fb0df666SToomas Soome default: 1296fb0df666SToomas Soome keybuf[0] = key->UnicodeChar; 1297fb0df666SToomas Soome break; 1298fb0df666SToomas Soome } 1299fb0df666SToomas Soome } 1300fb0df666SToomas Soome 1301fb0df666SToomas Soome static bool 1302fb0df666SToomas Soome efi_readkey(void) 1303fb0df666SToomas Soome { 1304fb0df666SToomas Soome EFI_STATUS status; 1305fb0df666SToomas Soome EFI_INPUT_KEY key; 1306fb0df666SToomas Soome 1307ca987d46SWarner Losh status = conin->ReadKeyStroke(conin, &key); 1308ca987d46SWarner Losh if (status == EFI_SUCCESS) { 1309fb0df666SToomas Soome keybuf_inschar(&key); 1310fb0df666SToomas Soome return (true); 1311ca987d46SWarner Losh } 1312fb0df666SToomas Soome return (false); 1313ca987d46SWarner Losh } 1314ca987d46SWarner Losh 131505b24e86SToomas Soome static bool 131605b24e86SToomas Soome efi_readkey_ex(void) 131705b24e86SToomas Soome { 131805b24e86SToomas Soome EFI_STATUS status; 131905b24e86SToomas Soome EFI_INPUT_KEY *kp; 132005b24e86SToomas Soome EFI_KEY_DATA key_data; 132105b24e86SToomas Soome uint32_t kss; 132205b24e86SToomas Soome 132305b24e86SToomas Soome status = coninex->ReadKeyStrokeEx(coninex, &key_data); 132405b24e86SToomas Soome if (status == EFI_SUCCESS) { 132505b24e86SToomas Soome kss = key_data.KeyState.KeyShiftState; 132605b24e86SToomas Soome kp = &key_data.Key; 132705b24e86SToomas Soome if (kss & EFI_SHIFT_STATE_VALID) { 132805b24e86SToomas Soome 132905b24e86SToomas Soome /* 133005b24e86SToomas Soome * quick mapping to control chars, replace with 133105b24e86SToomas Soome * map lookup later. 133205b24e86SToomas Soome */ 133305b24e86SToomas Soome if (kss & EFI_RIGHT_CONTROL_PRESSED || 133405b24e86SToomas Soome kss & EFI_LEFT_CONTROL_PRESSED) { 133505b24e86SToomas Soome if (kp->UnicodeChar >= 'a' && 133605b24e86SToomas Soome kp->UnicodeChar <= 'z') { 133705b24e86SToomas Soome kp->UnicodeChar -= 'a'; 133805b24e86SToomas Soome kp->UnicodeChar++; 133905b24e86SToomas Soome } 134005b24e86SToomas Soome } 1341ade8a0f1SToomas Soome } 1342ade8a0f1SToomas Soome /* 1343ade8a0f1SToomas Soome * The shift state and/or toggle state may not be valid, 1344ade8a0f1SToomas Soome * but we still can have ScanCode or UnicodeChar. 1345ade8a0f1SToomas Soome */ 13460aff5f39SToomas Soome if (kp->ScanCode == 0 && kp->UnicodeChar == 0) 13470aff5f39SToomas Soome return (false); 134805b24e86SToomas Soome keybuf_inschar(kp); 134905b24e86SToomas Soome return (true); 135005b24e86SToomas Soome } 135105b24e86SToomas Soome return (false); 135205b24e86SToomas Soome } 135305b24e86SToomas Soome 1354fb0df666SToomas Soome int 1355fb0df666SToomas Soome efi_cons_getchar(void) 1356fb0df666SToomas Soome { 1357fb0df666SToomas Soome int c; 1358fb0df666SToomas Soome 1359fb0df666SToomas Soome if ((c = keybuf_getchar()) != 0) 1360fb0df666SToomas Soome return (c); 1361fb0df666SToomas Soome 1362a2e02d9dSToomas Soome if (!boot_services_active) 1363a2e02d9dSToomas Soome return (-1); 1364a2e02d9dSToomas Soome 1365fb0df666SToomas Soome key_pending = 0; 1366fb0df666SToomas Soome 136705b24e86SToomas Soome if (coninex == NULL) { 1368fb0df666SToomas Soome if (efi_readkey()) 1369fb0df666SToomas Soome return (keybuf_getchar()); 137005b24e86SToomas Soome } else { 137105b24e86SToomas Soome if (efi_readkey_ex()) 137205b24e86SToomas Soome return (keybuf_getchar()); 137305b24e86SToomas Soome } 1374fb0df666SToomas Soome 1375fb0df666SToomas Soome return (-1); 1376fb0df666SToomas Soome } 1377fb0df666SToomas Soome 1378fb0df666SToomas Soome int 1379fb0df666SToomas Soome efi_cons_poll(void) 1380fb0df666SToomas Soome { 138105b24e86SToomas Soome EFI_STATUS status; 1382fb0df666SToomas Soome 1383fb0df666SToomas Soome if (keybuf_ischar() || key_pending) 1384fb0df666SToomas Soome return (1); 1385fb0df666SToomas Soome 1386a2e02d9dSToomas Soome if (!boot_services_active) 1387a2e02d9dSToomas Soome return (0); 1388a2e02d9dSToomas Soome 1389fb0df666SToomas Soome /* 1390fb0df666SToomas Soome * Some EFI implementation (u-boot for example) do not support 1391fb0df666SToomas Soome * WaitForKey(). 1392fb0df666SToomas Soome * CheckEvent() can clear the signaled state. 1393fb0df666SToomas Soome */ 139405b24e86SToomas Soome if (coninex != NULL) { 139505b24e86SToomas Soome if (coninex->WaitForKeyEx == NULL) { 139605b24e86SToomas Soome key_pending = efi_readkey_ex(); 139705b24e86SToomas Soome } else { 139805b24e86SToomas Soome status = BS->CheckEvent(coninex->WaitForKeyEx); 139905b24e86SToomas Soome key_pending = status == EFI_SUCCESS; 140005b24e86SToomas Soome } 140105b24e86SToomas Soome } else { 140205b24e86SToomas Soome if (conin->WaitForKey == NULL) { 1403fb0df666SToomas Soome key_pending = efi_readkey(); 140405b24e86SToomas Soome } else { 140505b24e86SToomas Soome status = BS->CheckEvent(conin->WaitForKey); 140605b24e86SToomas Soome key_pending = status == EFI_SUCCESS; 140705b24e86SToomas Soome } 140805b24e86SToomas Soome } 1409fb0df666SToomas Soome 1410fb0df666SToomas Soome return (key_pending); 1411ca987d46SWarner Losh } 1412ca987d46SWarner Losh 1413ca987d46SWarner Losh /* Plain direct access to EFI OutputString(). */ 1414ca987d46SWarner Losh void 1415ca987d46SWarner Losh efi_cons_efiputchar(int c) 1416ca987d46SWarner Losh { 1417ca987d46SWarner Losh CHAR16 buf[2]; 141856758831SToomas Soome EFI_STATUS status; 1419ca987d46SWarner Losh 1420ca987d46SWarner Losh buf[0] = c; 1421ca987d46SWarner Losh buf[1] = 0; /* terminate string */ 1422ca987d46SWarner Losh 142356758831SToomas Soome status = conout->TestString(conout, buf); 142456758831SToomas Soome if (EFI_ERROR(status)) 142556758831SToomas Soome buf[0] = '?'; 1426ca987d46SWarner Losh conout->OutputString(conout, buf); 1427ca987d46SWarner Losh } 1428