Merge branch 'master_sh/gen4/mmcfix' of https://source.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / common / menu.c
index 7b66d19..9451417 100644 (file)
@@ -4,14 +4,19 @@
  * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
  */
 
+#include <ansi.h>
 #include <common.h>
 #include <cli.h>
 #include <malloc.h>
 #include <errno.h>
+#include <linux/delay.h>
 #include <linux/list.h>
+#include <watchdog.h>
 
 #include "menu.h"
 
+#define ansi 0
+
 /*
  * Internally, each item in a menu is represented by a struct menu_item.
  *
@@ -36,6 +41,7 @@ struct menu {
        int timeout;
        char *title;
        int prompt;
+       void (*display_statusline)(struct menu *);
        void (*item_data_print)(void *);
        char *(*item_choice)(void *);
        void *item_choice_data;
@@ -106,10 +112,6 @@ static inline void *menu_item_destroy(struct menu *m,
        return NULL;
 }
 
-__weak void menu_display_statusline(struct menu *m)
-{
-}
-
 /*
  * Display a menu so the user can make a choice of an item. First display its
  * title, if any, and then each item in the menu.
@@ -120,7 +122,8 @@ static inline void menu_display(struct menu *m)
                puts(m->title);
                putc('\n');
        }
-       menu_display_statusline(m);
+       if (m->display_statusline)
+               m->display_statusline(m);
 
        menu_items_iter(m, menu_item_print, NULL);
 }
@@ -273,7 +276,10 @@ int menu_get_choice(struct menu *m, void **choice)
        if (!m || !choice)
                return -EINVAL;
 
-       if (!m->prompt || m->item_cnt == 1)
+       if (!m->item_cnt)
+               return -ENOENT;
+
+       if (!m->prompt)
                return menu_default_choice(m, choice);
 
        return menu_interactive_choice(m, choice);
@@ -344,6 +350,9 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data)
  * timeout. If 1, the user will be prompted for input regardless of the value
  * of timeout.
  *
+ * display_statusline - If not NULL, will be called to show a statusline when
+ * the menu is displayed.
+ *
  * item_data_print - If not NULL, will be called for each item when the menu
  * is displayed, with the pointer to the item's data passed as the argument.
  * If NULL, each item's key will be printed instead.  Since an item's key is
@@ -360,6 +369,7 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data)
  * insufficient memory available to create the menu.
  */
 struct menu *menu_create(char *title, int timeout, int prompt,
+                               void (*display_statusline)(struct menu *),
                                void (*item_data_print)(void *),
                                char *(*item_choice)(void *),
                                void *item_choice_data)
@@ -374,6 +384,7 @@ struct menu *menu_create(char *title, int timeout, int prompt,
        m->default_item = NULL;
        m->prompt = prompt;
        m->timeout = timeout;
+       m->display_statusline = display_statusline;
        m->item_data_print = item_data_print;
        m->item_choice = item_choice;
        m->item_choice_data = item_choice_data;
@@ -415,3 +426,123 @@ int menu_destroy(struct menu *m)
 
        return 1;
 }
+
+enum bootmenu_key bootmenu_autoboot_loop(struct bootmenu_data *menu,
+                                        struct cli_ch_state *cch)
+{
+       enum bootmenu_key key = BKEY_NONE;
+       int i, c;
+
+       while (menu->delay > 0) {
+               if (ansi)
+                       printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
+               printf("Hit any key to stop autoboot: %d ", menu->delay);
+               for (i = 0; i < 100; ++i) {
+                       int ichar;
+
+                       if (!tstc()) {
+                               schedule();
+                               mdelay(10);
+                               continue;
+                       }
+
+                       menu->delay = -1;
+                       c = getchar();
+
+                       ichar = cli_ch_process(cch, c);
+
+                       switch (ichar) {
+                       case '\0':
+                               key = BKEY_NONE;
+                               break;
+                       case '\n':
+                               key = BKEY_SELECT;
+                               break;
+                       case 0x3: /* ^C */
+                               key = BKEY_QUIT;
+                               break;
+                       default:
+                               key = BKEY_NONE;
+                               break;
+                       }
+                       break;
+               }
+
+               if (menu->delay < 0)
+                       break;
+
+               --menu->delay;
+       }
+
+       if (ansi)
+               printf(ANSI_CURSOR_POSITION ANSI_CLEAR_LINE, menu->count + 5, 1);
+
+       if (menu->delay == 0)
+               key = BKEY_SELECT;
+
+       return key;
+}
+
+enum bootmenu_key bootmenu_conv_key(int ichar)
+{
+       enum bootmenu_key key;
+
+       switch (ichar) {
+       case '\n':
+               /* enter key was pressed */
+               key = BKEY_SELECT;
+               break;
+       case CTL_CH('c'):
+       case '\e':
+               /* ^C was pressed */
+               key = BKEY_QUIT;
+               break;
+       case CTL_CH('p'):
+               key = BKEY_UP;
+               break;
+       case CTL_CH('n'):
+               key = BKEY_DOWN;
+               break;
+       case CTL_CH('s'):
+               key = BKEY_SAVE;
+               break;
+       case '+':
+               key = BKEY_PLUS;
+               break;
+       case '-':
+               key = BKEY_MINUS;
+               break;
+       case ' ':
+               key = BKEY_SPACE;
+               break;
+       default:
+               key = BKEY_NONE;
+               break;
+       }
+
+       return key;
+}
+
+enum bootmenu_key bootmenu_loop(struct bootmenu_data *menu,
+                               struct cli_ch_state *cch)
+{
+       enum bootmenu_key key;
+       int c;
+
+       c = cli_ch_process(cch, 0);
+       if (!c) {
+               while (!c && !tstc()) {
+                       schedule();
+                       mdelay(10);
+                       c = cli_ch_process(cch, -ETIMEDOUT);
+               }
+               if (!c) {
+                       c = getchar();
+                       c = cli_ch_process(cch, c);
+               }
+       }
+
+       key = bootmenu_conv_key(c);
+
+       return key;
+}