1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+
2c1311ad4SAlexander Graf /*
3c1311ad4SAlexander Graf * EFI application console interface
4c1311ad4SAlexander Graf *
5c1311ad4SAlexander Graf * Copyright (c) 2016 Alexander Graf
6c1311ad4SAlexander Graf */
7c1311ad4SAlexander Graf
8c1311ad4SAlexander Graf #include <common.h>
978178bb0SRob Clark #include <charset.h>
10a18c5a83SRob Clark #include <dm/device.h>
11c1311ad4SAlexander Graf #include <efi_loader.h>
12a18c5a83SRob Clark #include <stdio_dev.h>
13a18c5a83SRob Clark #include <video_console.h>
14c1311ad4SAlexander Graf
155be8b0a3SEmmanuel Vadot #define EFI_COUT_MODE_2 2
165be8b0a3SEmmanuel Vadot #define EFI_MAX_COUT_MODE 3
175be8b0a3SEmmanuel Vadot
185be8b0a3SEmmanuel Vadot struct cout_mode {
195be8b0a3SEmmanuel Vadot unsigned long columns;
205be8b0a3SEmmanuel Vadot unsigned long rows;
215be8b0a3SEmmanuel Vadot int present;
225be8b0a3SEmmanuel Vadot };
235be8b0a3SEmmanuel Vadot
245be8b0a3SEmmanuel Vadot static struct cout_mode efi_cout_modes[] = {
255be8b0a3SEmmanuel Vadot /* EFI Mode 0 is 80x25 and always present */
265be8b0a3SEmmanuel Vadot {
275be8b0a3SEmmanuel Vadot .columns = 80,
285be8b0a3SEmmanuel Vadot .rows = 25,
295be8b0a3SEmmanuel Vadot .present = 1,
305be8b0a3SEmmanuel Vadot },
315be8b0a3SEmmanuel Vadot /* EFI Mode 1 is always 80x50 */
325be8b0a3SEmmanuel Vadot {
335be8b0a3SEmmanuel Vadot .columns = 80,
345be8b0a3SEmmanuel Vadot .rows = 50,
355be8b0a3SEmmanuel Vadot .present = 0,
365be8b0a3SEmmanuel Vadot },
375be8b0a3SEmmanuel Vadot /* Value are unknown until we query the console */
385be8b0a3SEmmanuel Vadot {
395be8b0a3SEmmanuel Vadot .columns = 0,
405be8b0a3SEmmanuel Vadot .rows = 0,
415be8b0a3SEmmanuel Vadot .present = 0,
425be8b0a3SEmmanuel Vadot },
435be8b0a3SEmmanuel Vadot };
445be8b0a3SEmmanuel Vadot
45110c6280SHeinrich Schuchardt const efi_guid_t efi_guid_text_input_ex_protocol =
46110c6280SHeinrich Schuchardt EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
47ebb4dd5bSHeinrich Schuchardt const efi_guid_t efi_guid_text_input_protocol =
48ebb4dd5bSHeinrich Schuchardt EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
49110c6280SHeinrich Schuchardt const efi_guid_t efi_guid_text_output_protocol =
50110c6280SHeinrich Schuchardt EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
51c1311ad4SAlexander Graf
52c1311ad4SAlexander Graf #define cESC '\x1b'
53c1311ad4SAlexander Graf #define ESC "\x1b"
54c1311ad4SAlexander Graf
555be8b0a3SEmmanuel Vadot /* Default to mode 0 */
56c1311ad4SAlexander Graf static struct simple_text_output_mode efi_con_mode = {
575be8b0a3SEmmanuel Vadot .max_mode = 1,
58c1311ad4SAlexander Graf .mode = 0,
59c1311ad4SAlexander Graf .attribute = 0,
60c1311ad4SAlexander Graf .cursor_column = 0,
61c1311ad4SAlexander Graf .cursor_row = 0,
62c1311ad4SAlexander Graf .cursor_visible = 1,
63c1311ad4SAlexander Graf };
64c1311ad4SAlexander Graf
term_get_char(s32 * c)65*dd1a1ec2SMatthias Brugger static int term_get_char(s32 *c)
66*dd1a1ec2SMatthias Brugger {
67*dd1a1ec2SMatthias Brugger u64 timeout;
68*dd1a1ec2SMatthias Brugger
69*dd1a1ec2SMatthias Brugger /* Wait up to 100 ms for a character */
70*dd1a1ec2SMatthias Brugger timeout = timer_get_us() + 100000;
71*dd1a1ec2SMatthias Brugger
72*dd1a1ec2SMatthias Brugger while (!tstc())
73*dd1a1ec2SMatthias Brugger if (timer_get_us() > timeout)
74*dd1a1ec2SMatthias Brugger return 1;
75*dd1a1ec2SMatthias Brugger
76*dd1a1ec2SMatthias Brugger *c = getc();
77*dd1a1ec2SMatthias Brugger return 0;
78*dd1a1ec2SMatthias Brugger }
79*dd1a1ec2SMatthias Brugger
8062217295SHeinrich Schuchardt /*
8162217295SHeinrich Schuchardt * Receive and parse a reply from the terminal.
8262217295SHeinrich Schuchardt *
8362217295SHeinrich Schuchardt * @n: array of return values
8462217295SHeinrich Schuchardt * @num: number of return values expected
8562217295SHeinrich Schuchardt * @end_char: character indicating end of terminal message
8662217295SHeinrich Schuchardt * @return: non-zero indicates error
8762217295SHeinrich Schuchardt */
term_read_reply(int * n,int num,char end_char)8862217295SHeinrich Schuchardt static int term_read_reply(int *n, int num, char end_char)
89c1311ad4SAlexander Graf {
90*dd1a1ec2SMatthias Brugger s32 c;
91c1311ad4SAlexander Graf int i = 0;
92c1311ad4SAlexander Graf
93*dd1a1ec2SMatthias Brugger if (term_get_char(&c) || c != cESC)
94c1311ad4SAlexander Graf return -1;
95*dd1a1ec2SMatthias Brugger
96*dd1a1ec2SMatthias Brugger if (term_get_char(&c) || c != '[')
97c1311ad4SAlexander Graf return -1;
98c1311ad4SAlexander Graf
99c1311ad4SAlexander Graf n[0] = 0;
100c1311ad4SAlexander Graf while (1) {
101*dd1a1ec2SMatthias Brugger if (!term_get_char(&c)) {
102c1311ad4SAlexander Graf if (c == ';') {
103c1311ad4SAlexander Graf i++;
10462217295SHeinrich Schuchardt if (i >= num)
105c1311ad4SAlexander Graf return -1;
106c1311ad4SAlexander Graf n[i] = 0;
107c1311ad4SAlexander Graf continue;
108c1311ad4SAlexander Graf } else if (c == end_char) {
109c1311ad4SAlexander Graf break;
110c1311ad4SAlexander Graf } else if (c > '9' || c < '0') {
111c1311ad4SAlexander Graf return -1;
112c1311ad4SAlexander Graf }
113c1311ad4SAlexander Graf
114c1311ad4SAlexander Graf /* Read one more decimal position */
115c1311ad4SAlexander Graf n[i] *= 10;
116c1311ad4SAlexander Graf n[i] += c - '0';
117*dd1a1ec2SMatthias Brugger } else {
118*dd1a1ec2SMatthias Brugger return -1;
119*dd1a1ec2SMatthias Brugger }
120c1311ad4SAlexander Graf }
12162217295SHeinrich Schuchardt if (i != num - 1)
12262217295SHeinrich Schuchardt return -1;
123c1311ad4SAlexander Graf
124c1311ad4SAlexander Graf return 0;
125c1311ad4SAlexander Graf }
126c1311ad4SAlexander Graf
efi_cout_output_string(struct efi_simple_text_output_protocol * this,const efi_string_t string)127c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_output_string(
128c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
1293a45bc7fSRob Clark const efi_string_t string)
130c1311ad4SAlexander Graf {
1313a45bc7fSRob Clark struct simple_text_output_mode *con = &efi_con_mode;
1323a45bc7fSRob Clark struct cout_mode *mode = &efi_cout_modes[con->mode];
133ba7bd5c2SHeinrich Schuchardt char *buf, *pos;
134ba7bd5c2SHeinrich Schuchardt u16 *p;
135ba7bd5c2SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
136c1311ad4SAlexander Graf
137c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, string);
1383a45bc7fSRob Clark
139ba7bd5c2SHeinrich Schuchardt buf = malloc(utf16_utf8_strlen(string) + 1);
140ba7bd5c2SHeinrich Schuchardt if (!buf) {
141ba7bd5c2SHeinrich Schuchardt ret = EFI_OUT_OF_RESOURCES;
142ba7bd5c2SHeinrich Schuchardt goto out;
143ba7bd5c2SHeinrich Schuchardt }
144ba7bd5c2SHeinrich Schuchardt pos = buf;
145ba7bd5c2SHeinrich Schuchardt utf16_utf8_strcpy(&pos, string);
1463a45bc7fSRob Clark fputs(stdout, buf);
147ba7bd5c2SHeinrich Schuchardt free(buf);
1483a45bc7fSRob Clark
1497ca7c3c0SHeinrich Schuchardt /*
1507ca7c3c0SHeinrich Schuchardt * Update the cursor position.
1517ca7c3c0SHeinrich Schuchardt *
1527ca7c3c0SHeinrich Schuchardt * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
1537ca7c3c0SHeinrich Schuchardt * and U000D. All other characters, including control characters
15414d103bbSHeinrich Schuchardt * U+0007 (BEL) and U+0009 (TAB), have to increase the column by one.
1557ca7c3c0SHeinrich Schuchardt */
1567ca7c3c0SHeinrich Schuchardt for (p = string; *p; ++p) {
1573a45bc7fSRob Clark switch (*p) {
1587ca7c3c0SHeinrich Schuchardt case '\b': /* U+0008, backspace */
1597ca7c3c0SHeinrich Schuchardt con->cursor_column = max(0, con->cursor_column - 1);
1603a45bc7fSRob Clark break;
1617ca7c3c0SHeinrich Schuchardt case '\n': /* U+000A, newline */
1623a45bc7fSRob Clark con->cursor_column = 0;
1633a45bc7fSRob Clark con->cursor_row++;
1643a45bc7fSRob Clark break;
1657ca7c3c0SHeinrich Schuchardt case '\r': /* U+000D, carriage-return */
1667ca7c3c0SHeinrich Schuchardt con->cursor_column = 0;
1673a45bc7fSRob Clark break;
1687ca7c3c0SHeinrich Schuchardt case 0xd800 ... 0xdbff:
1697ca7c3c0SHeinrich Schuchardt /*
1707ca7c3c0SHeinrich Schuchardt * Ignore high surrogates, we do not want to count a
1717ca7c3c0SHeinrich Schuchardt * Unicode character twice.
1727ca7c3c0SHeinrich Schuchardt */
1733a45bc7fSRob Clark break;
1743a45bc7fSRob Clark default:
1753a45bc7fSRob Clark con->cursor_column++;
1763a45bc7fSRob Clark break;
177c1311ad4SAlexander Graf }
1783a45bc7fSRob Clark if (con->cursor_column >= mode->columns) {
1793a45bc7fSRob Clark con->cursor_column = 0;
1803a45bc7fSRob Clark con->cursor_row++;
1813a45bc7fSRob Clark }
1823a45bc7fSRob Clark con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
183c1311ad4SAlexander Graf }
184c1311ad4SAlexander Graf
185ba7bd5c2SHeinrich Schuchardt out:
186ba7bd5c2SHeinrich Schuchardt return EFI_EXIT(ret);
187c1311ad4SAlexander Graf }
188c1311ad4SAlexander Graf
efi_cout_test_string(struct efi_simple_text_output_protocol * this,const efi_string_t string)189c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_test_string(
190c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
1913a45bc7fSRob Clark const efi_string_t string)
192c1311ad4SAlexander Graf {
193c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, string);
194c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS);
195c1311ad4SAlexander Graf }
196c1311ad4SAlexander Graf
cout_mode_matches(struct cout_mode * mode,int rows,int cols)1975be8b0a3SEmmanuel Vadot static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
1985be8b0a3SEmmanuel Vadot {
1995be8b0a3SEmmanuel Vadot if (!mode->present)
2005be8b0a3SEmmanuel Vadot return false;
2015be8b0a3SEmmanuel Vadot
2025be8b0a3SEmmanuel Vadot return (mode->rows == rows) && (mode->columns == cols);
2035be8b0a3SEmmanuel Vadot }
2045be8b0a3SEmmanuel Vadot
2056bb591f7SHeinrich Schuchardt /**
2066bb591f7SHeinrich Schuchardt * query_console_serial() - query console size
2076bb591f7SHeinrich Schuchardt *
2086bb591f7SHeinrich Schuchardt * @rows pointer to return number of rows
2096bb591f7SHeinrich Schuchardt * @columns pointer to return number of columns
2106bb591f7SHeinrich Schuchardt * Returns 0 on success
2116bb591f7SHeinrich Schuchardt */
query_console_serial(int * rows,int * cols)21271cc25c3SRob Clark static int query_console_serial(int *rows, int *cols)
213c1311ad4SAlexander Graf {
2146bb591f7SHeinrich Schuchardt int ret = 0;
2156bb591f7SHeinrich Schuchardt int n[2];
216c1311ad4SAlexander Graf
217c1311ad4SAlexander Graf /* Empty input buffer */
218c1311ad4SAlexander Graf while (tstc())
219c1311ad4SAlexander Graf getc();
220c1311ad4SAlexander Graf
2216bb591f7SHeinrich Schuchardt /*
2226bb591f7SHeinrich Schuchardt * Not all terminals understand CSI [18t for querying the console size.
2236bb591f7SHeinrich Schuchardt * We should adhere to escape sequences documented in the console_codes
2246bb591f7SHeinrich Schuchardt * man page and the ECMA-48 standard.
2256bb591f7SHeinrich Schuchardt *
2266bb591f7SHeinrich Schuchardt * So here we follow a different approach. We position the cursor to the
2276bb591f7SHeinrich Schuchardt * bottom right and query its position. Before leaving the function we
2286bb591f7SHeinrich Schuchardt * restore the original cursor position.
2296bb591f7SHeinrich Schuchardt */
2306bb591f7SHeinrich Schuchardt printf(ESC "7" /* Save cursor position */
2316bb591f7SHeinrich Schuchardt ESC "[r" /* Set scrolling region to full window */
2326bb591f7SHeinrich Schuchardt ESC "[999;999H" /* Move to bottom right corner */
2336bb591f7SHeinrich Schuchardt ESC "[6n"); /* Query cursor position */
234c1311ad4SAlexander Graf
2356bb591f7SHeinrich Schuchardt /* Read {rows,cols} */
2366bb591f7SHeinrich Schuchardt if (term_read_reply(n, 2, 'R')) {
2376bb591f7SHeinrich Schuchardt ret = 1;
2386bb591f7SHeinrich Schuchardt goto out;
2396bb591f7SHeinrich Schuchardt }
24071cc25c3SRob Clark
2416bb591f7SHeinrich Schuchardt *cols = n[1];
2426bb591f7SHeinrich Schuchardt *rows = n[0];
2436bb591f7SHeinrich Schuchardt out:
2446bb591f7SHeinrich Schuchardt printf(ESC "8"); /* Restore cursor position */
2456bb591f7SHeinrich Schuchardt return ret;
246c1311ad4SAlexander Graf }
247c1311ad4SAlexander Graf
248a4aa7befSHeinrich Schuchardt /*
249a4aa7befSHeinrich Schuchardt * Update the mode table.
250a4aa7befSHeinrich Schuchardt *
251a4aa7befSHeinrich Schuchardt * By default the only mode available is 80x25. If the console has at least 50
252a4aa7befSHeinrich Schuchardt * lines, enable mode 80x50. If we can query the console size and it is neither
253a4aa7befSHeinrich Schuchardt * 80x25 nor 80x50, set it as an additional mode.
254a4aa7befSHeinrich Schuchardt */
query_console_size(void)255a4aa7befSHeinrich Schuchardt static void query_console_size(void)
25671cc25c3SRob Clark {
257a18c5a83SRob Clark const char *stdout_name = env_get("stdout");
25880483b2aSAlexander Graf int rows = 25, cols = 80;
25971cc25c3SRob Clark
260a18c5a83SRob Clark if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
261a18c5a83SRob Clark IS_ENABLED(CONFIG_DM_VIDEO)) {
262a18c5a83SRob Clark struct stdio_dev *stdout_dev =
263a18c5a83SRob Clark stdio_get_by_name("vidconsole");
264a18c5a83SRob Clark struct udevice *dev = stdout_dev->priv;
265a18c5a83SRob Clark struct vidconsole_priv *priv =
266a18c5a83SRob Clark dev_get_uclass_priv(dev);
267a18c5a83SRob Clark rows = priv->rows;
268a18c5a83SRob Clark cols = priv->cols;
269a18c5a83SRob Clark } else if (query_console_serial(&rows, &cols)) {
270a4aa7befSHeinrich Schuchardt return;
271a18c5a83SRob Clark }
2725be8b0a3SEmmanuel Vadot
2735be8b0a3SEmmanuel Vadot /* Test if we can have Mode 1 */
2745be8b0a3SEmmanuel Vadot if (cols >= 80 && rows >= 50) {
2755be8b0a3SEmmanuel Vadot efi_cout_modes[1].present = 1;
2765be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = 2;
277c1311ad4SAlexander Graf }
278c1311ad4SAlexander Graf
2795be8b0a3SEmmanuel Vadot /*
2805be8b0a3SEmmanuel Vadot * Install our mode as mode 2 if it is different
2815be8b0a3SEmmanuel Vadot * than mode 0 or 1 and set it as the currently selected mode
2825be8b0a3SEmmanuel Vadot */
2835be8b0a3SEmmanuel Vadot if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
2845be8b0a3SEmmanuel Vadot !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
2855be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
2865be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
2875be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].present = 1;
2885be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
2895be8b0a3SEmmanuel Vadot efi_con_mode.mode = EFI_COUT_MODE_2;
2905be8b0a3SEmmanuel Vadot }
2915be8b0a3SEmmanuel Vadot }
2925be8b0a3SEmmanuel Vadot
efi_cout_query_mode(struct efi_simple_text_output_protocol * this,unsigned long mode_number,unsigned long * columns,unsigned long * rows)293a4aa7befSHeinrich Schuchardt static efi_status_t EFIAPI efi_cout_query_mode(
294a4aa7befSHeinrich Schuchardt struct efi_simple_text_output_protocol *this,
295a4aa7befSHeinrich Schuchardt unsigned long mode_number, unsigned long *columns,
296a4aa7befSHeinrich Schuchardt unsigned long *rows)
297a4aa7befSHeinrich Schuchardt {
298a4aa7befSHeinrich Schuchardt EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
299a4aa7befSHeinrich Schuchardt
3005be8b0a3SEmmanuel Vadot if (mode_number >= efi_con_mode.max_mode)
3015be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED);
3025be8b0a3SEmmanuel Vadot
3035be8b0a3SEmmanuel Vadot if (efi_cout_modes[mode_number].present != 1)
3045be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED);
3055be8b0a3SEmmanuel Vadot
306c1311ad4SAlexander Graf if (columns)
3075be8b0a3SEmmanuel Vadot *columns = efi_cout_modes[mode_number].columns;
308c1311ad4SAlexander Graf if (rows)
3095be8b0a3SEmmanuel Vadot *rows = efi_cout_modes[mode_number].rows;
310c1311ad4SAlexander Graf
311c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS);
312c1311ad4SAlexander Graf }
313c1311ad4SAlexander Graf
efi_cout_set_mode(struct efi_simple_text_output_protocol * this,unsigned long mode_number)314c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_mode(
315c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
316c1311ad4SAlexander Graf unsigned long mode_number)
317c1311ad4SAlexander Graf {
318c1311ad4SAlexander Graf EFI_ENTRY("%p, %ld", this, mode_number);
319c1311ad4SAlexander Graf
320c1311ad4SAlexander Graf
3215be8b0a3SEmmanuel Vadot if (mode_number > efi_con_mode.max_mode)
322c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED);
3235be8b0a3SEmmanuel Vadot
3245be8b0a3SEmmanuel Vadot efi_con_mode.mode = mode_number;
3255be8b0a3SEmmanuel Vadot efi_con_mode.cursor_column = 0;
3265be8b0a3SEmmanuel Vadot efi_con_mode.cursor_row = 0;
3275be8b0a3SEmmanuel Vadot
3285be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_SUCCESS);
329c1311ad4SAlexander Graf }
330c1311ad4SAlexander Graf
3312d5dc2a5SRob Clark static const struct {
3322d5dc2a5SRob Clark unsigned int fg;
3332d5dc2a5SRob Clark unsigned int bg;
3342d5dc2a5SRob Clark } color[] = {
3352d5dc2a5SRob Clark { 30, 40 }, /* 0: black */
3362d5dc2a5SRob Clark { 34, 44 }, /* 1: blue */
3372d5dc2a5SRob Clark { 32, 42 }, /* 2: green */
3382d5dc2a5SRob Clark { 36, 46 }, /* 3: cyan */
3392d5dc2a5SRob Clark { 31, 41 }, /* 4: red */
3402d5dc2a5SRob Clark { 35, 45 }, /* 5: magenta */
34114d103bbSHeinrich Schuchardt { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
34214d103bbSHeinrich Schuchardt { 37, 47 }, /* 7: light gray, map to white */
3432d5dc2a5SRob Clark };
3442d5dc2a5SRob Clark
3452d5dc2a5SRob Clark /* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
efi_cout_set_attribute(struct efi_simple_text_output_protocol * this,unsigned long attribute)346c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_attribute(
347c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
348c1311ad4SAlexander Graf unsigned long attribute)
349c1311ad4SAlexander Graf {
3502d5dc2a5SRob Clark unsigned int bold = EFI_ATTR_BOLD(attribute);
3512d5dc2a5SRob Clark unsigned int fg = EFI_ATTR_FG(attribute);
3522d5dc2a5SRob Clark unsigned int bg = EFI_ATTR_BG(attribute);
3532d5dc2a5SRob Clark
354c1311ad4SAlexander Graf EFI_ENTRY("%p, %lx", this, attribute);
355c1311ad4SAlexander Graf
3562d5dc2a5SRob Clark if (attribute)
3572d5dc2a5SRob Clark printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
3582d5dc2a5SRob Clark else
3592d5dc2a5SRob Clark printf(ESC"[0;37;40m");
3602d5dc2a5SRob Clark
3612d5dc2a5SRob Clark return EFI_EXIT(EFI_SUCCESS);
362c1311ad4SAlexander Graf }
363c1311ad4SAlexander Graf
efi_cout_clear_screen(struct efi_simple_text_output_protocol * this)364c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_clear_screen(
365c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this)
366c1311ad4SAlexander Graf {
367c1311ad4SAlexander Graf EFI_ENTRY("%p", this);
368c1311ad4SAlexander Graf
369c1311ad4SAlexander Graf printf(ESC"[2J");
370e67ff94dSHeinrich Schuchardt efi_con_mode.cursor_column = 0;
371e67ff94dSHeinrich Schuchardt efi_con_mode.cursor_row = 0;
372c1311ad4SAlexander Graf
373c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS);
374c1311ad4SAlexander Graf }
375c1311ad4SAlexander Graf
efi_cout_reset(struct efi_simple_text_output_protocol * this,char extended_verification)3769d12daffSHeinrich Schuchardt static efi_status_t EFIAPI efi_cout_reset(
3779d12daffSHeinrich Schuchardt struct efi_simple_text_output_protocol *this,
3789d12daffSHeinrich Schuchardt char extended_verification)
3799d12daffSHeinrich Schuchardt {
3809d12daffSHeinrich Schuchardt EFI_ENTRY("%p, %d", this, extended_verification);
3819d12daffSHeinrich Schuchardt
3829d12daffSHeinrich Schuchardt /* Clear screen */
3839d12daffSHeinrich Schuchardt EFI_CALL(efi_cout_clear_screen(this));
3849d12daffSHeinrich Schuchardt /* Set default colors */
3859d12daffSHeinrich Schuchardt printf(ESC "[0;37;40m");
3869d12daffSHeinrich Schuchardt
3879d12daffSHeinrich Schuchardt return EFI_EXIT(EFI_SUCCESS);
3889d12daffSHeinrich Schuchardt }
3899d12daffSHeinrich Schuchardt
efi_cout_set_cursor_position(struct efi_simple_text_output_protocol * this,unsigned long column,unsigned long row)390c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_cursor_position(
391c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
392c1311ad4SAlexander Graf unsigned long column, unsigned long row)
393c1311ad4SAlexander Graf {
394aaace4b0SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
395aaace4b0SHeinrich Schuchardt struct simple_text_output_mode *con = &efi_con_mode;
396aaace4b0SHeinrich Schuchardt struct cout_mode *mode = &efi_cout_modes[con->mode];
397aaace4b0SHeinrich Schuchardt
398c1311ad4SAlexander Graf EFI_ENTRY("%p, %ld, %ld", this, column, row);
399c1311ad4SAlexander Graf
400aaace4b0SHeinrich Schuchardt /* Check parameters */
401aaace4b0SHeinrich Schuchardt if (!this) {
402aaace4b0SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
403aaace4b0SHeinrich Schuchardt goto out;
404aaace4b0SHeinrich Schuchardt }
405aaace4b0SHeinrich Schuchardt if (row >= mode->rows || column >= mode->columns) {
406aaace4b0SHeinrich Schuchardt ret = EFI_UNSUPPORTED;
407aaace4b0SHeinrich Schuchardt goto out;
408aaace4b0SHeinrich Schuchardt }
409aaace4b0SHeinrich Schuchardt
410aaace4b0SHeinrich Schuchardt /*
411aaace4b0SHeinrich Schuchardt * Set cursor position by sending CSI H.
412aaace4b0SHeinrich Schuchardt * EFI origin is [0, 0], terminal origin is [1, 1].
413aaace4b0SHeinrich Schuchardt */
414aaace4b0SHeinrich Schuchardt printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
415c1311ad4SAlexander Graf efi_con_mode.cursor_column = column;
416c1311ad4SAlexander Graf efi_con_mode.cursor_row = row;
417aaace4b0SHeinrich Schuchardt out:
418aaace4b0SHeinrich Schuchardt return EFI_EXIT(ret);
419c1311ad4SAlexander Graf }
420c1311ad4SAlexander Graf
efi_cout_enable_cursor(struct efi_simple_text_output_protocol * this,bool enable)421c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_enable_cursor(
422c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this,
423c1311ad4SAlexander Graf bool enable)
424c1311ad4SAlexander Graf {
425c1311ad4SAlexander Graf EFI_ENTRY("%p, %d", this, enable);
426c1311ad4SAlexander Graf
427c1311ad4SAlexander Graf printf(ESC"[?25%c", enable ? 'h' : 'l');
428c1311ad4SAlexander Graf
429c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS);
430c1311ad4SAlexander Graf }
431c1311ad4SAlexander Graf
432ebb4dd5bSHeinrich Schuchardt struct efi_simple_text_output_protocol efi_con_out = {
433c1311ad4SAlexander Graf .reset = efi_cout_reset,
434c1311ad4SAlexander Graf .output_string = efi_cout_output_string,
435c1311ad4SAlexander Graf .test_string = efi_cout_test_string,
436c1311ad4SAlexander Graf .query_mode = efi_cout_query_mode,
437c1311ad4SAlexander Graf .set_mode = efi_cout_set_mode,
438c1311ad4SAlexander Graf .set_attribute = efi_cout_set_attribute,
439c1311ad4SAlexander Graf .clear_screen = efi_cout_clear_screen,
440c1311ad4SAlexander Graf .set_cursor_position = efi_cout_set_cursor_position,
441c1311ad4SAlexander Graf .enable_cursor = efi_cout_enable_cursor,
442c1311ad4SAlexander Graf .mode = (void*)&efi_con_mode,
443c1311ad4SAlexander Graf };
444c1311ad4SAlexander Graf
4454fdcf066SHeinrich Schuchardt /**
4464fdcf066SHeinrich Schuchardt * struct efi_cin_notify_function - registered console input notify function
4474fdcf066SHeinrich Schuchardt *
4484fdcf066SHeinrich Schuchardt * @link: link to list
4494fdcf066SHeinrich Schuchardt * @data: key to notify
4504fdcf066SHeinrich Schuchardt * @function: function to call
4514fdcf066SHeinrich Schuchardt */
4524fdcf066SHeinrich Schuchardt struct efi_cin_notify_function {
4534fdcf066SHeinrich Schuchardt struct list_head link;
4544fdcf066SHeinrich Schuchardt struct efi_key_data key;
4554fdcf066SHeinrich Schuchardt efi_status_t (EFIAPI *function)
4564fdcf066SHeinrich Schuchardt (struct efi_key_data *key_data);
4574fdcf066SHeinrich Schuchardt };
4584fdcf066SHeinrich Schuchardt
4590dfd13a4SHeinrich Schuchardt static bool key_available;
460110c6280SHeinrich Schuchardt static struct efi_key_data next_key;
4614fdcf066SHeinrich Schuchardt static LIST_HEAD(cin_notify_functions);
4624f187897SHeinrich Schuchardt
4630dfd13a4SHeinrich Schuchardt /**
46455fbdf99SHeinrich Schuchardt * set_shift_mask() - set shift mask
46555fbdf99SHeinrich Schuchardt *
46655fbdf99SHeinrich Schuchardt * @mod: Xterm shift mask
46755fbdf99SHeinrich Schuchardt */
set_shift_mask(int mod,struct efi_key_state * key_state)46855fbdf99SHeinrich Schuchardt void set_shift_mask(int mod, struct efi_key_state *key_state)
46955fbdf99SHeinrich Schuchardt {
47055fbdf99SHeinrich Schuchardt key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
47155fbdf99SHeinrich Schuchardt if (mod) {
47255fbdf99SHeinrich Schuchardt --mod;
47355fbdf99SHeinrich Schuchardt if (mod & 1)
47455fbdf99SHeinrich Schuchardt key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
47555fbdf99SHeinrich Schuchardt if (mod & 2)
47655fbdf99SHeinrich Schuchardt key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
47755fbdf99SHeinrich Schuchardt if (mod & 4)
47855fbdf99SHeinrich Schuchardt key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
47955fbdf99SHeinrich Schuchardt if (mod & 8)
48055fbdf99SHeinrich Schuchardt key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
48155fbdf99SHeinrich Schuchardt } else {
48255fbdf99SHeinrich Schuchardt key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
48355fbdf99SHeinrich Schuchardt }
48455fbdf99SHeinrich Schuchardt }
48555fbdf99SHeinrich Schuchardt
48655fbdf99SHeinrich Schuchardt /**
487110c6280SHeinrich Schuchardt * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
4880dfd13a4SHeinrich Schuchardt *
4890fb4169eSHeinrich Schuchardt * This gets called when we have already parsed CSI.
4900fb4169eSHeinrich Schuchardt *
4910fb4169eSHeinrich Schuchardt * @modifiers: bit mask (shift, alt, ctrl)
4920fb4169eSHeinrich Schuchardt * @return: the unmodified code
4930fb4169eSHeinrich Schuchardt */
analyze_modifiers(struct efi_key_state * key_state)494110c6280SHeinrich Schuchardt static int analyze_modifiers(struct efi_key_state *key_state)
4950fb4169eSHeinrich Schuchardt {
496110c6280SHeinrich Schuchardt int c, mod = 0, ret = 0;
4970fb4169eSHeinrich Schuchardt
4980fb4169eSHeinrich Schuchardt c = getc();
4990fb4169eSHeinrich Schuchardt
5000fb4169eSHeinrich Schuchardt if (c != ';') {
5010fb4169eSHeinrich Schuchardt ret = c;
5020fb4169eSHeinrich Schuchardt if (c == '~')
5030fb4169eSHeinrich Schuchardt goto out;
5040fb4169eSHeinrich Schuchardt c = getc();
5050fb4169eSHeinrich Schuchardt }
5060fb4169eSHeinrich Schuchardt for (;;) {
5070fb4169eSHeinrich Schuchardt switch (c) {
5080fb4169eSHeinrich Schuchardt case '0'...'9':
5090fb4169eSHeinrich Schuchardt mod *= 10;
5100fb4169eSHeinrich Schuchardt mod += c - '0';
5110fb4169eSHeinrich Schuchardt /* fall through */
5120fb4169eSHeinrich Schuchardt case ';':
5130fb4169eSHeinrich Schuchardt c = getc();
5140fb4169eSHeinrich Schuchardt break;
5150fb4169eSHeinrich Schuchardt default:
5160fb4169eSHeinrich Schuchardt goto out;
5170fb4169eSHeinrich Schuchardt }
5180fb4169eSHeinrich Schuchardt }
5190fb4169eSHeinrich Schuchardt out:
52055fbdf99SHeinrich Schuchardt set_shift_mask(mod, key_state);
5210fb4169eSHeinrich Schuchardt if (!ret)
5220fb4169eSHeinrich Schuchardt ret = c;
5230fb4169eSHeinrich Schuchardt return ret;
5240fb4169eSHeinrich Schuchardt }
5250fb4169eSHeinrich Schuchardt
5260dfd13a4SHeinrich Schuchardt /**
5270dfd13a4SHeinrich Schuchardt * efi_cin_read_key() - read a key from the console input
5280dfd13a4SHeinrich Schuchardt *
5290dfd13a4SHeinrich Schuchardt * @key: - key received
5300dfd13a4SHeinrich Schuchardt * Return: - status code
5310dfd13a4SHeinrich Schuchardt */
efi_cin_read_key(struct efi_key_data * key)532110c6280SHeinrich Schuchardt static efi_status_t efi_cin_read_key(struct efi_key_data *key)
533c1311ad4SAlexander Graf {
534c1311ad4SAlexander Graf struct efi_input_key pressed_key = {
535c1311ad4SAlexander Graf .scan_code = 0,
536c1311ad4SAlexander Graf .unicode_char = 0,
537c1311ad4SAlexander Graf };
53835cbb796SHeinrich Schuchardt s32 ch;
539c1311ad4SAlexander Graf
54055fbdf99SHeinrich Schuchardt if (console_read_unicode(&ch))
5410dfd13a4SHeinrich Schuchardt return EFI_NOT_READY;
542110c6280SHeinrich Schuchardt
543110c6280SHeinrich Schuchardt key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
544110c6280SHeinrich Schuchardt key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
545110c6280SHeinrich Schuchardt
54635cbb796SHeinrich Schuchardt /* We do not support multi-word codes */
54735cbb796SHeinrich Schuchardt if (ch >= 0x10000)
54835cbb796SHeinrich Schuchardt ch = '?';
54955fbdf99SHeinrich Schuchardt
55055fbdf99SHeinrich Schuchardt switch (ch) {
55155fbdf99SHeinrich Schuchardt case 0x1b:
5520fb4169eSHeinrich Schuchardt /*
5530fb4169eSHeinrich Schuchardt * Xterm Control Sequences
5540fb4169eSHeinrich Schuchardt * https://www.xfree86.org/4.8.0/ctlseqs.html
5550fb4169eSHeinrich Schuchardt */
556c1311ad4SAlexander Graf ch = getc();
557c1311ad4SAlexander Graf switch (ch) {
558c1311ad4SAlexander Graf case cESC: /* ESC */
559c1311ad4SAlexander Graf pressed_key.scan_code = 23;
560c1311ad4SAlexander Graf break;
561c1311ad4SAlexander Graf case 'O': /* F1 - F4 */
5620fb4169eSHeinrich Schuchardt ch = getc();
56355fbdf99SHeinrich Schuchardt /* consider modifiers */
56455fbdf99SHeinrich Schuchardt if (ch < 'P') {
56555fbdf99SHeinrich Schuchardt set_shift_mask(ch - '0', &key->key_state);
5660fb4169eSHeinrich Schuchardt ch = getc();
56755fbdf99SHeinrich Schuchardt }
5680fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - 'P' + 11;
569c1311ad4SAlexander Graf break;
570c1311ad4SAlexander Graf case '[':
571c1311ad4SAlexander Graf ch = getc();
572c1311ad4SAlexander Graf switch (ch) {
573c1311ad4SAlexander Graf case 'A'...'D': /* up, down right, left */
574c1311ad4SAlexander Graf pressed_key.scan_code = ch - 'A' + 1;
575c1311ad4SAlexander Graf break;
576c1311ad4SAlexander Graf case 'F': /* End */
577c1311ad4SAlexander Graf pressed_key.scan_code = 6;
578c1311ad4SAlexander Graf break;
579c1311ad4SAlexander Graf case 'H': /* Home */
580c1311ad4SAlexander Graf pressed_key.scan_code = 5;
581c1311ad4SAlexander Graf break;
5820fb4169eSHeinrich Schuchardt case '1':
583110c6280SHeinrich Schuchardt ch = analyze_modifiers(&key->key_state);
5840fb4169eSHeinrich Schuchardt switch (ch) {
5850fb4169eSHeinrich Schuchardt case '1'...'5': /* F1 - F5 */
5860fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - '1' + 11;
587c1311ad4SAlexander Graf break;
5880fb4169eSHeinrich Schuchardt case '7'...'9': /* F6 - F8 */
5890fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - '7' + 16;
5900fb4169eSHeinrich Schuchardt break;
5910fb4169eSHeinrich Schuchardt case 'A'...'D': /* up, down right, left */
5920fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - 'A' + 1;
5930fb4169eSHeinrich Schuchardt break;
5940fb4169eSHeinrich Schuchardt case 'F':
5950fb4169eSHeinrich Schuchardt pressed_key.scan_code = 6; /* End */
5960fb4169eSHeinrich Schuchardt break;
5970fb4169eSHeinrich Schuchardt case 'H':
5980fb4169eSHeinrich Schuchardt pressed_key.scan_code = 5; /* Home */
5990fb4169eSHeinrich Schuchardt break;
6000fb4169eSHeinrich Schuchardt }
6010fb4169eSHeinrich Schuchardt break;
6020fb4169eSHeinrich Schuchardt case '2':
603110c6280SHeinrich Schuchardt ch = analyze_modifiers(&key->key_state);
6040fb4169eSHeinrich Schuchardt switch (ch) {
6050fb4169eSHeinrich Schuchardt case '0'...'1': /* F9 - F10 */
6060fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - '0' + 19;
6070fb4169eSHeinrich Schuchardt break;
6080fb4169eSHeinrich Schuchardt case '3'...'4': /* F11 - F12 */
6090fb4169eSHeinrich Schuchardt pressed_key.scan_code = ch - '3' + 21;
6100fb4169eSHeinrich Schuchardt break;
6110fb4169eSHeinrich Schuchardt case '~': /* INS */
6120fb4169eSHeinrich Schuchardt pressed_key.scan_code = 7;
6130fb4169eSHeinrich Schuchardt break;
6140fb4169eSHeinrich Schuchardt }
615c1311ad4SAlexander Graf break;
616c1311ad4SAlexander Graf case '3': /* DEL */
617c1311ad4SAlexander Graf pressed_key.scan_code = 8;
618110c6280SHeinrich Schuchardt analyze_modifiers(&key->key_state);
6190fb4169eSHeinrich Schuchardt break;
6200fb4169eSHeinrich Schuchardt case '5': /* PG UP */
6210fb4169eSHeinrich Schuchardt pressed_key.scan_code = 9;
622110c6280SHeinrich Schuchardt analyze_modifiers(&key->key_state);
6230fb4169eSHeinrich Schuchardt break;
6240fb4169eSHeinrich Schuchardt case '6': /* PG DOWN */
6250fb4169eSHeinrich Schuchardt pressed_key.scan_code = 10;
626110c6280SHeinrich Schuchardt analyze_modifiers(&key->key_state);
627c1311ad4SAlexander Graf break;
62855fbdf99SHeinrich Schuchardt } /* [ */
62955fbdf99SHeinrich Schuchardt break;
63055fbdf99SHeinrich Schuchardt default:
63155fbdf99SHeinrich Schuchardt /* ALT key */
63255fbdf99SHeinrich Schuchardt set_shift_mask(3, &key->key_state);
633c1311ad4SAlexander Graf }
634c1311ad4SAlexander Graf break;
63555fbdf99SHeinrich Schuchardt case 0x7f:
636c1311ad4SAlexander Graf /* Backspace */
637c1311ad4SAlexander Graf ch = 0x08;
638c1311ad4SAlexander Graf }
639110c6280SHeinrich Schuchardt if (pressed_key.scan_code) {
640110c6280SHeinrich Schuchardt key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
641110c6280SHeinrich Schuchardt } else {
642c1311ad4SAlexander Graf pressed_key.unicode_char = ch;
643110c6280SHeinrich Schuchardt
644110c6280SHeinrich Schuchardt /*
645110c6280SHeinrich Schuchardt * Assume left control key for control characters typically
646110c6280SHeinrich Schuchardt * entered using the control key.
647110c6280SHeinrich Schuchardt */
648110c6280SHeinrich Schuchardt if (ch >= 0x01 && ch <= 0x1f) {
64955fbdf99SHeinrich Schuchardt key->key_state.key_shift_state |=
650110c6280SHeinrich Schuchardt EFI_SHIFT_STATE_VALID;
651110c6280SHeinrich Schuchardt switch (ch) {
652110c6280SHeinrich Schuchardt case 0x01 ... 0x07:
653110c6280SHeinrich Schuchardt case 0x0b ... 0x0c:
654110c6280SHeinrich Schuchardt case 0x0e ... 0x1f:
655110c6280SHeinrich Schuchardt key->key_state.key_shift_state |=
656110c6280SHeinrich Schuchardt EFI_LEFT_CONTROL_PRESSED;
657110c6280SHeinrich Schuchardt }
658110c6280SHeinrich Schuchardt }
659110c6280SHeinrich Schuchardt }
660110c6280SHeinrich Schuchardt key->key = pressed_key;
661c1311ad4SAlexander Graf
6620dfd13a4SHeinrich Schuchardt return EFI_SUCCESS;
6630dfd13a4SHeinrich Schuchardt }
6640dfd13a4SHeinrich Schuchardt
6650dfd13a4SHeinrich Schuchardt /**
6664fdcf066SHeinrich Schuchardt * efi_cin_notify() - notify registered functions
6674fdcf066SHeinrich Schuchardt */
efi_cin_notify(void)6684fdcf066SHeinrich Schuchardt static void efi_cin_notify(void)
6694fdcf066SHeinrich Schuchardt {
6704fdcf066SHeinrich Schuchardt struct efi_cin_notify_function *item;
6714fdcf066SHeinrich Schuchardt
6724fdcf066SHeinrich Schuchardt list_for_each_entry(item, &cin_notify_functions, link) {
6734fdcf066SHeinrich Schuchardt bool match = true;
6744fdcf066SHeinrich Schuchardt
6754fdcf066SHeinrich Schuchardt /* We do not support toggle states */
6764fdcf066SHeinrich Schuchardt if (item->key.key.unicode_char || item->key.key.scan_code) {
6774fdcf066SHeinrich Schuchardt if (item->key.key.unicode_char !=
6784fdcf066SHeinrich Schuchardt next_key.key.unicode_char ||
6794fdcf066SHeinrich Schuchardt item->key.key.scan_code != next_key.key.scan_code)
6804fdcf066SHeinrich Schuchardt match = false;
6814fdcf066SHeinrich Schuchardt }
6824fdcf066SHeinrich Schuchardt if (item->key.key_state.key_shift_state &&
6834fdcf066SHeinrich Schuchardt item->key.key_state.key_shift_state !=
6844fdcf066SHeinrich Schuchardt next_key.key_state.key_shift_state)
6854fdcf066SHeinrich Schuchardt match = false;
6864fdcf066SHeinrich Schuchardt
6874fdcf066SHeinrich Schuchardt if (match)
6884fdcf066SHeinrich Schuchardt /* We don't bother about the return code */
6894fdcf066SHeinrich Schuchardt EFI_CALL(item->function(&next_key));
6904fdcf066SHeinrich Schuchardt }
6914fdcf066SHeinrich Schuchardt }
6924fdcf066SHeinrich Schuchardt
6934fdcf066SHeinrich Schuchardt /**
6940dfd13a4SHeinrich Schuchardt * efi_cin_check() - check if keyboard input is available
6950dfd13a4SHeinrich Schuchardt */
efi_cin_check(void)6960dfd13a4SHeinrich Schuchardt static void efi_cin_check(void)
6970dfd13a4SHeinrich Schuchardt {
6980dfd13a4SHeinrich Schuchardt efi_status_t ret;
6990dfd13a4SHeinrich Schuchardt
7000dfd13a4SHeinrich Schuchardt if (key_available) {
7010dfd13a4SHeinrich Schuchardt efi_signal_event(efi_con_in.wait_for_key, true);
7020dfd13a4SHeinrich Schuchardt return;
7030dfd13a4SHeinrich Schuchardt }
7040dfd13a4SHeinrich Schuchardt
7050dfd13a4SHeinrich Schuchardt if (tstc()) {
7060dfd13a4SHeinrich Schuchardt ret = efi_cin_read_key(&next_key);
7070dfd13a4SHeinrich Schuchardt if (ret == EFI_SUCCESS) {
7080dfd13a4SHeinrich Schuchardt key_available = true;
7090dfd13a4SHeinrich Schuchardt
7104fdcf066SHeinrich Schuchardt /* Notify registered functions */
7114fdcf066SHeinrich Schuchardt efi_cin_notify();
7124fdcf066SHeinrich Schuchardt
7130dfd13a4SHeinrich Schuchardt /* Queue the wait for key event */
7144fdcf066SHeinrich Schuchardt if (key_available)
7150dfd13a4SHeinrich Schuchardt efi_signal_event(efi_con_in.wait_for_key, true);
7160dfd13a4SHeinrich Schuchardt }
7170dfd13a4SHeinrich Schuchardt }
7180dfd13a4SHeinrich Schuchardt }
7190dfd13a4SHeinrich Schuchardt
7200dfd13a4SHeinrich Schuchardt /**
721110c6280SHeinrich Schuchardt * efi_cin_empty_buffer() - empty input buffer
722110c6280SHeinrich Schuchardt */
efi_cin_empty_buffer(void)723110c6280SHeinrich Schuchardt static void efi_cin_empty_buffer(void)
724110c6280SHeinrich Schuchardt {
725110c6280SHeinrich Schuchardt while (tstc())
726110c6280SHeinrich Schuchardt getc();
727110c6280SHeinrich Schuchardt key_available = false;
728110c6280SHeinrich Schuchardt }
729110c6280SHeinrich Schuchardt
730110c6280SHeinrich Schuchardt /**
731110c6280SHeinrich Schuchardt * efi_cin_reset_ex() - reset console input
732110c6280SHeinrich Schuchardt *
733110c6280SHeinrich Schuchardt * @this: - the extended simple text input protocol
734110c6280SHeinrich Schuchardt * @extended_verification: - extended verification
735110c6280SHeinrich Schuchardt *
736110c6280SHeinrich Schuchardt * This function implements the reset service of the
737110c6280SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
738110c6280SHeinrich Schuchardt *
739110c6280SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
740110c6280SHeinrich Schuchardt * details.
741110c6280SHeinrich Schuchardt *
742110c6280SHeinrich Schuchardt * Return: old value of the task priority level
743110c6280SHeinrich Schuchardt */
efi_cin_reset_ex(struct efi_simple_text_input_ex_protocol * this,bool extended_verification)744110c6280SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_reset_ex(
745110c6280SHeinrich Schuchardt struct efi_simple_text_input_ex_protocol *this,
746110c6280SHeinrich Schuchardt bool extended_verification)
747110c6280SHeinrich Schuchardt {
748110c6280SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
749110c6280SHeinrich Schuchardt
750110c6280SHeinrich Schuchardt EFI_ENTRY("%p, %d", this, extended_verification);
751110c6280SHeinrich Schuchardt
752110c6280SHeinrich Schuchardt /* Check parameters */
753110c6280SHeinrich Schuchardt if (!this) {
754110c6280SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
755110c6280SHeinrich Schuchardt goto out;
756110c6280SHeinrich Schuchardt }
757110c6280SHeinrich Schuchardt
758110c6280SHeinrich Schuchardt efi_cin_empty_buffer();
759110c6280SHeinrich Schuchardt out:
760110c6280SHeinrich Schuchardt return EFI_EXIT(ret);
761110c6280SHeinrich Schuchardt }
762110c6280SHeinrich Schuchardt
763110c6280SHeinrich Schuchardt /**
764110c6280SHeinrich Schuchardt * efi_cin_read_key_stroke_ex() - read key stroke
765110c6280SHeinrich Schuchardt *
766110c6280SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
767110c6280SHeinrich Schuchardt * @key_data: key read from console
768110c6280SHeinrich Schuchardt * Return: status code
769110c6280SHeinrich Schuchardt *
770110c6280SHeinrich Schuchardt * This function implements the ReadKeyStrokeEx service of the
771110c6280SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
772110c6280SHeinrich Schuchardt *
773110c6280SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
774110c6280SHeinrich Schuchardt * details.
775110c6280SHeinrich Schuchardt */
efi_cin_read_key_stroke_ex(struct efi_simple_text_input_ex_protocol * this,struct efi_key_data * key_data)776110c6280SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
777110c6280SHeinrich Schuchardt struct efi_simple_text_input_ex_protocol *this,
778110c6280SHeinrich Schuchardt struct efi_key_data *key_data)
779110c6280SHeinrich Schuchardt {
780110c6280SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
781110c6280SHeinrich Schuchardt
782110c6280SHeinrich Schuchardt EFI_ENTRY("%p, %p", this, key_data);
783110c6280SHeinrich Schuchardt
784110c6280SHeinrich Schuchardt /* Check parameters */
785110c6280SHeinrich Schuchardt if (!this || !key_data) {
786110c6280SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
787110c6280SHeinrich Schuchardt goto out;
788110c6280SHeinrich Schuchardt }
789110c6280SHeinrich Schuchardt
790110c6280SHeinrich Schuchardt /* We don't do interrupts, so check for timers cooperatively */
791110c6280SHeinrich Schuchardt efi_timer_check();
792110c6280SHeinrich Schuchardt
793110c6280SHeinrich Schuchardt /* Enable console input after ExitBootServices */
794110c6280SHeinrich Schuchardt efi_cin_check();
795110c6280SHeinrich Schuchardt
796110c6280SHeinrich Schuchardt if (!key_available) {
797110c6280SHeinrich Schuchardt ret = EFI_NOT_READY;
798110c6280SHeinrich Schuchardt goto out;
799110c6280SHeinrich Schuchardt }
800110c6280SHeinrich Schuchardt *key_data = next_key;
801110c6280SHeinrich Schuchardt key_available = false;
802110c6280SHeinrich Schuchardt efi_con_in.wait_for_key->is_signaled = false;
803110c6280SHeinrich Schuchardt out:
804110c6280SHeinrich Schuchardt return EFI_EXIT(ret);
805110c6280SHeinrich Schuchardt }
806110c6280SHeinrich Schuchardt
807110c6280SHeinrich Schuchardt /**
808110c6280SHeinrich Schuchardt * efi_cin_set_state() - set toggle key state
809110c6280SHeinrich Schuchardt *
810110c6280SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
811110c6280SHeinrich Schuchardt * @key_toggle_state: key toggle state
812110c6280SHeinrich Schuchardt * Return: status code
813110c6280SHeinrich Schuchardt *
814110c6280SHeinrich Schuchardt * This function implements the SetState service of the
815110c6280SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
816110c6280SHeinrich Schuchardt *
817110c6280SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
818110c6280SHeinrich Schuchardt * details.
819110c6280SHeinrich Schuchardt */
efi_cin_set_state(struct efi_simple_text_input_ex_protocol * this,u8 key_toggle_state)820110c6280SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_set_state(
821110c6280SHeinrich Schuchardt struct efi_simple_text_input_ex_protocol *this,
822110c6280SHeinrich Schuchardt u8 key_toggle_state)
823110c6280SHeinrich Schuchardt {
824110c6280SHeinrich Schuchardt EFI_ENTRY("%p, %u", this, key_toggle_state);
825110c6280SHeinrich Schuchardt /*
826110c6280SHeinrich Schuchardt * U-Boot supports multiple console input sources like serial and
827110c6280SHeinrich Schuchardt * net console for which a key toggle state cannot be set at all.
828110c6280SHeinrich Schuchardt *
829110c6280SHeinrich Schuchardt * According to the UEFI specification it is allowable to not implement
830110c6280SHeinrich Schuchardt * this service.
831110c6280SHeinrich Schuchardt */
832110c6280SHeinrich Schuchardt return EFI_EXIT(EFI_UNSUPPORTED);
833110c6280SHeinrich Schuchardt }
834110c6280SHeinrich Schuchardt
835110c6280SHeinrich Schuchardt /**
836110c6280SHeinrich Schuchardt * efi_cin_register_key_notify() - register key notification function
837110c6280SHeinrich Schuchardt *
838110c6280SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
839110c6280SHeinrich Schuchardt * @key_data: key to be notified
840110c6280SHeinrich Schuchardt * @key_notify_function: function to be called if the key is pressed
841110c6280SHeinrich Schuchardt * @notify_handle: handle for unregistering the notification
842110c6280SHeinrich Schuchardt * Return: status code
843110c6280SHeinrich Schuchardt *
844110c6280SHeinrich Schuchardt * This function implements the SetState service of the
845110c6280SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
846110c6280SHeinrich Schuchardt *
847110c6280SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
848110c6280SHeinrich Schuchardt * details.
849110c6280SHeinrich Schuchardt */
efi_cin_register_key_notify(struct efi_simple_text_input_ex_protocol * this,struct efi_key_data * key_data,efi_status_t (EFIAPI * key_notify_function)(struct efi_key_data * key_data),void ** notify_handle)850110c6280SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_register_key_notify(
851110c6280SHeinrich Schuchardt struct efi_simple_text_input_ex_protocol *this,
852110c6280SHeinrich Schuchardt struct efi_key_data *key_data,
853110c6280SHeinrich Schuchardt efi_status_t (EFIAPI *key_notify_function)(
854110c6280SHeinrich Schuchardt struct efi_key_data *key_data),
855110c6280SHeinrich Schuchardt void **notify_handle)
856110c6280SHeinrich Schuchardt {
8574fdcf066SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
8584fdcf066SHeinrich Schuchardt struct efi_cin_notify_function *notify_function;
8594fdcf066SHeinrich Schuchardt
860110c6280SHeinrich Schuchardt EFI_ENTRY("%p, %p, %p, %p",
861110c6280SHeinrich Schuchardt this, key_data, key_notify_function, notify_handle);
8624fdcf066SHeinrich Schuchardt
8634fdcf066SHeinrich Schuchardt /* Check parameters */
8644fdcf066SHeinrich Schuchardt if (!this || !key_data || !key_notify_function || !notify_handle) {
8654fdcf066SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
8664fdcf066SHeinrich Schuchardt goto out;
8674fdcf066SHeinrich Schuchardt }
8684fdcf066SHeinrich Schuchardt
8694fdcf066SHeinrich Schuchardt EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
8704fdcf066SHeinrich Schuchardt key_data->key.unicode_char,
8714fdcf066SHeinrich Schuchardt key_data->key.scan_code,
8724fdcf066SHeinrich Schuchardt key_data->key_state.key_shift_state,
8734fdcf066SHeinrich Schuchardt key_data->key_state.key_toggle_state);
8744fdcf066SHeinrich Schuchardt
8754fdcf066SHeinrich Schuchardt notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
8764fdcf066SHeinrich Schuchardt if (!notify_function) {
8774fdcf066SHeinrich Schuchardt ret = EFI_OUT_OF_RESOURCES;
8784fdcf066SHeinrich Schuchardt goto out;
8794fdcf066SHeinrich Schuchardt }
8804fdcf066SHeinrich Schuchardt notify_function->key = *key_data;
8814fdcf066SHeinrich Schuchardt notify_function->function = key_notify_function;
8824fdcf066SHeinrich Schuchardt list_add_tail(¬ify_function->link, &cin_notify_functions);
8834fdcf066SHeinrich Schuchardt *notify_handle = notify_function;
8844fdcf066SHeinrich Schuchardt out:
8854fdcf066SHeinrich Schuchardt return EFI_EXIT(ret);
886110c6280SHeinrich Schuchardt }
887110c6280SHeinrich Schuchardt
888110c6280SHeinrich Schuchardt /**
889110c6280SHeinrich Schuchardt * efi_cin_unregister_key_notify() - unregister key notification function
890110c6280SHeinrich Schuchardt *
891110c6280SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
892110c6280SHeinrich Schuchardt * @notification_handle: handle received when registering
893110c6280SHeinrich Schuchardt * Return: status code
894110c6280SHeinrich Schuchardt *
895110c6280SHeinrich Schuchardt * This function implements the SetState service of the
896110c6280SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
897110c6280SHeinrich Schuchardt *
898110c6280SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
899110c6280SHeinrich Schuchardt * details.
900110c6280SHeinrich Schuchardt */
efi_cin_unregister_key_notify(struct efi_simple_text_input_ex_protocol * this,void * notification_handle)901110c6280SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_unregister_key_notify(
902110c6280SHeinrich Schuchardt struct efi_simple_text_input_ex_protocol *this,
903110c6280SHeinrich Schuchardt void *notification_handle)
904110c6280SHeinrich Schuchardt {
9054fdcf066SHeinrich Schuchardt efi_status_t ret = EFI_INVALID_PARAMETER;
9064fdcf066SHeinrich Schuchardt struct efi_cin_notify_function *item, *notify_function =
9074fdcf066SHeinrich Schuchardt notification_handle;
9084fdcf066SHeinrich Schuchardt
909110c6280SHeinrich Schuchardt EFI_ENTRY("%p, %p", this, notification_handle);
9104fdcf066SHeinrich Schuchardt
9114fdcf066SHeinrich Schuchardt /* Check parameters */
9124fdcf066SHeinrich Schuchardt if (!this || !notification_handle)
9134fdcf066SHeinrich Schuchardt goto out;
9144fdcf066SHeinrich Schuchardt
9154fdcf066SHeinrich Schuchardt list_for_each_entry(item, &cin_notify_functions, link) {
9164fdcf066SHeinrich Schuchardt if (item == notify_function) {
9174fdcf066SHeinrich Schuchardt ret = EFI_SUCCESS;
9184fdcf066SHeinrich Schuchardt break;
9194fdcf066SHeinrich Schuchardt }
9204fdcf066SHeinrich Schuchardt }
9214fdcf066SHeinrich Schuchardt if (ret != EFI_SUCCESS)
9224fdcf066SHeinrich Schuchardt goto out;
9234fdcf066SHeinrich Schuchardt
9244fdcf066SHeinrich Schuchardt /* Remove the notify function */
9254fdcf066SHeinrich Schuchardt list_del(¬ify_function->link);
9264fdcf066SHeinrich Schuchardt free(notify_function);
9274fdcf066SHeinrich Schuchardt out:
9284fdcf066SHeinrich Schuchardt return EFI_EXIT(ret);
929110c6280SHeinrich Schuchardt }
930110c6280SHeinrich Schuchardt
931110c6280SHeinrich Schuchardt
932110c6280SHeinrich Schuchardt /**
9330dfd13a4SHeinrich Schuchardt * efi_cin_reset() - drain the input buffer
9340dfd13a4SHeinrich Schuchardt *
9350dfd13a4SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
9360dfd13a4SHeinrich Schuchardt * @extended_verification: allow for exhaustive verification
9370dfd13a4SHeinrich Schuchardt * Return: status code
9380dfd13a4SHeinrich Schuchardt *
9390dfd13a4SHeinrich Schuchardt * This function implements the Reset service of the
9400dfd13a4SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
9410dfd13a4SHeinrich Schuchardt *
9420dfd13a4SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
9430dfd13a4SHeinrich Schuchardt * details.
9440dfd13a4SHeinrich Schuchardt */
efi_cin_reset(struct efi_simple_text_input_protocol * this,bool extended_verification)9450dfd13a4SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_reset
9460dfd13a4SHeinrich Schuchardt (struct efi_simple_text_input_protocol *this,
9470dfd13a4SHeinrich Schuchardt bool extended_verification)
9480dfd13a4SHeinrich Schuchardt {
9490dfd13a4SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
9500dfd13a4SHeinrich Schuchardt
9510dfd13a4SHeinrich Schuchardt EFI_ENTRY("%p, %d", this, extended_verification);
9520dfd13a4SHeinrich Schuchardt
9530dfd13a4SHeinrich Schuchardt /* Check parameters */
9540dfd13a4SHeinrich Schuchardt if (!this) {
9550dfd13a4SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
9560dfd13a4SHeinrich Schuchardt goto out;
9570dfd13a4SHeinrich Schuchardt }
9580dfd13a4SHeinrich Schuchardt
959110c6280SHeinrich Schuchardt efi_cin_empty_buffer();
9600dfd13a4SHeinrich Schuchardt out:
9610dfd13a4SHeinrich Schuchardt return EFI_EXIT(ret);
9620dfd13a4SHeinrich Schuchardt }
9630dfd13a4SHeinrich Schuchardt
9640dfd13a4SHeinrich Schuchardt /**
965110c6280SHeinrich Schuchardt * efi_cin_read_key_stroke() - read key stroke
9660dfd13a4SHeinrich Schuchardt *
9670dfd13a4SHeinrich Schuchardt * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
9680dfd13a4SHeinrich Schuchardt * @key: key read from console
9690dfd13a4SHeinrich Schuchardt * Return: status code
9700dfd13a4SHeinrich Schuchardt *
9710dfd13a4SHeinrich Schuchardt * This function implements the ReadKeyStroke service of the
9720dfd13a4SHeinrich Schuchardt * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
9730dfd13a4SHeinrich Schuchardt *
9740dfd13a4SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
9750dfd13a4SHeinrich Schuchardt * details.
9760dfd13a4SHeinrich Schuchardt */
efi_cin_read_key_stroke(struct efi_simple_text_input_protocol * this,struct efi_input_key * key)9770dfd13a4SHeinrich Schuchardt static efi_status_t EFIAPI efi_cin_read_key_stroke
9780dfd13a4SHeinrich Schuchardt (struct efi_simple_text_input_protocol *this,
9790dfd13a4SHeinrich Schuchardt struct efi_input_key *key)
9800dfd13a4SHeinrich Schuchardt {
9810dfd13a4SHeinrich Schuchardt efi_status_t ret = EFI_SUCCESS;
9820dfd13a4SHeinrich Schuchardt
9830dfd13a4SHeinrich Schuchardt EFI_ENTRY("%p, %p", this, key);
9840dfd13a4SHeinrich Schuchardt
9850dfd13a4SHeinrich Schuchardt /* Check parameters */
9860dfd13a4SHeinrich Schuchardt if (!this || !key) {
9870dfd13a4SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER;
9880dfd13a4SHeinrich Schuchardt goto out;
9890dfd13a4SHeinrich Schuchardt }
9900dfd13a4SHeinrich Schuchardt
9910dfd13a4SHeinrich Schuchardt /* We don't do interrupts, so check for timers cooperatively */
9920dfd13a4SHeinrich Schuchardt efi_timer_check();
9930dfd13a4SHeinrich Schuchardt
9940dfd13a4SHeinrich Schuchardt /* Enable console input after ExitBootServices */
9950dfd13a4SHeinrich Schuchardt efi_cin_check();
9960dfd13a4SHeinrich Schuchardt
9970dfd13a4SHeinrich Schuchardt if (!key_available) {
9980dfd13a4SHeinrich Schuchardt ret = EFI_NOT_READY;
9990dfd13a4SHeinrich Schuchardt goto out;
10000dfd13a4SHeinrich Schuchardt }
1001110c6280SHeinrich Schuchardt *key = next_key.key;
10020dfd13a4SHeinrich Schuchardt key_available = false;
10030dfd13a4SHeinrich Schuchardt efi_con_in.wait_for_key->is_signaled = false;
10040dfd13a4SHeinrich Schuchardt out:
10050dfd13a4SHeinrich Schuchardt return EFI_EXIT(ret);
1006c1311ad4SAlexander Graf }
1007c1311ad4SAlexander Graf
1008110c6280SHeinrich Schuchardt static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1009110c6280SHeinrich Schuchardt .reset = efi_cin_reset_ex,
1010110c6280SHeinrich Schuchardt .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1011110c6280SHeinrich Schuchardt .wait_for_key_ex = NULL,
1012110c6280SHeinrich Schuchardt .set_state = efi_cin_set_state,
1013110c6280SHeinrich Schuchardt .register_key_notify = efi_cin_register_key_notify,
1014110c6280SHeinrich Schuchardt .unregister_key_notify = efi_cin_unregister_key_notify,
1015110c6280SHeinrich Schuchardt };
1016110c6280SHeinrich Schuchardt
10173e603ec7SHeinrich Schuchardt struct efi_simple_text_input_protocol efi_con_in = {
1018c1311ad4SAlexander Graf .reset = efi_cin_reset,
1019c1311ad4SAlexander Graf .read_key_stroke = efi_cin_read_key_stroke,
1020c1311ad4SAlexander Graf .wait_for_key = NULL,
1021c1311ad4SAlexander Graf };
102291be9a77Sxypron.glpk@gmx.de
102391be9a77Sxypron.glpk@gmx.de static struct efi_event *console_timer_event;
102491be9a77Sxypron.glpk@gmx.de
10259bc9664dSHeinrich Schuchardt /*
10260dfd13a4SHeinrich Schuchardt * efi_console_timer_notify() - notify the console timer event
10279bc9664dSHeinrich Schuchardt *
10280dfd13a4SHeinrich Schuchardt * @event: console timer event
10290dfd13a4SHeinrich Schuchardt * @context: not used
10309bc9664dSHeinrich Schuchardt */
efi_console_timer_notify(struct efi_event * event,void * context)1031ff925938Sxypron.glpk@gmx.de static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1032ff925938Sxypron.glpk@gmx.de void *context)
103391be9a77Sxypron.glpk@gmx.de {
103491be9a77Sxypron.glpk@gmx.de EFI_ENTRY("%p, %p", event, context);
10350dfd13a4SHeinrich Schuchardt efi_cin_check();
103691be9a77Sxypron.glpk@gmx.de EFI_EXIT(EFI_SUCCESS);
103791be9a77Sxypron.glpk@gmx.de }
103891be9a77Sxypron.glpk@gmx.de
10390dfd13a4SHeinrich Schuchardt /**
10400dfd13a4SHeinrich Schuchardt * efi_key_notify() - notify the wait for key event
10410dfd13a4SHeinrich Schuchardt *
10420dfd13a4SHeinrich Schuchardt * @event: wait for key event
10430dfd13a4SHeinrich Schuchardt * @context: not used
10440dfd13a4SHeinrich Schuchardt */
efi_key_notify(struct efi_event * event,void * context)10450dfd13a4SHeinrich Schuchardt static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
10460dfd13a4SHeinrich Schuchardt {
10470dfd13a4SHeinrich Schuchardt EFI_ENTRY("%p, %p", event, context);
10480dfd13a4SHeinrich Schuchardt efi_cin_check();
10490dfd13a4SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
10500dfd13a4SHeinrich Schuchardt }
10510dfd13a4SHeinrich Schuchardt
10520dfd13a4SHeinrich Schuchardt /**
10530dfd13a4SHeinrich Schuchardt * efi_console_register() - install the console protocols
10540dfd13a4SHeinrich Schuchardt *
10550dfd13a4SHeinrich Schuchardt * This function is called from do_bootefi_exec().
10566f566c23SHeinrich Schuchardt *
10576f566c23SHeinrich Schuchardt * Return: status code
10580dfd13a4SHeinrich Schuchardt */
efi_console_register(void)10596f566c23SHeinrich Schuchardt efi_status_t efi_console_register(void)
106091be9a77Sxypron.glpk@gmx.de {
106191be9a77Sxypron.glpk@gmx.de efi_status_t r;
1062fae0118eSHeinrich Schuchardt efi_handle_t console_output_handle;
1063fae0118eSHeinrich Schuchardt efi_handle_t console_input_handle;
1064a17e62ccSRob Clark
1065a4aa7befSHeinrich Schuchardt /* Set up mode information */
1066a4aa7befSHeinrich Schuchardt query_console_size();
1067a4aa7befSHeinrich Schuchardt
1068ebb4dd5bSHeinrich Schuchardt /* Create handles */
1069fae0118eSHeinrich Schuchardt r = efi_create_handle(&console_output_handle);
1070ebb4dd5bSHeinrich Schuchardt if (r != EFI_SUCCESS)
1071ebb4dd5bSHeinrich Schuchardt goto out_of_memory;
107240e3e757SAlexander Graf
1073fae0118eSHeinrich Schuchardt r = efi_add_protocol(console_output_handle,
1074ebb4dd5bSHeinrich Schuchardt &efi_guid_text_output_protocol, &efi_con_out);
1075ebb4dd5bSHeinrich Schuchardt if (r != EFI_SUCCESS)
1076ebb4dd5bSHeinrich Schuchardt goto out_of_memory;
1077fae0118eSHeinrich Schuchardt systab.con_out_handle = console_output_handle;
1078fae0118eSHeinrich Schuchardt systab.stderr_handle = console_output_handle;
107940e3e757SAlexander Graf
1080fae0118eSHeinrich Schuchardt r = efi_create_handle(&console_input_handle);
1081ebb4dd5bSHeinrich Schuchardt if (r != EFI_SUCCESS)
1082ebb4dd5bSHeinrich Schuchardt goto out_of_memory;
108340e3e757SAlexander Graf
1084fae0118eSHeinrich Schuchardt r = efi_add_protocol(console_input_handle,
1085ebb4dd5bSHeinrich Schuchardt &efi_guid_text_input_protocol, &efi_con_in);
1086ebb4dd5bSHeinrich Schuchardt if (r != EFI_SUCCESS)
1087ebb4dd5bSHeinrich Schuchardt goto out_of_memory;
1088fae0118eSHeinrich Schuchardt systab.con_in_handle = console_input_handle;
1089fae0118eSHeinrich Schuchardt r = efi_add_protocol(console_input_handle,
1090110c6280SHeinrich Schuchardt &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
1091110c6280SHeinrich Schuchardt if (r != EFI_SUCCESS)
1092110c6280SHeinrich Schuchardt goto out_of_memory;
1093a17e62ccSRob Clark
1094ebb4dd5bSHeinrich Schuchardt /* Create console events */
1095b095f3c8SHeinrich Schuchardt r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1096b095f3c8SHeinrich Schuchardt NULL, NULL, &efi_con_in.wait_for_key);
109791be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) {
109891be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to register WaitForKey event\n");
109991be9a77Sxypron.glpk@gmx.de return r;
110091be9a77Sxypron.glpk@gmx.de }
1101110c6280SHeinrich Schuchardt efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
110291be9a77Sxypron.glpk@gmx.de r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
1103b095f3c8SHeinrich Schuchardt efi_console_timer_notify, NULL, NULL,
110491be9a77Sxypron.glpk@gmx.de &console_timer_event);
110591be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) {
110691be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to register console event\n");
110791be9a77Sxypron.glpk@gmx.de return r;
110891be9a77Sxypron.glpk@gmx.de }
110991be9a77Sxypron.glpk@gmx.de /* 5000 ns cycle is sufficient for 2 MBaud */
111091be9a77Sxypron.glpk@gmx.de r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
111191be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS)
111291be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to set console timer\n");
111391be9a77Sxypron.glpk@gmx.de return r;
1114ebb4dd5bSHeinrich Schuchardt out_of_memory:
111514d103bbSHeinrich Schuchardt printf("ERROR: Out of memory\n");
1116ebb4dd5bSHeinrich Schuchardt return r;
111791be9a77Sxypron.glpk@gmx.de }
1118