2 * Copyright (c) 2000 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
33 #include "bootstrap.h"
35 static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
36 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
37 static SIMPLE_INPUT_INTERFACE *conin;
38 static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
41 #define DEFAULT_FGCOLOR EFI_LIGHTGRAY
42 #define DEFAULT_BGCOLOR EFI_BLACK
45 static int args[MAXARGS], argc;
46 static int fg_c, bg_c, curx, cury;
49 void get_pos(int *x, int *y);
50 void curs_move(int *_x, int *_y, int x, int y);
57 static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
58 static int key_pending;
60 static void efi_cons_probe(struct console *);
61 static int efi_cons_init(int);
62 void efi_cons_putchar(int);
63 int efi_cons_getchar(void);
64 void efi_cons_efiputchar(int);
65 int efi_cons_poll(void);
67 struct console efi_console = {
80 /* Get cursor position. */
82 get_pos(int *x, int *y)
84 *x = conout->Mode->CursorColumn;
85 *y = conout->Mode->CursorRow;
88 /* Move cursor to x rows and y cols (0-based). */
90 curs_move(int *_x, int *_y, int x, int y)
92 conout->SetCursorPosition(conout, x, y);
94 *_x = conout->Mode->CursorColumn;
96 *_y = conout->Mode->CursorRow;
99 /* Clear internal state of the terminal emulation code. */
110 efi_cons_probe(struct console *cp)
114 cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
118 efi_cons_init(int arg)
123 conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
126 get_pos(&curx, &cury);
127 curs_move(&curx, &cury, curx, cury);
128 fg_c = DEFAULT_FGCOLOR;
129 bg_c = DEFAULT_BGCOLOR;
131 conout->EnableCursor(conout, TRUE);
132 status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid,
133 (void **)&coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
134 if (status != EFI_SUCCESS)
140 efi_cons_rawputchar(int c)
144 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
149 n = 8 - ((conout->Mode->CursorColumn + 8) % 8);
150 for (i = 0; i < n; i++)
151 efi_cons_rawputchar(' ');
155 efi_cons_efiputchar('\r');
156 efi_cons_efiputchar(c);
161 efi_cons_efiputchar('\r');
164 efi_cons_efiputchar('\n');
165 efi_cons_efiputchar('\r');
173 efi_cons_efiputchar('\b');
178 efi_cons_efiputchar(c);
194 /* Gracefully exit ESC-sequence processing in case of misunderstanding. */
202 efi_cons_rawputchar('\033');
204 efi_cons_rawputchar(esc);
205 for (i = 0; i <= argc; ++i) {
206 sprintf(buf, "%d", args[i]);
209 efi_cons_rawputchar(*ch++);
212 efi_cons_rawputchar(c);
216 /* Clear display from current position to end of screen. */
222 get_pos(&curx, &cury);
223 if (curx == 0 && cury == 0) {
224 conout->ClearScreen(conout);
229 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
230 CL(0); /* clear current line from cursor to end */
231 for (i = cury + 1; i < y-1; i++) {
232 curs_move(NULL, NULL, 0, i);
235 curs_move(NULL, NULL, curx, cury);
240 * Absolute cursor move to args[0] rows and args[1] columns
241 * (the coordinates are 1-based).
250 curs_move(&curx, &cury, args[1], args[0]);
254 /* Home cursor (left top corner), also called from mode command. */
259 args[0] = args[1] = 1;
263 /* Clear line from current position to end of line */
271 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
273 case 0: /* from cursor to end */
276 case 1: /* from beginning to cursor */
279 case 2: /* entire line */
282 default: /* NOTREACHED */
289 line = malloc(len * sizeof (CHAR16));
291 printf("out of memory\n");
294 for (i = 0; i < len; i++)
299 curs_move(NULL, NULL, 0, cury);
301 conout->OutputString(conout, line);
302 /* restore cursor position */
303 curs_move(NULL, NULL, curx, cury);
314 args[argc] += c - '0';
317 /* Emulate basic capabilities of cons25 terminal */
321 static int ansi_col[] = {
322 0, 4, 2, 6, 1, 5, 3, 7
333 efi_cons_rawputchar(c);
354 else if (argc + 1 >= MAXARGS)
359 case 'H': /* ho = \E[H */
367 case 'J': /* cd = \E[J */
375 fg_c = DEFAULT_FGCOLOR;
376 bg_c = DEFAULT_BGCOLOR;
378 for (i = 0; i <= argc; ++i) {
380 case 0: /* back to normal */
381 fg_c = DEFAULT_FGCOLOR;
382 bg_c = DEFAULT_BGCOLOR;
387 case 4: /* underline */
391 case 7: /* reverse */
396 case 22: /* normal intensity */
399 case 24: /* not underline */
400 case 25: /* not blinking */
403 case 30: case 31: case 32: case 33:
404 case 34: case 35: case 36: case 37:
405 fg_c = ansi_col[args[i] - 30];
407 case 39: /* normal */
408 fg_c = DEFAULT_FGCOLOR;
410 case 40: case 41: case 42: case 43:
411 case 44: case 45: case 46: case 47:
412 bg_c = ansi_col[args[i] - 40];
414 case 49: /* normal */
415 bg_c = DEFAULT_BGCOLOR;
419 conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
443 efi_cons_putchar(int c)
448 efi_cons_rawputchar(c);
457 for (i = 0; i < KEYBUFSZ; i++) {
458 if (keybuf[i] != 0) {
473 for (i = 0; i < KEYBUFSZ; i++) {
481 * We are not reading input before keybuf is empty, so we are safe
482 * just to fill keybuf from the beginning.
485 keybuf_inschar(EFI_INPUT_KEY *key)
488 switch (key->ScanCode) {
489 case SCAN_UP: /* UP */
490 keybuf[0] = 0x1b; /* esc */
494 case SCAN_DOWN: /* DOWN */
495 keybuf[0] = 0x1b; /* esc */
499 case SCAN_RIGHT: /* RIGHT */
500 keybuf[0] = 0x1b; /* esc */
504 case SCAN_LEFT: /* LEFT */
505 keybuf[0] = 0x1b; /* esc */
510 keybuf[0] = CHAR_BACKSPACE;
513 keybuf[0] = 0x1b; /* esc */
516 keybuf[0] = key->UnicodeChar;
527 status = conin->ReadKeyStroke(conin, &key);
528 if (status == EFI_SUCCESS) {
529 keybuf_inschar(&key);
540 EFI_KEY_DATA key_data;
543 status = coninex->ReadKeyStrokeEx(coninex, &key_data);
544 if (status == EFI_SUCCESS) {
545 kss = key_data.KeyState.KeyShiftState;
547 if (kss & EFI_SHIFT_STATE_VALID) {
550 * quick mapping to control chars, replace with
553 if (kss & EFI_RIGHT_CONTROL_PRESSED ||
554 kss & EFI_LEFT_CONTROL_PRESSED) {
555 if (kp->UnicodeChar >= 'a' &&
556 kp->UnicodeChar <= 'z') {
557 kp->UnicodeChar -= 'a';
561 if (kp->ScanCode == 0 && kp->UnicodeChar == 0)
571 efi_cons_getchar(void)
575 if ((c = keybuf_getchar()) != 0)
580 if (coninex == NULL) {
582 return (keybuf_getchar());
584 if (efi_readkey_ex())
585 return (keybuf_getchar());
596 if (keybuf_ischar() || key_pending)
600 * Some EFI implementation (u-boot for example) do not support
602 * CheckEvent() can clear the signaled state.
604 if (coninex != NULL) {
605 if (coninex->WaitForKeyEx == NULL) {
606 key_pending = efi_readkey_ex();
608 status = BS->CheckEvent(coninex->WaitForKeyEx);
609 key_pending = status == EFI_SUCCESS;
612 if (conin->WaitForKey == NULL) {
613 key_pending = efi_readkey();
615 status = BS->CheckEvent(conin->WaitForKey);
616 key_pending = status == EFI_SUCCESS;
620 return (key_pending);
623 /* Plain direct access to EFI OutputString(). */
625 efi_cons_efiputchar(int c)
630 * translate box chars to unicode
634 case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
635 case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
636 case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
637 case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
638 case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
639 case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
642 case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
643 case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
644 case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
645 case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
646 case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
647 case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
652 buf[1] = 0; /* terminate string */
654 conout->OutputString(conout, buf);