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
term_image_display(teken_gfx_t * state,const teken_rect_t * r)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
efi_cons_bell(void * s __unused)16856758831SToomas Soome efi_cons_bell(void *s __unused)
169ca987d46SWarner Losh {
170ca987d46SWarner Losh }
171ca987d46SWarner Losh
17256758831SToomas Soome static void
efi_text_cursor(void * arg,const teken_pos_t * p)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
efi_text_printchar(teken_gfx_t * state,const teken_pos_t * p,bool autoscroll)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
efi_text_putchar(void * s,const teken_pos_t * p,teken_char_t c,const teken_attr_t * a)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
efi_text_fill(void * arg,const teken_rect_t * r,teken_char_t c,const teken_attr_t * a)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
efi_text_copy_line(teken_gfx_t * state,int ncol,teken_pos_t * s,teken_pos_t * d,bool scroll)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
efi_text_copy(void * arg,const teken_rect_t * r,const teken_pos_t * p)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
efi_text_param(void * arg,int cmd,unsigned int value)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
efi_cons_respond(void * s __unused,const void * buf __unused,size_t len __unused)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
efi_cons_probe(struct console * cp)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
color_name_to_teken(const char * name,int * val)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
efi_set_colors(struct env_var * ev,int flags,const void * value)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
get_pos(int * x,int * y)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
curs_move(int * _x,int * _y,int x,int y)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
end_term(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
efi_cons_rawputchar(int c)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
bail_out(int c)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
CD(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
CM(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
HO(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
CL(int direction)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
get_arg(int c)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
efi_term_emu(int c)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
env_screen_nounset(struct env_var * ev __unused)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
cons_draw_frame(teken_attr_t * a)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
cons_update_mode(bool use_gfx_mode)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
efi_cons_init(int arg)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
input_partial(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
input_byte(uint8_t c)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
efi_cons_putchar(int c)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
keybuf_getchar(void)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
keybuf_ischar(void)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
keybuf_inschar(EFI_INPUT_KEY * key)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
efi_readkey(void)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
efi_readkey_ex(void)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
efi_cons_getchar(void)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
efi_cons_poll(void)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
efi_cons_efiputchar(int c)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