blob: c09b93d9d68be6c18e17d52be7a6cb24406e5390 [file] [log] [blame]
Tom Rinif739fcd2018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Grafc1311ad2016-03-04 01:10:00 +01002/*
3 * EFI application console interface
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Grafc1311ad2016-03-04 01:10:00 +01006 */
7
8#include <common.h>
Rob Clark78178bb2017-09-09 06:47:40 -04009#include <charset.h>
Rob Clarka18c5a82017-09-13 18:05:43 -040010#include <dm/device.h>
Alexander Grafc1311ad2016-03-04 01:10:00 +010011#include <efi_loader.h>
Rob Clarka18c5a82017-09-13 18:05:43 -040012#include <stdio_dev.h>
13#include <video_console.h>
Alexander Grafc1311ad2016-03-04 01:10:00 +010014
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010015#define EFI_COUT_MODE_2 2
16#define EFI_MAX_COUT_MODE 3
17
18struct cout_mode {
19 unsigned long columns;
20 unsigned long rows;
21 int present;
22};
23
24static struct cout_mode efi_cout_modes[] = {
25 /* EFI Mode 0 is 80x25 and always present */
26 {
27 .columns = 80,
28 .rows = 25,
29 .present = 1,
30 },
31 /* EFI Mode 1 is always 80x50 */
32 {
33 .columns = 80,
34 .rows = 50,
35 .present = 0,
36 },
37 /* Value are unknown until we query the console */
38 {
39 .columns = 0,
40 .rows = 0,
41 .present = 0,
42 },
43};
44
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +020045const efi_guid_t efi_guid_text_output_protocol =
46 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
47const efi_guid_t efi_guid_text_input_protocol =
48 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Alexander Grafc1311ad2016-03-04 01:10:00 +010049
50#define cESC '\x1b'
51#define ESC "\x1b"
52
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010053/* Default to mode 0 */
Alexander Grafc1311ad2016-03-04 01:10:00 +010054static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +010055 .max_mode = 1,
Alexander Grafc1311ad2016-03-04 01:10:00 +010056 .mode = 0,
57 .attribute = 0,
58 .cursor_column = 0,
59 .cursor_row = 0,
60 .cursor_visible = 1,
61};
62
63static int term_read_reply(int *n, int maxnum, char end_char)
64{
65 char c;
66 int i = 0;
67
68 c = getc();
69 if (c != cESC)
70 return -1;
71 c = getc();
72 if (c != '[')
73 return -1;
74
75 n[0] = 0;
76 while (1) {
77 c = getc();
78 if (c == ';') {
79 i++;
80 if (i >= maxnum)
81 return -1;
82 n[i] = 0;
83 continue;
84 } else if (c == end_char) {
85 break;
86 } else if (c > '9' || c < '0') {
87 return -1;
88 }
89
90 /* Read one more decimal position */
91 n[i] *= 10;
92 n[i] += c - '0';
93 }
94
95 return 0;
96}
97
98static efi_status_t EFIAPI efi_cout_reset(
99 struct efi_simple_text_output_protocol *this,
100 char extended_verification)
101{
102 EFI_ENTRY("%p, %d", this, extended_verification);
103 return EFI_EXIT(EFI_UNSUPPORTED);
104}
105
Alexander Grafc1311ad2016-03-04 01:10:00 +0100106static efi_status_t EFIAPI efi_cout_output_string(
107 struct efi_simple_text_output_protocol *this,
Rob Clark3a45bc72017-09-13 18:05:44 -0400108 const efi_string_t string)
Alexander Grafc1311ad2016-03-04 01:10:00 +0100109{
Rob Clark3a45bc72017-09-13 18:05:44 -0400110 struct simple_text_output_mode *con = &efi_con_mode;
111 struct cout_mode *mode = &efi_cout_modes[con->mode];
Alexander Grafc1311ad2016-03-04 01:10:00 +0100112
113 EFI_ENTRY("%p, %p", this, string);
Rob Clark3a45bc72017-09-13 18:05:44 -0400114
115 unsigned int n16 = utf16_strlen(string);
116 char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200117 u16 *p;
Rob Clark3a45bc72017-09-13 18:05:44 -0400118
119 *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
120
121 fputs(stdout, buf);
122
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200123 /*
124 * Update the cursor position.
125 *
126 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
127 * and U000D. All other characters, including control characters
128 * U+0007 (bel) and U+0009 (tab), have to increase the column by one.
129 */
130 for (p = string; *p; ++p) {
Rob Clark3a45bc72017-09-13 18:05:44 -0400131 switch (*p) {
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200132 case '\b': /* U+0008, backspace */
133 con->cursor_column = max(0, con->cursor_column - 1);
Rob Clark3a45bc72017-09-13 18:05:44 -0400134 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200135 case '\n': /* U+000A, newline */
Rob Clark3a45bc72017-09-13 18:05:44 -0400136 con->cursor_column = 0;
137 con->cursor_row++;
138 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200139 case '\r': /* U+000D, carriage-return */
140 con->cursor_column = 0;
Rob Clark3a45bc72017-09-13 18:05:44 -0400141 break;
Heinrich Schuchardt7ca7c3c2018-04-29 16:24:25 +0200142 case 0xd800 ... 0xdbff:
143 /*
144 * Ignore high surrogates, we do not want to count a
145 * Unicode character twice.
146 */
Rob Clark3a45bc72017-09-13 18:05:44 -0400147 break;
148 default:
149 con->cursor_column++;
150 break;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100151 }
Rob Clark3a45bc72017-09-13 18:05:44 -0400152 if (con->cursor_column >= mode->columns) {
153 con->cursor_column = 0;
154 con->cursor_row++;
155 }
156 con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100157 }
158
159 return EFI_EXIT(EFI_SUCCESS);
160}
161
162static efi_status_t EFIAPI efi_cout_test_string(
163 struct efi_simple_text_output_protocol *this,
Rob Clark3a45bc72017-09-13 18:05:44 -0400164 const efi_string_t string)
Alexander Grafc1311ad2016-03-04 01:10:00 +0100165{
166 EFI_ENTRY("%p, %p", this, string);
167 return EFI_EXIT(EFI_SUCCESS);
168}
169
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100170static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
171{
172 if (!mode->present)
173 return false;
174
175 return (mode->rows == rows) && (mode->columns == cols);
176}
177
Rob Clark71cc25c2017-09-13 18:05:42 -0400178static int query_console_serial(int *rows, int *cols)
179{
180 /* Ask the terminal about its size */
181 int n[3];
182 u64 timeout;
183
184 /* Empty input buffer */
185 while (tstc())
186 getc();
187
188 printf(ESC"[18t");
189
190 /* Check if we have a terminal that understands */
191 timeout = timer_get_us() + 1000000;
192 while (!tstc())
193 if (timer_get_us() > timeout)
194 return -1;
195
196 /* Read {depth,rows,cols} */
197 if (term_read_reply(n, 3, 't'))
198 return -1;
199
200 *cols = n[2];
201 *rows = n[1];
202
203 return 0;
204}
205
Heinrich Schuchardta4aa7be2018-04-29 20:02:46 +0200206/*
207 * Update the mode table.
208 *
209 * By default the only mode available is 80x25. If the console has at least 50
210 * lines, enable mode 80x50. If we can query the console size and it is neither
211 * 80x25 nor 80x50, set it as an additional mode.
212 */
213static void query_console_size(void)
214{
215 const char *stdout_name = env_get("stdout");
216 int rows, cols;
217
218 if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
219 IS_ENABLED(CONFIG_DM_VIDEO)) {
220 struct stdio_dev *stdout_dev =
221 stdio_get_by_name("vidconsole");
222 struct udevice *dev = stdout_dev->priv;
223 struct vidconsole_priv *priv =
224 dev_get_uclass_priv(dev);
225 rows = priv->rows;
226 cols = priv->cols;
227 } else if (query_console_serial(&rows, &cols)) {
228 return;
229 }
230
231 /* Test if we can have Mode 1 */
232 if (cols >= 80 && rows >= 50) {
233 efi_cout_modes[1].present = 1;
234 efi_con_mode.max_mode = 2;
235 }
236
237 /*
238 * Install our mode as mode 2 if it is different
239 * than mode 0 or 1 and set it as the currently selected mode
240 */
241 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
242 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
243 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
244 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
245 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
246 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
247 efi_con_mode.mode = EFI_COUT_MODE_2;
248 }
249}
250
Alexander Grafc1311ad2016-03-04 01:10:00 +0100251static efi_status_t EFIAPI efi_cout_query_mode(
252 struct efi_simple_text_output_protocol *this,
253 unsigned long mode_number, unsigned long *columns,
254 unsigned long *rows)
255{
256 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
257
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100258 if (mode_number >= efi_con_mode.max_mode)
259 return EFI_EXIT(EFI_UNSUPPORTED);
260
261 if (efi_cout_modes[mode_number].present != 1)
262 return EFI_EXIT(EFI_UNSUPPORTED);
263
Alexander Grafc1311ad2016-03-04 01:10:00 +0100264 if (columns)
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100265 *columns = efi_cout_modes[mode_number].columns;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100266 if (rows)
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100267 *rows = efi_cout_modes[mode_number].rows;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100268
269 return EFI_EXIT(EFI_SUCCESS);
270}
271
272static efi_status_t EFIAPI efi_cout_set_mode(
273 struct efi_simple_text_output_protocol *this,
274 unsigned long mode_number)
275{
276 EFI_ENTRY("%p, %ld", this, mode_number);
277
Alexander Grafc1311ad2016-03-04 01:10:00 +0100278
Emmanuel Vadot5be8b0a2016-11-08 06:03:29 +0100279 if (mode_number > efi_con_mode.max_mode)
280 return EFI_EXIT(EFI_UNSUPPORTED);
281
282 efi_con_mode.mode = mode_number;
283 efi_con_mode.cursor_column = 0;
284 efi_con_mode.cursor_row = 0;
285
286 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100287}
288
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400289static const struct {
290 unsigned int fg;
291 unsigned int bg;
292} color[] = {
293 { 30, 40 }, /* 0: black */
294 { 34, 44 }, /* 1: blue */
295 { 32, 42 }, /* 2: green */
296 { 36, 46 }, /* 3: cyan */
297 { 31, 41 }, /* 4: red */
298 { 35, 45 }, /* 5: magenta */
299 { 33, 43 }, /* 6: brown, map to yellow as edk2 does*/
300 { 37, 47 }, /* 7: light grey, map to white */
301};
302
303/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100304static efi_status_t EFIAPI efi_cout_set_attribute(
305 struct efi_simple_text_output_protocol *this,
306 unsigned long attribute)
307{
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400308 unsigned int bold = EFI_ATTR_BOLD(attribute);
309 unsigned int fg = EFI_ATTR_FG(attribute);
310 unsigned int bg = EFI_ATTR_BG(attribute);
311
Alexander Grafc1311ad2016-03-04 01:10:00 +0100312 EFI_ENTRY("%p, %lx", this, attribute);
313
Rob Clark2d5dc2a2017-10-10 08:23:01 -0400314 if (attribute)
315 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
316 else
317 printf(ESC"[0;37;40m");
318
319 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100320}
321
322static efi_status_t EFIAPI efi_cout_clear_screen(
323 struct efi_simple_text_output_protocol *this)
324{
325 EFI_ENTRY("%p", this);
326
327 printf(ESC"[2J");
328
329 return EFI_EXIT(EFI_SUCCESS);
330}
331
332static efi_status_t EFIAPI efi_cout_set_cursor_position(
333 struct efi_simple_text_output_protocol *this,
334 unsigned long column, unsigned long row)
335{
336 EFI_ENTRY("%p, %ld, %ld", this, column, row);
337
338 printf(ESC"[%d;%df", (int)row, (int)column);
339 efi_con_mode.cursor_column = column;
340 efi_con_mode.cursor_row = row;
341
342 return EFI_EXIT(EFI_SUCCESS);
343}
344
345static efi_status_t EFIAPI efi_cout_enable_cursor(
346 struct efi_simple_text_output_protocol *this,
347 bool enable)
348{
349 EFI_ENTRY("%p, %d", this, enable);
350
351 printf(ESC"[?25%c", enable ? 'h' : 'l');
352
353 return EFI_EXIT(EFI_SUCCESS);
354}
355
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200356struct efi_simple_text_output_protocol efi_con_out = {
Alexander Grafc1311ad2016-03-04 01:10:00 +0100357 .reset = efi_cout_reset,
358 .output_string = efi_cout_output_string,
359 .test_string = efi_cout_test_string,
360 .query_mode = efi_cout_query_mode,
361 .set_mode = efi_cout_set_mode,
362 .set_attribute = efi_cout_set_attribute,
363 .clear_screen = efi_cout_clear_screen,
364 .set_cursor_position = efi_cout_set_cursor_position,
365 .enable_cursor = efi_cout_enable_cursor,
366 .mode = (void*)&efi_con_mode,
367};
368
369static efi_status_t EFIAPI efi_cin_reset(
370 struct efi_simple_input_interface *this,
371 bool extended_verification)
372{
373 EFI_ENTRY("%p, %d", this, extended_verification);
374 return EFI_EXIT(EFI_UNSUPPORTED);
375}
376
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100377/*
378 * Analyze modifiers (shift, alt, ctrl) for function keys.
379 * This gets called when we have already parsed CSI.
380 *
381 * @modifiers: bitmask (shift, alt, ctrl)
382 * @return: the unmodified code
383 */
384static char skip_modifiers(int *modifiers)
385{
386 char c, mod = 0, ret = 0;
387
388 c = getc();
389
390 if (c != ';') {
391 ret = c;
392 if (c == '~')
393 goto out;
394 c = getc();
395 }
396 for (;;) {
397 switch (c) {
398 case '0'...'9':
399 mod *= 10;
400 mod += c - '0';
401 /* fall through */
402 case ';':
403 c = getc();
404 break;
405 default:
406 goto out;
407 }
408 }
409out:
410 if (mod)
411 --mod;
412 if (modifiers)
413 *modifiers = mod;
414 if (!ret)
415 ret = c;
416 return ret;
417}
418
Alexander Grafc1311ad2016-03-04 01:10:00 +0100419static efi_status_t EFIAPI efi_cin_read_key_stroke(
420 struct efi_simple_input_interface *this,
421 struct efi_input_key *key)
422{
423 struct efi_input_key pressed_key = {
424 .scan_code = 0,
425 .unicode_char = 0,
426 };
427 char ch;
428
429 EFI_ENTRY("%p, %p", this, key);
430
431 /* We don't do interrupts, so check for timers cooperatively */
432 efi_timer_check();
433
434 if (!tstc()) {
435 /* No key pressed */
436 return EFI_EXIT(EFI_NOT_READY);
437 }
438
439 ch = getc();
440 if (ch == cESC) {
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100441 /*
442 * Xterm Control Sequences
443 * https://www.xfree86.org/4.8.0/ctlseqs.html
444 */
Alexander Grafc1311ad2016-03-04 01:10:00 +0100445 ch = getc();
446 switch (ch) {
447 case cESC: /* ESC */
448 pressed_key.scan_code = 23;
449 break;
450 case 'O': /* F1 - F4 */
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100451 ch = getc();
452 /* skip modifiers */
453 if (ch <= '9')
454 ch = getc();
455 pressed_key.scan_code = ch - 'P' + 11;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100456 break;
457 case 'a'...'z':
458 ch = ch - 'a';
459 break;
460 case '[':
461 ch = getc();
462 switch (ch) {
463 case 'A'...'D': /* up, down right, left */
464 pressed_key.scan_code = ch - 'A' + 1;
465 break;
466 case 'F': /* End */
467 pressed_key.scan_code = 6;
468 break;
469 case 'H': /* Home */
470 pressed_key.scan_code = 5;
471 break;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100472 case '1':
473 ch = skip_modifiers(NULL);
474 switch (ch) {
475 case '1'...'5': /* F1 - F5 */
476 pressed_key.scan_code = ch - '1' + 11;
477 break;
478 case '7'...'9': /* F6 - F8 */
479 pressed_key.scan_code = ch - '7' + 16;
480 break;
481 case 'A'...'D': /* up, down right, left */
482 pressed_key.scan_code = ch - 'A' + 1;
483 break;
484 case 'F':
485 pressed_key.scan_code = 6; /* End */
486 break;
487 case 'H':
488 pressed_key.scan_code = 5; /* Home */
489 break;
490 }
Alexander Grafc1311ad2016-03-04 01:10:00 +0100491 break;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100492 case '2':
493 ch = skip_modifiers(NULL);
494 switch (ch) {
495 case '0'...'1': /* F9 - F10 */
496 pressed_key.scan_code = ch - '0' + 19;
497 break;
498 case '3'...'4': /* F11 - F12 */
499 pressed_key.scan_code = ch - '3' + 21;
500 break;
501 case '~': /* INS */
502 pressed_key.scan_code = 7;
503 break;
504 }
Alexander Grafc1311ad2016-03-04 01:10:00 +0100505 break;
506 case '3': /* DEL */
507 pressed_key.scan_code = 8;
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100508 skip_modifiers(NULL);
509 break;
510 case '5': /* PG UP */
511 pressed_key.scan_code = 9;
512 skip_modifiers(NULL);
513 break;
514 case '6': /* PG DOWN */
515 pressed_key.scan_code = 10;
516 skip_modifiers(NULL);
Alexander Grafc1311ad2016-03-04 01:10:00 +0100517 break;
518 }
519 break;
520 }
521 } else if (ch == 0x7f) {
522 /* Backspace */
523 ch = 0x08;
524 }
Heinrich Schuchardt0fb41692018-02-19 18:53:29 +0100525 if (!pressed_key.scan_code)
526 pressed_key.unicode_char = ch;
Alexander Grafc1311ad2016-03-04 01:10:00 +0100527 *key = pressed_key;
528
529 return EFI_EXIT(EFI_SUCCESS);
530}
531
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200532struct efi_simple_input_interface efi_con_in = {
Alexander Grafc1311ad2016-03-04 01:10:00 +0100533 .reset = efi_cin_reset,
534 .read_key_stroke = efi_cin_read_key_stroke,
535 .wait_for_key = NULL,
536};
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200537
538static struct efi_event *console_timer_event;
539
xypron.glpk@gmx.deff925932017-07-20 05:26:07 +0200540static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200541{
542}
543
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100544/*
545 * Notification function of the console timer event.
546 *
547 * event: console timer event
548 * context: not used
549 */
xypron.glpk@gmx.deff925932017-07-20 05:26:07 +0200550static void EFIAPI efi_console_timer_notify(struct efi_event *event,
551 void *context)
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200552{
553 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100554
555 /* Check if input is available */
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200556 if (tstc()) {
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100557 /* Queue the wait for key event */
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200558 efi_con_in.wait_for_key->is_signaled = true;
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100559 efi_signal_event(efi_con_in.wait_for_key, true);
560 }
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200561 EFI_EXIT(EFI_SUCCESS);
562}
563
564/* This gets called from do_bootefi_exec(). */
565int efi_console_register(void)
566{
567 efi_status_t r;
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200568 struct efi_object *efi_console_output_obj;
569 struct efi_object *efi_console_input_obj;
Rob Clarka17e62c2017-07-24 10:39:01 -0400570
Heinrich Schuchardta4aa7be2018-04-29 20:02:46 +0200571 /* Set up mode information */
572 query_console_size();
573
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200574 /* Create handles */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100575 r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200576 if (r != EFI_SUCCESS)
577 goto out_of_memory;
578 r = efi_add_protocol(efi_console_output_obj->handle,
579 &efi_guid_text_output_protocol, &efi_con_out);
580 if (r != EFI_SUCCESS)
581 goto out_of_memory;
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100582 r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200583 if (r != EFI_SUCCESS)
584 goto out_of_memory;
585 r = efi_add_protocol(efi_console_input_obj->handle,
586 &efi_guid_text_input_protocol, &efi_con_in);
587 if (r != EFI_SUCCESS)
588 goto out_of_memory;
Rob Clarka17e62c2017-07-24 10:39:01 -0400589
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200590 /* Create console events */
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100591 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
592 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200593 if (r != EFI_SUCCESS) {
594 printf("ERROR: Failed to register WaitForKey event\n");
595 return r;
596 }
597 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100598 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200599 &console_timer_event);
600 if (r != EFI_SUCCESS) {
601 printf("ERROR: Failed to register console event\n");
602 return r;
603 }
604 /* 5000 ns cycle is sufficient for 2 MBaud */
605 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
606 if (r != EFI_SUCCESS)
607 printf("ERROR: Failed to set console timer\n");
608 return r;
Heinrich Schuchardtebb4dd52017-10-26 19:25:59 +0200609out_of_memory:
610 printf("ERROR: Out of meemory\n");
611 return r;
xypron.glpk@gmx.de91be9a72017-07-18 20:17:22 +0200612}