|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2008 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stddef.h> ! 22: #include <assert.h> ! 23: #include <ipxe/efi/efi.h> ! 24: #include <ipxe/ansiesc.h> ! 25: #include <ipxe/console.h> ! 26: ! 27: #define ATTR_BOLD 0x08 ! 28: ! 29: #define ATTR_FCOL_MASK 0x07 ! 30: #define ATTR_FCOL_BLACK 0x00 ! 31: #define ATTR_FCOL_BLUE 0x01 ! 32: #define ATTR_FCOL_GREEN 0x02 ! 33: #define ATTR_FCOL_CYAN 0x03 ! 34: #define ATTR_FCOL_RED 0x04 ! 35: #define ATTR_FCOL_MAGENTA 0x05 ! 36: #define ATTR_FCOL_YELLOW 0x06 ! 37: #define ATTR_FCOL_WHITE 0x07 ! 38: ! 39: #define ATTR_BCOL_MASK 0x70 ! 40: #define ATTR_BCOL_BLACK 0x00 ! 41: #define ATTR_BCOL_BLUE 0x10 ! 42: #define ATTR_BCOL_GREEN 0x20 ! 43: #define ATTR_BCOL_CYAN 0x30 ! 44: #define ATTR_BCOL_RED 0x40 ! 45: #define ATTR_BCOL_MAGENTA 0x50 ! 46: #define ATTR_BCOL_YELLOW 0x60 ! 47: #define ATTR_BCOL_WHITE 0x70 ! 48: ! 49: #define ATTR_DEFAULT ATTR_FCOL_WHITE ! 50: ! 51: /** Current character attribute */ ! 52: static unsigned int efi_attr = ATTR_DEFAULT; ! 53: ! 54: /** ! 55: * Handle ANSI CUP (cursor position) ! 56: * ! 57: * @v count Parameter count ! 58: * @v params[0] Row (1 is top) ! 59: * @v params[1] Column (1 is left) ! 60: */ ! 61: static void efi_handle_cup ( unsigned int count __unused, int params[] ) { ! 62: EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; ! 63: int cx = ( params[1] - 1 ); ! 64: int cy = ( params[0] - 1 ); ! 65: ! 66: if ( cx < 0 ) ! 67: cx = 0; ! 68: if ( cy < 0 ) ! 69: cy = 0; ! 70: ! 71: conout->SetCursorPosition ( conout, cx, cy ); ! 72: } ! 73: ! 74: /** ! 75: * Handle ANSI ED (erase in page) ! 76: * ! 77: * @v count Parameter count ! 78: * @v params[0] Region to erase ! 79: */ ! 80: static void efi_handle_ed ( unsigned int count __unused, ! 81: int params[] __unused ) { ! 82: EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; ! 83: ! 84: /* We assume that we always clear the whole screen */ ! 85: assert ( params[0] == ANSIESC_ED_ALL ); ! 86: ! 87: conout->ClearScreen ( conout ); ! 88: } ! 89: ! 90: /** ! 91: * Handle ANSI SGR (set graphics rendition) ! 92: * ! 93: * @v count Parameter count ! 94: * @v params List of graphic rendition aspects ! 95: */ ! 96: static void efi_handle_sgr ( unsigned int count, int params[] ) { ! 97: EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; ! 98: static const uint8_t efi_attr_fcols[10] = { ! 99: ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN, ! 100: ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA, ! 101: ATTR_FCOL_CYAN, ATTR_FCOL_WHITE, ! 102: ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */ ! 103: }; ! 104: static const uint8_t efi_attr_bcols[10] = { ! 105: ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN, ! 106: ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA, ! 107: ATTR_BCOL_CYAN, ATTR_BCOL_WHITE, ! 108: ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */ ! 109: }; ! 110: unsigned int i; ! 111: int aspect; ! 112: ! 113: for ( i = 0 ; i < count ; i++ ) { ! 114: aspect = params[i]; ! 115: if ( aspect == 0 ) { ! 116: efi_attr = ATTR_DEFAULT; ! 117: } else if ( aspect == 1 ) { ! 118: efi_attr |= ATTR_BOLD; ! 119: } else if ( aspect == 22 ) { ! 120: efi_attr &= ~ATTR_BOLD; ! 121: } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) { ! 122: efi_attr &= ~ATTR_FCOL_MASK; ! 123: efi_attr |= efi_attr_fcols[ aspect - 30 ]; ! 124: } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) { ! 125: efi_attr &= ~ATTR_BCOL_MASK; ! 126: efi_attr |= efi_attr_bcols[ aspect - 40 ]; ! 127: } ! 128: } ! 129: ! 130: conout->SetAttribute ( conout, efi_attr ); ! 131: } ! 132: ! 133: /** EFI console ANSI escape sequence handlers */ ! 134: static struct ansiesc_handler efi_ansiesc_handlers[] = { ! 135: { ANSIESC_CUP, efi_handle_cup }, ! 136: { ANSIESC_ED, efi_handle_ed }, ! 137: { ANSIESC_SGR, efi_handle_sgr }, ! 138: { 0, NULL } ! 139: }; ! 140: ! 141: /** EFI console ANSI escape sequence context */ ! 142: static struct ansiesc_context efi_ansiesc_ctx = { ! 143: .handlers = efi_ansiesc_handlers, ! 144: }; ! 145: ! 146: /** ! 147: * Print a character to EFI console ! 148: * ! 149: * @v character Character to be printed ! 150: */ ! 151: static void efi_putchar ( int character ) { ! 152: EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; ! 153: wchar_t wstr[] = { character, 0 }; ! 154: ! 155: /* Intercept ANSI escape sequences */ ! 156: character = ansiesc_process ( &efi_ansiesc_ctx, character ); ! 157: if ( character < 0 ) ! 158: return; ! 159: ! 160: conout->OutputString ( conout, wstr ); ! 161: } ! 162: ! 163: /** ! 164: * Pointer to current ANSI output sequence ! 165: * ! 166: * While we are in the middle of returning an ANSI sequence for a ! 167: * special key, this will point to the next character to return. When ! 168: * not in the middle of such a sequence, this will point to a NUL ! 169: * (note: not "will be NULL"). ! 170: */ ! 171: static const char *ansi_input = ""; ! 172: ! 173: /** Mapping from EFI scan codes to ANSI escape sequences */ ! 174: static const char *ansi_sequences[] = { ! 175: [SCAN_UP] = "[A", ! 176: [SCAN_DOWN] = "[B", ! 177: [SCAN_RIGHT] = "[C", ! 178: [SCAN_LEFT] = "[D", ! 179: [SCAN_HOME] = "[H", ! 180: [SCAN_END] = "[F", ! 181: [SCAN_INSERT] = "[2~", ! 182: /* EFI translates an incoming backspace via the serial console ! 183: * into a SCAN_DELETE. There's not much we can do about this. ! 184: */ ! 185: [SCAN_DELETE] = "[3~", ! 186: [SCAN_PAGE_UP] = "[5~", ! 187: [SCAN_PAGE_DOWN] = "[6~", ! 188: /* EFI translates some (but not all) incoming escape sequences ! 189: * via the serial console into equivalent scancodes. When it ! 190: * doesn't recognise a sequence, it helpfully(!) translates ! 191: * the initial ESC and passes the remainder through verbatim. ! 192: * Treating SCAN_ESC as equivalent to an empty escape sequence ! 193: * works around this bug. ! 194: */ ! 195: [SCAN_ESC] = "", ! 196: }; ! 197: ! 198: /** ! 199: * Get ANSI escape sequence corresponding to EFI scancode ! 200: * ! 201: * @v scancode EFI scancode ! 202: * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL ! 203: */ ! 204: static const char * scancode_to_ansi_seq ( unsigned int scancode ) { ! 205: if ( scancode < ( sizeof ( ansi_sequences ) / ! 206: sizeof ( ansi_sequences[0] ) ) ) { ! 207: return ansi_sequences[scancode]; ! 208: } ! 209: return NULL; ! 210: } ! 211: ! 212: /** ! 213: * Get character from EFI console ! 214: * ! 215: * @ret character Character read from console ! 216: */ ! 217: static int efi_getchar ( void ) { ! 218: EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; ! 219: const char *ansi_seq; ! 220: EFI_INPUT_KEY key; ! 221: EFI_STATUS efirc; ! 222: ! 223: /* If we are mid-sequence, pass out the next byte */ ! 224: if ( *ansi_input ) ! 225: return *(ansi_input++); ! 226: ! 227: /* Read key from real EFI console */ ! 228: if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) { ! 229: DBG ( "EFI could not read keystroke: %s\n", ! 230: efi_strerror ( efirc ) ); ! 231: return 0; ! 232: } ! 233: DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n", ! 234: key.UnicodeChar, key.ScanCode ); ! 235: ! 236: /* If key has a Unicode representation, return it */ ! 237: if ( key.UnicodeChar ) ! 238: return key.UnicodeChar; ! 239: ! 240: /* Otherwise, check for a special key that we know about */ ! 241: if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) { ! 242: /* Start of escape sequence: return ESC (0x1b) */ ! 243: ansi_input = ansi_seq; ! 244: return 0x1b; ! 245: } ! 246: ! 247: return 0; ! 248: } ! 249: ! 250: /** ! 251: * Check for character ready to read from EFI console ! 252: * ! 253: * @ret True Character available to read ! 254: * @ret False No character available to read ! 255: */ ! 256: static int efi_iskey ( void ) { ! 257: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 258: EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; ! 259: EFI_STATUS efirc; ! 260: ! 261: /* If we are mid-sequence, we are always ready */ ! 262: if ( *ansi_input ) ! 263: return 1; ! 264: ! 265: /* Check to see if the WaitForKey event has fired */ ! 266: if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 ) ! 267: return 1; ! 268: ! 269: return 0; ! 270: } ! 271: ! 272: struct console_driver efi_console __console_driver = { ! 273: .putchar = efi_putchar, ! 274: .getchar = efi_getchar, ! 275: .iskey = efi_iskey, ! 276: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.