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 14*5be8b0a3SEmmanuel Vadot #define EFI_COUT_MODE_2 2 15*5be8b0a3SEmmanuel Vadot #define EFI_MAX_COUT_MODE 3 16*5be8b0a3SEmmanuel Vadot 17*5be8b0a3SEmmanuel Vadot struct cout_mode { 18*5be8b0a3SEmmanuel Vadot unsigned long columns; 19*5be8b0a3SEmmanuel Vadot unsigned long rows; 20*5be8b0a3SEmmanuel Vadot int present; 21*5be8b0a3SEmmanuel Vadot }; 22*5be8b0a3SEmmanuel Vadot 23*5be8b0a3SEmmanuel Vadot static struct cout_mode efi_cout_modes[] = { 24*5be8b0a3SEmmanuel Vadot /* EFI Mode 0 is 80x25 and always present */ 25*5be8b0a3SEmmanuel Vadot { 26*5be8b0a3SEmmanuel Vadot .columns = 80, 27*5be8b0a3SEmmanuel Vadot .rows = 25, 28*5be8b0a3SEmmanuel Vadot .present = 1, 29*5be8b0a3SEmmanuel Vadot }, 30*5be8b0a3SEmmanuel Vadot /* EFI Mode 1 is always 80x50 */ 31*5be8b0a3SEmmanuel Vadot { 32*5be8b0a3SEmmanuel Vadot .columns = 80, 33*5be8b0a3SEmmanuel Vadot .rows = 50, 34*5be8b0a3SEmmanuel Vadot .present = 0, 35*5be8b0a3SEmmanuel Vadot }, 36*5be8b0a3SEmmanuel Vadot /* Value are unknown until we query the console */ 37*5be8b0a3SEmmanuel Vadot { 38*5be8b0a3SEmmanuel Vadot .columns = 0, 39*5be8b0a3SEmmanuel Vadot .rows = 0, 40*5be8b0a3SEmmanuel Vadot .present = 0, 41*5be8b0a3SEmmanuel Vadot }, 42*5be8b0a3SEmmanuel Vadot }; 43*5be8b0a3SEmmanuel 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 86*5be8b0a3SEmmanuel Vadot /* Default to mode 0 */ 87c1311ad4SAlexander Graf static struct simple_text_output_mode efi_con_mode = { 88*5be8b0a3SEmmanuel 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 { 162*5be8b0a3SEmmanuel Vadot struct cout_mode *mode; 163c1311ad4SAlexander Graf u16 ch; 164c1311ad4SAlexander Graf 165*5be8b0a3SEmmanuel 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++; 173*5be8b0a3SEmmanuel 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 } 177*5be8b0a3SEmmanuel Vadot if (efi_con_mode.cursor_row > mode->rows) 178*5be8b0a3SEmmanuel 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 192*5be8b0a3SEmmanuel Vadot static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols) 193*5be8b0a3SEmmanuel Vadot { 194*5be8b0a3SEmmanuel Vadot if (!mode->present) 195*5be8b0a3SEmmanuel Vadot return false; 196*5be8b0a3SEmmanuel Vadot 197*5be8b0a3SEmmanuel Vadot return (mode->rows == rows) && (mode->columns == cols); 198*5be8b0a3SEmmanuel Vadot } 199*5be8b0a3SEmmanuel 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]; 210*5be8b0a3SEmmanuel Vadot int cols; 211*5be8b0a3SEmmanuel 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 233*5be8b0a3SEmmanuel Vadot cols = n[2]; 234*5be8b0a3SEmmanuel Vadot rows = n[1]; 235*5be8b0a3SEmmanuel Vadot 236*5be8b0a3SEmmanuel Vadot /* Test if we can have Mode 1 */ 237*5be8b0a3SEmmanuel Vadot if (cols >= 80 && rows >= 50) { 238*5be8b0a3SEmmanuel Vadot efi_cout_modes[1].present = 1; 239*5be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = 2; 240c1311ad4SAlexander Graf } 241c1311ad4SAlexander Graf 242*5be8b0a3SEmmanuel Vadot /* 243*5be8b0a3SEmmanuel Vadot * Install our mode as mode 2 if it is different 244*5be8b0a3SEmmanuel Vadot * than mode 0 or 1 and set it as the currently selected mode 245*5be8b0a3SEmmanuel Vadot */ 246*5be8b0a3SEmmanuel Vadot if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) && 247*5be8b0a3SEmmanuel Vadot !cout_mode_matches(&efi_cout_modes[1], rows, cols)) { 248*5be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].columns = cols; 249*5be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].rows = rows; 250*5be8b0a3SEmmanuel Vadot efi_cout_modes[EFI_COUT_MODE_2].present = 1; 251*5be8b0a3SEmmanuel Vadot efi_con_mode.max_mode = EFI_MAX_COUT_MODE; 252*5be8b0a3SEmmanuel Vadot efi_con_mode.mode = EFI_COUT_MODE_2; 253*5be8b0a3SEmmanuel Vadot } 254*5be8b0a3SEmmanuel Vadot } 255*5be8b0a3SEmmanuel Vadot 256*5be8b0a3SEmmanuel Vadot if (mode_number >= efi_con_mode.max_mode) 257*5be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED); 258*5be8b0a3SEmmanuel Vadot 259*5be8b0a3SEmmanuel Vadot if (efi_cout_modes[mode_number].present != 1) 260*5be8b0a3SEmmanuel Vadot return EFI_EXIT(EFI_UNSUPPORTED); 261*5be8b0a3SEmmanuel Vadot 262c1311ad4SAlexander Graf out: 263c1311ad4SAlexander Graf if (columns) 264*5be8b0a3SEmmanuel Vadot *columns = efi_cout_modes[mode_number].columns; 265c1311ad4SAlexander Graf if (rows) 266*5be8b0a3SEmmanuel 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 278*5be8b0a3SEmmanuel Vadot if (mode_number > efi_con_mode.max_mode) 279c1311ad4SAlexander Graf return EFI_EXIT(EFI_UNSUPPORTED); 280*5be8b0a3SEmmanuel Vadot 281*5be8b0a3SEmmanuel Vadot efi_con_mode.mode = mode_number; 282*5be8b0a3SEmmanuel Vadot efi_con_mode.cursor_column = 0; 283*5be8b0a3SEmmanuel Vadot efi_con_mode.cursor_row = 0; 284*5be8b0a3SEmmanuel Vadot 285*5be8b0a3SEmmanuel 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 424c1311ad4SAlexander Graf const 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 }; 429