bootmenu: Allow to quit it via ESC/CTRL+C

When ESC/CTRL+C is pressed interrupt bootmenu and jump into U-Boot console.
As the last entry in bootmenu is always U-Boot console just choose the last
entry when ESC or CTRL+C is pressed.

ESC key is detected when either no other character appears after '\e'
within 10ms or when non-'[' appears after '\e'.

It is useful when bootmenu is part of boot process and you want to
interrupt boot process by scripts which control U-Boot (serial) console.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Pali Rohár 2020-12-27 01:04:38 +01:00 committed by Tom Rini
parent 976a68a20d
commit 83a287a613
1 changed files with 35 additions and 7 deletions

View File

@ -45,6 +45,7 @@ enum bootmenu_key {
KEY_UP, KEY_UP,
KEY_DOWN, KEY_DOWN,
KEY_SELECT, KEY_SELECT,
KEY_QUIT,
}; };
static char *bootmenu_getoption(unsigned short int n) static char *bootmenu_getoption(unsigned short int n)
@ -109,6 +110,9 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
case '\r': case '\r':
*key = KEY_SELECT; *key = KEY_SELECT;
break; break;
case 0x3: /* ^C */
*key = KEY_QUIT;
break;
default: default:
*key = KEY_NONE; *key = KEY_NONE;
break; break;
@ -136,13 +140,25 @@ static void bootmenu_loop(struct bootmenu_data *menu,
{ {
int c; int c;
while (!tstc()) { if (*esc == 1) {
WATCHDOG_RESET(); if (tstc()) {
mdelay(10); c = getchar();
} else {
WATCHDOG_RESET();
mdelay(10);
if (tstc())
c = getchar();
else
c = '\e';
}
} else {
while (!tstc()) {
WATCHDOG_RESET();
mdelay(10);
}
c = getchar();
} }
c = getchar();
switch (*esc) { switch (*esc) {
case 0: case 0:
/* First char of ANSI escape sequence '\e' */ /* First char of ANSI escape sequence '\e' */
@ -157,7 +173,9 @@ static void bootmenu_loop(struct bootmenu_data *menu,
*esc = 2; *esc = 2;
*key = KEY_NONE; *key = KEY_NONE;
} else { } else {
*esc = 0; /* Alone ESC key was pressed */
*key = KEY_QUIT;
*esc = (c == '\e') ? 1 : 0;
} }
break; break;
case 2: case 2:
@ -187,6 +205,10 @@ static void bootmenu_loop(struct bootmenu_data *menu,
/* enter key was pressed */ /* enter key was pressed */
if (c == '\r') if (c == '\r')
*key = KEY_SELECT; *key = KEY_SELECT;
/* ^C was pressed */
if (c == 0x3)
*key = KEY_QUIT;
} }
static char *bootmenu_choice_entry(void *data) static char *bootmenu_choice_entry(void *data)
@ -222,6 +244,12 @@ static char *bootmenu_choice_entry(void *data)
for (i = 0; i < menu->active; ++i) for (i = 0; i < menu->active; ++i)
iter = iter->next; iter = iter->next;
return iter->key; return iter->key;
case KEY_QUIT:
/* Quit by choosing the last entry - U-Boot console */
iter = menu->first;
while (iter->next)
iter = iter->next;
return iter->key;
default: default:
break; break;
} }
@ -389,7 +417,7 @@ static void menu_display_statusline(struct menu *m)
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
puts(ANSI_CLEAR_LINE); puts(ANSI_CLEAR_LINE);
printf(ANSI_CURSOR_POSITION, menu->count + 6, 1); printf(ANSI_CURSOR_POSITION, menu->count + 6, 1);
puts(" Press UP/DOWN to move, ENTER to select"); puts(" Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
puts(ANSI_CLEAR_LINE_TO_END); puts(ANSI_CLEAR_LINE_TO_END);
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
puts(ANSI_CLEAR_LINE); puts(ANSI_CLEAR_LINE);