1c1311ad4SAlexander Graf /* 2c1311ad4SAlexander Graf * EFI application console interface 3c1311ad4SAlexander Graf * 4c1311ad4SAlexander Graf * Copyright (c) 2016 Alexander Graf 5c1311ad4SAlexander Graf * 6c1311ad4SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7c1311ad4SAlexander Graf */ 8c1311ad4SAlexander Graf 9c1311ad4SAlexander Graf #include <common.h> 10c1311ad4SAlexander Graf #include <efi_loader.h> 11c1311ad4SAlexander Graf 12c1311ad4SAlexander Graf static bool console_size_queried; 13c1311ad4SAlexander Graf 145be8b0a3SEmmanuel Vadot #define EFI_COUT_MODE_2 2 155be8b0a3SEmmanuel Vadot #define EFI_MAX_COUT_MODE 3 165be8b0a3SEmmanuel Vadot 175be8b0a3SEmmanuel Vadot struct cout_mode { 185be8b0a3SEmmanuel Vadot unsigned long columns; 195be8b0a3SEmmanuel Vadot unsigned long rows; 205be8b0a3SEmmanuel Vadot int present; 215be8b0a3SEmmanuel Vadot }; 225be8b0a3SEmmanuel Vadot 235be8b0a3SEmmanuel Vadot static struct cout_mode efi_cout_modes[] = { 245be8b0a3SEmmanuel Vadot /* EFI Mode 0 is 80x25 and always present */ 255be8b0a3SEmmanuel Vadot { 265be8b0a3SEmmanuel Vadot .columns = 80, 275be8b0a3SEmmanuel Vadot .rows = 25, 285be8b0a3SEmmanuel Vadot .present = 1, 295be8b0a3SEmmanuel Vadot }, 305be8b0a3SEmmanuel Vadot /* EFI Mode 1 is always 80x50 */ 315be8b0a3SEmmanuel Vadot { 325be8b0a3SEmmanuel Vadot .columns = 80, 335be8b0a3SEmmanuel Vadot .rows = 50, 345be8b0a3SEmmanuel Vadot .present = 0, 355be8b0a3SEmmanuel Vadot }, 365be8b0a3SEmmanuel Vadot /* Value are unknown until we query the console */ 375be8b0a3SEmmanuel Vadot { 385be8b0a3SEmmanuel Vadot .columns = 0, 395be8b0a3SEmmanuel Vadot .rows = 0, 405be8b0a3SEmmanuel Vadot .present = 0, 415be8b0a3SEmmanuel Vadot }, 425be8b0a3SEmmanuel Vadot }; 435be8b0a3SEmmanuel Vadot 44c1311ad4SAlexander Graf const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID; 45c1311ad4SAlexander Graf 46c1311ad4SAlexander Graf #define cESC '\x1b' 47c1311ad4SAlexander Graf #define ESC "\x1b" 48c1311ad4SAlexander Graf 49c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cin_get_mode( 50c1311ad4SAlexander Graf struct efi_console_control_protocol *this, 51c1311ad4SAlexander Graf int *mode, char *uga_exists, char *std_in_locked) 52c1311ad4SAlexander Graf { 53c1311ad4SAlexander Graf EFI_ENTRY("%p, %p, %p, %p", this, mode, uga_exists, std_in_locked); 54c1311ad4SAlexander Graf 55c1311ad4SAlexander Graf if (mode) 56c1311ad4SAlexander Graf *mode = EFI_CONSOLE_MODE_TEXT; 57c1311ad4SAlexander Graf if (uga_exists) 58c1311ad4SAlexander Graf *uga_exists = 0; 59c1311ad4SAlexander Graf if (std_in_locked) 60c1311ad4SAlexander Graf *std_in_locked = 0; 61c1311ad4SAlexander Graf 62c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 63c1311ad4SAlexander Graf } 64c1311ad4SAlexander Graf 65c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cin_set_mode( 66c1311ad4SAlexander Graf struct efi_console_control_protocol *this, int mode) 67c1311ad4SAlexander Graf { 68c1311ad4SAlexander Graf EFI_ENTRY("%p, %d", this, mode); 69c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 70c1311ad4SAlexander Graf } 71c1311ad4SAlexander Graf 72c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cin_lock_std_in( 73c1311ad4SAlexander Graf struct efi_console_control_protocol *this, 74c1311ad4SAlexander Graf uint16_t *password) 75c1311ad4SAlexander Graf { 76c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, password); 77c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 78c1311ad4SAlexander Graf } 79c1311ad4SAlexander Graf 80c1311ad4SAlexander Graf const struct efi_console_control_protocol efi_console_control = { 81c1311ad4SAlexander Graf .get_mode = efi_cin_get_mode, 82c1311ad4SAlexander Graf .set_mode = efi_cin_set_mode, 83c1311ad4SAlexander Graf .lock_std_in = efi_cin_lock_std_in, 84c1311ad4SAlexander Graf }; 85c1311ad4SAlexander Graf 865be8b0a3SEmmanuel Vadot /* Default to mode 0 */ 87c1311ad4SAlexander Graf static struct simple_text_output_mode efi_con_mode = { 885be8b0a3SEmmanuel Vadot .max_mode = 1, 89c1311ad4SAlexander Graf .mode = 0, 90c1311ad4SAlexander Graf .attribute = 0, 91c1311ad4SAlexander Graf .cursor_column = 0, 92c1311ad4SAlexander Graf .cursor_row = 0, 93c1311ad4SAlexander Graf .cursor_visible = 1, 94c1311ad4SAlexander Graf }; 95c1311ad4SAlexander Graf 96c1311ad4SAlexander Graf static int term_read_reply(int *n, int maxnum, char end_char) 97c1311ad4SAlexander Graf { 98c1311ad4SAlexander Graf char c; 99c1311ad4SAlexander Graf int i = 0; 100c1311ad4SAlexander Graf 101c1311ad4SAlexander Graf c = getc(); 102c1311ad4SAlexander Graf if (c != cESC) 103c1311ad4SAlexander Graf return -1; 104c1311ad4SAlexander Graf c = getc(); 105c1311ad4SAlexander Graf if (c != '[') 106c1311ad4SAlexander Graf return -1; 107c1311ad4SAlexander Graf 108c1311ad4SAlexander Graf n[0] = 0; 109c1311ad4SAlexander Graf while (1) { 110c1311ad4SAlexander Graf c = getc(); 111c1311ad4SAlexander Graf if (c == ';') { 112c1311ad4SAlexander Graf i++; 113c1311ad4SAlexander Graf if (i >= maxnum) 114c1311ad4SAlexander Graf return -1; 115c1311ad4SAlexander Graf n[i] = 0; 116c1311ad4SAlexander Graf continue; 117c1311ad4SAlexander Graf } else if (c == end_char) { 118c1311ad4SAlexander Graf break; 119c1311ad4SAlexander Graf } else if (c > '9' || c < '0') { 120c1311ad4SAlexander Graf return -1; 121c1311ad4SAlexander Graf } 122c1311ad4SAlexander Graf 123c1311ad4SAlexander Graf /* Read one more decimal position */ 124c1311ad4SAlexander Graf n[i] *= 10; 125c1311ad4SAlexander Graf n[i] += c - '0'; 126c1311ad4SAlexander Graf } 127c1311ad4SAlexander Graf 128c1311ad4SAlexander Graf return 0; 129c1311ad4SAlexander Graf } 130c1311ad4SAlexander Graf 131c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_reset( 132c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 133c1311ad4SAlexander Graf char extended_verification) 134c1311ad4SAlexander Graf { 135c1311ad4SAlexander Graf EFI_ENTRY("%p, %d", this, extended_verification); 136c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 137c1311ad4SAlexander Graf } 138c1311ad4SAlexander Graf 139c1311ad4SAlexander Graf static void print_unicode_in_utf8(u16 c) 140c1311ad4SAlexander Graf { 141c1311ad4SAlexander Graf char utf8[4] = { 0 }; 142c1311ad4SAlexander Graf char *b = utf8; 143c1311ad4SAlexander Graf 144c1311ad4SAlexander Graf if (c < 0x80) { 145c1311ad4SAlexander Graf *(b++) = c; 146c1311ad4SAlexander Graf } else if (c < 0x800) { 147c1311ad4SAlexander Graf *(b++) = 192 + c / 64; 148c1311ad4SAlexander Graf *(b++) = 128 + c % 64; 149c1311ad4SAlexander Graf } else { 150c1311ad4SAlexander Graf *(b++) = 224 + c / 4096; 151c1311ad4SAlexander Graf *(b++) = 128 + c / 64 % 64; 152c1311ad4SAlexander Graf *(b++) = 128 + c % 64; 153c1311ad4SAlexander Graf } 154c1311ad4SAlexander Graf 155c1311ad4SAlexander Graf puts(utf8); 156c1311ad4SAlexander Graf } 157c1311ad4SAlexander Graf 158c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_output_string( 159c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 160c1311ad4SAlexander Graf const unsigned short *string) 161c1311ad4SAlexander Graf { 1625be8b0a3SEmmanuel Vadot struct cout_mode *mode; 163c1311ad4SAlexander Graf u16 ch; 164c1311ad4SAlexander Graf 1655be8b0a3SEmmanuel Vadot mode = &efi_cout_modes[efi_con_mode.mode]; 166c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, string); 167c1311ad4SAlexander Graf for (;(ch = *string); string++) { 168c1311ad4SAlexander Graf print_unicode_in_utf8(ch); 169c1311ad4SAlexander Graf efi_con_mode.cursor_column++; 170c1311ad4SAlexander Graf if (ch == '\n') { 171c1311ad4SAlexander Graf efi_con_mode.cursor_column = 1; 172c1311ad4SAlexander Graf efi_con_mode.cursor_row++; 1735be8b0a3SEmmanuel Vadot } else if (efi_con_mode.cursor_column > mode->columns) { 174c1311ad4SAlexander Graf efi_con_mode.cursor_column = 1; 175c1311ad4SAlexander Graf efi_con_mode.cursor_row++; 176c1311ad4SAlexander Graf } 1775be8b0a3SEmmanuel Vadot if (efi_con_mode.cursor_row > mode->rows) 1785be8b0a3SEmmanuel Vadot efi_con_mode.cursor_row = mode->rows; 179c1311ad4SAlexander Graf } 180c1311ad4SAlexander Graf 181c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 182c1311ad4SAlexander Graf } 183c1311ad4SAlexander Graf 184c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_test_string( 185c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 186c1311ad4SAlexander Graf const unsigned short *string) 187c1311ad4SAlexander Graf { 188c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, string); 189c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 190c1311ad4SAlexander Graf } 191c1311ad4SAlexander Graf 1925be8b0a3SEmmanuel Vadot static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols) 1935be8b0a3SEmmanuel Vadot { 1945be8b0a3SEmmanuel Vadot if (!mode->present) 1955be8b0a3SEmmanuel Vadot return false; 1965be8b0a3SEmmanuel Vadot 1975be8b0a3SEmmanuel Vadot return (mode->rows == rows) && (mode->columns == cols); 1985be8b0a3SEmmanuel Vadot } 1995be8b0a3SEmmanuel Vadot 200c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_query_mode( 201c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 202c1311ad4SAlexander Graf unsigned long mode_number, unsigned long *columns, 203c1311ad4SAlexander Graf unsigned long *rows) 204c1311ad4SAlexander Graf { 205c1311ad4SAlexander Graf EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows); 206c1311ad4SAlexander Graf 207c1311ad4SAlexander Graf if (!console_size_queried) { 208c1311ad4SAlexander Graf /* Ask the terminal about its size */ 209c1311ad4SAlexander Graf int n[3]; 2105be8b0a3SEmmanuel Vadot int cols; 2115be8b0a3SEmmanuel Vadot int rows; 212c1311ad4SAlexander Graf u64 timeout; 213c1311ad4SAlexander Graf 214c1311ad4SAlexander Graf console_size_queried = true; 215c1311ad4SAlexander Graf 216c1311ad4SAlexander Graf /* Empty input buffer */ 217c1311ad4SAlexander Graf while (tstc()) 218c1311ad4SAlexander Graf getc(); 219c1311ad4SAlexander Graf 220c1311ad4SAlexander Graf printf(ESC"[18t"); 221c1311ad4SAlexander Graf 222c1311ad4SAlexander Graf /* Check if we have a terminal that understands */ 223c1311ad4SAlexander Graf timeout = timer_get_us() + 1000000; 224c1311ad4SAlexander Graf while (!tstc()) 225c1311ad4SAlexander Graf if (timer_get_us() > timeout) 226c1311ad4SAlexander Graf goto out; 227c1311ad4SAlexander Graf 228c1311ad4SAlexander Graf /* Read {depth,rows,cols} */ 229c1311ad4SAlexander Graf if (term_read_reply(n, 3, 't')) { 230c1311ad4SAlexander Graf goto out; 231c1311ad4SAlexander Graf } 232c1311ad4SAlexander Graf 2335be8b0a3SEmmanuel Vadot cols = n[2]; 2345be8b0a3SEmmanuel Vadot rows = n[1]; 2355be8b0a3SEmmanuel Vadot 2365be8b0a3SEmmanuel Vadot /* Test if we can have Mode 1 */ 2375be8b0a3SEmmanuel Vadot if (cols >= 80 && rows >= 50) { 2385be8b0a3SEmmanuel Vadot efi_cout_modes[1].present = 1; 2395be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = 2; 240c1311ad4SAlexander Graf } 241c1311ad4SAlexander Graf 2425be8b0a3SEmmanuel Vadot /* 2435be8b0a3SEmmanuel Vadot * Install our mode as mode 2 if it is different 2445be8b0a3SEmmanuel Vadot * than mode 0 or 1 and set it as the currently selected mode 2455be8b0a3SEmmanuel Vadot */ 2465be8b0a3SEmmanuel Vadot if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) && 2475be8b0a3SEmmanuel Vadot !cout_mode_matches(&efi_cout_modes[1], rows, cols)) { 2485be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].columns = cols; 2495be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].rows = rows; 2505be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].present = 1; 2515be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = EFI_MAX_COUT_MODE; 2525be8b0a3SEmmanuel Vadot efi_con_mode.mode = EFI_COUT_MODE_2; 2535be8b0a3SEmmanuel Vadot } 2545be8b0a3SEmmanuel Vadot } 2555be8b0a3SEmmanuel Vadot 2565be8b0a3SEmmanuel Vadot if (mode_number >= efi_con_mode.max_mode) 2575be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED); 2585be8b0a3SEmmanuel Vadot 2595be8b0a3SEmmanuel Vadot if (efi_cout_modes[mode_number].present != 1) 2605be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED); 2615be8b0a3SEmmanuel Vadot 262c1311ad4SAlexander Graf out: 263c1311ad4SAlexander Graf if (columns) 2645be8b0a3SEmmanuel Vadot *columns = efi_cout_modes[mode_number].columns; 265c1311ad4SAlexander Graf if (rows) 2665be8b0a3SEmmanuel Vadot *rows = efi_cout_modes[mode_number].rows; 267c1311ad4SAlexander Graf 268c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 269c1311ad4SAlexander Graf } 270c1311ad4SAlexander Graf 271c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_mode( 272c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 273c1311ad4SAlexander Graf unsigned long mode_number) 274c1311ad4SAlexander Graf { 275c1311ad4SAlexander Graf EFI_ENTRY("%p, %ld", this, mode_number); 276c1311ad4SAlexander Graf 277c1311ad4SAlexander Graf 2785be8b0a3SEmmanuel Vadot if (mode_number > efi_con_mode.max_mode) 279c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 2805be8b0a3SEmmanuel Vadot 2815be8b0a3SEmmanuel Vadot efi_con_mode.mode = mode_number; 2825be8b0a3SEmmanuel Vadot efi_con_mode.cursor_column = 0; 2835be8b0a3SEmmanuel Vadot efi_con_mode.cursor_row = 0; 2845be8b0a3SEmmanuel Vadot 2855be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_SUCCESS); 286c1311ad4SAlexander Graf } 287c1311ad4SAlexander Graf 288c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_attribute( 289c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 290c1311ad4SAlexander Graf unsigned long attribute) 291c1311ad4SAlexander Graf { 292c1311ad4SAlexander Graf EFI_ENTRY("%p, %lx", this, attribute); 293c1311ad4SAlexander Graf 294c1311ad4SAlexander Graf /* Just ignore attributes (colors) for now */ 295c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 296c1311ad4SAlexander Graf } 297c1311ad4SAlexander Graf 298c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_clear_screen( 299c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this) 300c1311ad4SAlexander Graf { 301c1311ad4SAlexander Graf EFI_ENTRY("%p", this); 302c1311ad4SAlexander Graf 303c1311ad4SAlexander Graf printf(ESC"[2J"); 304c1311ad4SAlexander Graf 305c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 306c1311ad4SAlexander Graf } 307c1311ad4SAlexander Graf 308c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_set_cursor_position( 309c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 310c1311ad4SAlexander Graf unsigned long column, unsigned long row) 311c1311ad4SAlexander Graf { 312c1311ad4SAlexander Graf EFI_ENTRY("%p, %ld, %ld", this, column, row); 313c1311ad4SAlexander Graf 314c1311ad4SAlexander Graf printf(ESC"[%d;%df", (int)row, (int)column); 315c1311ad4SAlexander Graf efi_con_mode.cursor_column = column; 316c1311ad4SAlexander Graf efi_con_mode.cursor_row = row; 317c1311ad4SAlexander Graf 318c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 319c1311ad4SAlexander Graf } 320c1311ad4SAlexander Graf 321c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cout_enable_cursor( 322c1311ad4SAlexander Graf struct efi_simple_text_output_protocol *this, 323c1311ad4SAlexander Graf bool enable) 324c1311ad4SAlexander Graf { 325c1311ad4SAlexander Graf EFI_ENTRY("%p, %d", this, enable); 326c1311ad4SAlexander Graf 327c1311ad4SAlexander Graf printf(ESC"[?25%c", enable ? 'h' : 'l'); 328c1311ad4SAlexander Graf 329c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 330c1311ad4SAlexander Graf } 331c1311ad4SAlexander Graf 332c1311ad4SAlexander Graf const struct efi_simple_text_output_protocol efi_con_out = { 333c1311ad4SAlexander Graf .reset = efi_cout_reset, 334c1311ad4SAlexander Graf .output_string = efi_cout_output_string, 335c1311ad4SAlexander Graf .test_string = efi_cout_test_string, 336c1311ad4SAlexander Graf .query_mode = efi_cout_query_mode, 337c1311ad4SAlexander Graf .set_mode = efi_cout_set_mode, 338c1311ad4SAlexander Graf .set_attribute = efi_cout_set_attribute, 339c1311ad4SAlexander Graf .clear_screen = efi_cout_clear_screen, 340c1311ad4SAlexander Graf .set_cursor_position = efi_cout_set_cursor_position, 341c1311ad4SAlexander Graf .enable_cursor = efi_cout_enable_cursor, 342c1311ad4SAlexander Graf .mode = (void*)&efi_con_mode, 343c1311ad4SAlexander Graf }; 344c1311ad4SAlexander Graf 345c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cin_reset( 346c1311ad4SAlexander Graf struct efi_simple_input_interface *this, 347c1311ad4SAlexander Graf bool extended_verification) 348c1311ad4SAlexander Graf { 349c1311ad4SAlexander Graf EFI_ENTRY("%p, %d", this, extended_verification); 350c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 351c1311ad4SAlexander Graf } 352c1311ad4SAlexander Graf 353c1311ad4SAlexander Graf static efi_status_t EFIAPI efi_cin_read_key_stroke( 354c1311ad4SAlexander Graf struct efi_simple_input_interface *this, 355c1311ad4SAlexander Graf struct efi_input_key *key) 356c1311ad4SAlexander Graf { 357c1311ad4SAlexander Graf struct efi_input_key pressed_key = { 358c1311ad4SAlexander Graf .scan_code = 0, 359c1311ad4SAlexander Graf .unicode_char = 0, 360c1311ad4SAlexander Graf }; 361c1311ad4SAlexander Graf char ch; 362c1311ad4SAlexander Graf 363c1311ad4SAlexander Graf EFI_ENTRY("%p, %p", this, key); 364c1311ad4SAlexander Graf 365c1311ad4SAlexander Graf /* We don't do interrupts, so check for timers cooperatively */ 366c1311ad4SAlexander Graf efi_timer_check(); 367c1311ad4SAlexander Graf 368c1311ad4SAlexander Graf if (!tstc()) { 369c1311ad4SAlexander Graf /* No key pressed */ 370c1311ad4SAlexander Graf return EFI_EXIT(EFI_NOT_READY); 371c1311ad4SAlexander Graf } 372c1311ad4SAlexander Graf 373c1311ad4SAlexander Graf ch = getc(); 374c1311ad4SAlexander Graf if (ch == cESC) { 375c1311ad4SAlexander Graf /* Escape Sequence */ 376c1311ad4SAlexander Graf ch = getc(); 377c1311ad4SAlexander Graf switch (ch) { 378c1311ad4SAlexander Graf case cESC: /* ESC */ 379c1311ad4SAlexander Graf pressed_key.scan_code = 23; 380c1311ad4SAlexander Graf break; 381c1311ad4SAlexander Graf case 'O': /* F1 - F4 */ 382c1311ad4SAlexander Graf pressed_key.scan_code = getc() - 'P' + 11; 383c1311ad4SAlexander Graf break; 384c1311ad4SAlexander Graf case 'a'...'z': 385c1311ad4SAlexander Graf ch = ch - 'a'; 386c1311ad4SAlexander Graf break; 387c1311ad4SAlexander Graf case '[': 388c1311ad4SAlexander Graf ch = getc(); 389c1311ad4SAlexander Graf switch (ch) { 390c1311ad4SAlexander Graf case 'A'...'D': /* up, down right, left */ 391c1311ad4SAlexander Graf pressed_key.scan_code = ch - 'A' + 1; 392c1311ad4SAlexander Graf break; 393c1311ad4SAlexander Graf case 'F': /* End */ 394c1311ad4SAlexander Graf pressed_key.scan_code = 6; 395c1311ad4SAlexander Graf break; 396c1311ad4SAlexander Graf case 'H': /* Home */ 397c1311ad4SAlexander Graf pressed_key.scan_code = 5; 398c1311ad4SAlexander Graf break; 399c1311ad4SAlexander Graf case '1': /* F5 - F8 */ 400c1311ad4SAlexander Graf pressed_key.scan_code = getc() - '0' + 11; 401c1311ad4SAlexander Graf getc(); 402c1311ad4SAlexander Graf break; 403c1311ad4SAlexander Graf case '2': /* F9 - F12 */ 404c1311ad4SAlexander Graf pressed_key.scan_code = getc() - '0' + 19; 405c1311ad4SAlexander Graf getc(); 406c1311ad4SAlexander Graf break; 407c1311ad4SAlexander Graf case '3': /* DEL */ 408c1311ad4SAlexander Graf pressed_key.scan_code = 8; 409c1311ad4SAlexander Graf getc(); 410c1311ad4SAlexander Graf break; 411c1311ad4SAlexander Graf } 412c1311ad4SAlexander Graf break; 413c1311ad4SAlexander Graf } 414c1311ad4SAlexander Graf } else if (ch == 0x7f) { 415c1311ad4SAlexander Graf /* Backspace */ 416c1311ad4SAlexander Graf ch = 0x08; 417c1311ad4SAlexander Graf } 418c1311ad4SAlexander Graf pressed_key.unicode_char = ch; 419c1311ad4SAlexander Graf *key = pressed_key; 420c1311ad4SAlexander Graf 421c1311ad4SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 422c1311ad4SAlexander Graf } 423c1311ad4SAlexander Graf 42491be9a77Sxypron.glpk@gmx.de struct efi_simple_input_interface efi_con_in = { 425c1311ad4SAlexander Graf .reset = efi_cin_reset, 426c1311ad4SAlexander Graf .read_key_stroke = efi_cin_read_key_stroke, 427c1311ad4SAlexander Graf .wait_for_key = NULL, 428c1311ad4SAlexander Graf }; 42991be9a77Sxypron.glpk@gmx.de 43091be9a77Sxypron.glpk@gmx.de static struct efi_event *console_timer_event; 43191be9a77Sxypron.glpk@gmx.de 432*ff925938Sxypron.glpk@gmx.de static void EFIAPI efi_key_notify(struct efi_event *event, void *context) 43391be9a77Sxypron.glpk@gmx.de { 43491be9a77Sxypron.glpk@gmx.de } 43591be9a77Sxypron.glpk@gmx.de 436*ff925938Sxypron.glpk@gmx.de static void EFIAPI efi_console_timer_notify(struct efi_event *event, 437*ff925938Sxypron.glpk@gmx.de void *context) 43891be9a77Sxypron.glpk@gmx.de { 43991be9a77Sxypron.glpk@gmx.de EFI_ENTRY("%p, %p", event, context); 44091be9a77Sxypron.glpk@gmx.de if (tstc()) 44191be9a77Sxypron.glpk@gmx.de efi_signal_event(efi_con_in.wait_for_key); 44291be9a77Sxypron.glpk@gmx.de EFI_EXIT(EFI_SUCCESS); 44391be9a77Sxypron.glpk@gmx.de } 44491be9a77Sxypron.glpk@gmx.de 44591be9a77Sxypron.glpk@gmx.de /* This gets called from do_bootefi_exec(). */ 44691be9a77Sxypron.glpk@gmx.de int efi_console_register(void) 44791be9a77Sxypron.glpk@gmx.de { 44891be9a77Sxypron.glpk@gmx.de efi_status_t r; 44991be9a77Sxypron.glpk@gmx.de r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, 45091be9a77Sxypron.glpk@gmx.de efi_key_notify, NULL, &efi_con_in.wait_for_key); 45191be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) { 45291be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to register WaitForKey event\n"); 45391be9a77Sxypron.glpk@gmx.de return r; 45491be9a77Sxypron.glpk@gmx.de } 45591be9a77Sxypron.glpk@gmx.de r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, 45691be9a77Sxypron.glpk@gmx.de efi_console_timer_notify, NULL, 45791be9a77Sxypron.glpk@gmx.de &console_timer_event); 45891be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) { 45991be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to register console event\n"); 46091be9a77Sxypron.glpk@gmx.de return r; 46191be9a77Sxypron.glpk@gmx.de } 46291be9a77Sxypron.glpk@gmx.de /* 5000 ns cycle is sufficient for 2 MBaud */ 46391be9a77Sxypron.glpk@gmx.de r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50); 46491be9a77Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 46591be9a77Sxypron.glpk@gmx.de printf("ERROR: Failed to set console timer\n"); 46691be9a77Sxypron.glpk@gmx.de return r; 46791be9a77Sxypron.glpk@gmx.de } 468