source: bootcd/isolinux/syslinux-6.03/gpxe/src/interface/efi/efi_console.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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
19FILE_LICENCE ( GPL2_OR_LATER );
20
21#include <stddef.h>
22#include <assert.h>
23#include <gpxe/efi/efi.h>
24#include <gpxe/ansiesc.h>
25#include <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 */
52static 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 */
61static 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 */
80static 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 */
96static 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 */
134static 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 */
142static 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 */
151static 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 */
171static const char *ansi_input = "";
172
173/** Mapping from EFI scan codes to ANSI escape sequences */
174static 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 */
204static 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 */
217static 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 */
256static 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
272struct console_driver efi_console __console_driver = {
273        .putchar = efi_putchar,
274        .getchar = efi_getchar,
275        .iskey = efi_iskey,
276};
Note: See TracBrowser for help on using the repository browser.