]> Git Repo - u-boot.git/blobdiff - lib/efi_loader/efi_console.c
Merge https://source.denx.de/u-boot/custodians/u-boot-marvell
[u-boot.git] / lib / efi_loader / efi_console.c
index ba68a15017243dd416c42a2da3950cec65408a33..03dece51aeaa8ed7d45a2d3408690b6701a0d077 100644 (file)
@@ -5,13 +5,16 @@
  *  Copyright (c) 2016 Alexander Graf
  */
 
-#include <common.h>
+#define LOG_CATEGORY LOGC_EFI
+
+#include <ansi.h>
 #include <charset.h>
 #include <malloc.h>
 #include <time.h>
 #include <dm/device.h>
 #include <efi_loader.h>
 #include <env.h>
+#include <log.h>
 #include <stdio_dev.h>
 #include <video_console.h>
 #include <linux/delay.h>
@@ -58,7 +61,12 @@ const efi_guid_t efi_guid_text_output_protocol =
 #define cESC '\x1b'
 #define ESC "\x1b"
 
-/* Default to mode 0 */
+/*
+ * efi_con_mode - mode information of the Simple Text Output Protocol
+ *
+ * Use safe settings before efi_setup_console_size() is called.
+ * By default enable only the 80x25 mode which must always exist.
+ */
 static struct simple_text_output_mode efi_con_mode = {
        .max_mode = 1,
        .mode = 0,
@@ -68,6 +76,14 @@ static struct simple_text_output_mode efi_con_mode = {
        .cursor_visible = 1,
 };
 
+/**
+ * term_get_char() - read a character from the console
+ *
+ * Wait for up to 100 ms to read a character from the console.
+ *
+ * @c:         pointer to the buffer to receive the character
+ * Return:     0 on success, 1 otherwise
+ */
 static int term_get_char(s32 *c)
 {
        u64 timeout;
@@ -333,24 +349,26 @@ static int __maybe_unused query_vidconsole(int *rows, int *cols)
 }
 
 /**
- * query_console_size() - update the mode table.
+ * efi_setup_console_size() - update the mode table.
  *
  * By default the only mode available is 80x25. If the console has at least 50
  * lines, enable mode 80x50. If we can query the console size and it is neither
  * 80x25 nor 80x50, set it as an additional mode.
  */
-static void query_console_size(void)
+void efi_setup_console_size(void)
 {
        int rows = 25, cols = 80;
        int ret = -ENODEV;
 
-       if (IS_ENABLED(CONFIG_DM_VIDEO))
+       if (IS_ENABLED(CONFIG_VIDEO))
                ret = query_vidconsole(&rows, &cols);
        if (ret)
                ret = query_console_serial(&rows, &cols);
        if (ret)
                return;
 
+       log_debug("Console size %dx%d\n", rows, cols);
+
        /* Test if we can have Mode 1 */
        if (cols >= 80 && rows >= 50) {
                efi_cout_modes[1].present = 1;
@@ -371,7 +389,6 @@ static void query_console_size(void)
        }
 }
 
-
 /**
  * efi_cout_query_mode() - get terminal size for a text mode
  *
@@ -450,6 +467,31 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
        return EFI_EXIT(EFI_SUCCESS);
 }
 
+/**
+ * efi_clear_screen() - clear screen
+ */
+static void efi_clear_screen(void)
+{
+       if (CONFIG_IS_ENABLED(EFI_SCROLL_ON_CLEAR_SCREEN)) {
+               unsigned int row, screen_rows, screen_columns;
+
+               /* Avoid overwriting previous outputs on streaming consoles */
+               screen_rows = efi_cout_modes[efi_con_mode.mode].rows;
+               screen_columns = efi_cout_modes[efi_con_mode.mode].columns;
+               printf(ESC "[%u;%uH", screen_rows, screen_columns);
+               for (row = 1; row < screen_rows; row++)
+                       printf("\n");
+       }
+
+       /*
+        * The Linux console wants both a clear and a home command. The video
+        * uclass does not support <ESC>[H without coordinates, yet.
+        */
+       printf(ESC "[2J" ESC "[1;1H");
+       efi_con_mode.cursor_column = 0;
+       efi_con_mode.cursor_row = 0;
+}
+
 /**
  * efi_cout_clear_screen() - clear screen
  *
@@ -465,13 +507,13 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
        EFI_ENTRY("%p", this);
 
-       /*
-        * The Linux console wants both a clear and a home command. The video
-        * uclass does not support <ESC>[H without coordinates, yet.
-        */
-       printf(ESC "[2J" ESC "[1;1H");
-       efi_con_mode.cursor_column = 0;
-       efi_con_mode.cursor_row = 0;
+       /* Set default colors if not done yet */
+       if (efi_con_mode.attribute == 0) {
+               efi_con_mode.attribute = 0x07;
+               printf(ESC "[0;37;40m");
+       }
+
+       efi_clear_screen();
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -500,7 +542,7 @@ static efi_status_t EFIAPI efi_cout_set_mode(
                return EFI_EXIT(EFI_UNSUPPORTED);
 
        efi_con_mode.mode = mode_number;
-       EFI_CALL(efi_cout_clear_screen(this));
+       efi_clear_screen();
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -522,11 +564,11 @@ static efi_status_t EFIAPI efi_cout_reset(
 {
        EFI_ENTRY("%p, %d", this, extended_verification);
 
-       /* Clear screen */
-       EFI_CALL(efi_cout_clear_screen(this));
        /* Set default colors */
        efi_con_mode.attribute = 0x07;
        printf(ESC "[0;37;40m");
+       /* Clear screen */
+       efi_clear_screen();
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -634,7 +676,7 @@ static LIST_HEAD(cin_notify_functions);
  * @mod:       Xterm shift mask
  * @key_state:  receives the state of the shift, alt, control, and logo keys
  */
-void set_shift_mask(int mod, struct efi_key_state *key_state)
+static void set_shift_mask(int mod, struct efi_key_state *key_state)
 {
        key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
        if (mod) {
@@ -978,12 +1020,14 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
        efi_cin_check();
 
        if (!key_available) {
+               memset(key_data, 0, sizeof(struct efi_key_data));
                ret = EFI_NOT_READY;
                goto out;
        }
        /*
         * CTRL+A - CTRL+Z have to be signaled as a - z.
         * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
+        * CTRL+\ - CTRL+_ have to be signaled as \ - _.
         */
        switch (next_key.key.unicode_char) {
        case 0x01 ... 0x07:
@@ -996,6 +1040,9 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
                        next_key.key.unicode_char += 0x40;
                else
                        next_key.key.unicode_char += 0x60;
+               break;
+       case 0x1c ... 0x1f:
+                       next_key.key.unicode_char += 0x40;
        }
        *key_data = next_key;
        key_available = false;
@@ -1262,16 +1309,15 @@ efi_status_t efi_console_register(void)
        efi_status_t r;
        struct efi_device_path *dp;
 
-       /* Set up mode information */
-       query_console_size();
-
        /* Install protocols on root node */
-       r = EFI_CALL(efi_install_multiple_protocol_interfaces
-                    (&efi_root,
-                     &efi_guid_text_output_protocol, &efi_con_out,
-                     &efi_guid_text_input_protocol, &efi_con_in,
-                     &efi_guid_text_input_ex_protocol, &efi_con_in_ex,
-                     NULL));
+       r = efi_install_multiple_protocol_interfaces(&efi_root,
+                                                    &efi_guid_text_output_protocol,
+                                                    &efi_con_out,
+                                                    &efi_guid_text_input_protocol,
+                                                    &efi_con_in,
+                                                    &efi_guid_text_input_ex_protocol,
+                                                    &efi_con_in_ex,
+                                                    NULL);
 
        /* Create console node and install device path protocols */
        if (CONFIG_IS_ENABLED(DM_SERIAL)) {
@@ -1312,3 +1358,70 @@ out_of_memory:
        printf("ERROR: Out of memory\n");
        return r;
 }
+
+/**
+ * efi_console_get_u16_string() - get user input string
+ *
+ * @cin:               protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @buf:               buffer to store user input string in UTF16
+ * @count:             number of u16 string including NULL terminator that buf has
+ * @filter_func:       callback to filter user input
+ * @row:               row number to locate user input form
+ * @col:               column number to locate user input form
+ * Return:             status code
+ */
+efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin,
+                                       u16 *buf, efi_uintn_t count,
+                                       efi_console_filter_func filter_func,
+                                       int row, int col)
+{
+       efi_status_t ret;
+       efi_uintn_t len = 0;
+       struct efi_input_key key;
+
+       printf(ANSI_CURSOR_POSITION
+              ANSI_CLEAR_LINE_TO_END
+              ANSI_CURSOR_SHOW, row, col);
+
+       efi_cin_empty_buffer();
+
+       for (;;) {
+               do {
+                       ret = EFI_CALL(cin->read_key_stroke(cin, &key));
+                       mdelay(10);
+               } while (ret == EFI_NOT_READY);
+
+               if (key.unicode_char == u'\b') {
+                       if (len > 0)
+                               buf[--len] = u'\0';
+
+                       printf(ANSI_CURSOR_POSITION
+                              "%ls"
+                              ANSI_CLEAR_LINE_TO_END, row, col, buf);
+                       continue;
+               } else if (key.unicode_char == u'\r') {
+                       buf[len] = u'\0';
+                       return EFI_SUCCESS;
+               } else if (key.unicode_char == 0x3 || key.scan_code == 23) {
+                       return EFI_ABORTED;
+               } else if (key.unicode_char < 0x20) {
+                       /* ignore control codes other than Ctrl+C, '\r' and '\b' */
+                       continue;
+               } else if (key.scan_code != 0) {
+                       /* only accept single ESC press for cancel */
+                       continue;
+               }
+
+               if (filter_func) {
+                       if (filter_func(&key) != EFI_SUCCESS)
+                               continue;
+               }
+
+               if (len >= (count - 1))
+                       continue;
+
+               buf[len] = key.unicode_char;
+               len++;
+               printf(ANSI_CURSOR_POSITION "%ls", row, col, buf);
+       }
+}
This page took 0.034339 seconds and 4 git commands to generate.