|
|
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.