1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2011-2013 Pali Rohár <pali.rohar@gmail.com> 3*2e192b24SSimon Glass * 4*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 5*2e192b24SSimon Glass */ 6*2e192b24SSimon Glass 7*2e192b24SSimon Glass #include <common.h> 8*2e192b24SSimon Glass #include <command.h> 9*2e192b24SSimon Glass #include <ansi.h> 10*2e192b24SSimon Glass #include <menu.h> 11*2e192b24SSimon Glass #include <watchdog.h> 12*2e192b24SSimon Glass #include <malloc.h> 13*2e192b24SSimon Glass #include <linux/string.h> 14*2e192b24SSimon Glass 15*2e192b24SSimon Glass /* maximum bootmenu entries */ 16*2e192b24SSimon Glass #define MAX_COUNT 99 17*2e192b24SSimon Glass 18*2e192b24SSimon Glass /* maximal size of bootmenu env 19*2e192b24SSimon Glass * 9 = strlen("bootmenu_") 20*2e192b24SSimon Glass * 2 = strlen(MAX_COUNT) 21*2e192b24SSimon Glass * 1 = NULL term 22*2e192b24SSimon Glass */ 23*2e192b24SSimon Glass #define MAX_ENV_SIZE (9 + 2 + 1) 24*2e192b24SSimon Glass 25*2e192b24SSimon Glass struct bootmenu_entry { 26*2e192b24SSimon Glass unsigned short int num; /* unique number 0 .. MAX_COUNT */ 27*2e192b24SSimon Glass char key[3]; /* key identifier of number */ 28*2e192b24SSimon Glass char *title; /* title of entry */ 29*2e192b24SSimon Glass char *command; /* hush command of entry */ 30*2e192b24SSimon Glass struct bootmenu_data *menu; /* this bootmenu */ 31*2e192b24SSimon Glass struct bootmenu_entry *next; /* next menu entry (num+1) */ 32*2e192b24SSimon Glass }; 33*2e192b24SSimon Glass 34*2e192b24SSimon Glass struct bootmenu_data { 35*2e192b24SSimon Glass int delay; /* delay for autoboot */ 36*2e192b24SSimon Glass int active; /* active menu entry */ 37*2e192b24SSimon Glass int count; /* total count of menu entries */ 38*2e192b24SSimon Glass struct bootmenu_entry *first; /* first menu entry */ 39*2e192b24SSimon Glass }; 40*2e192b24SSimon Glass 41*2e192b24SSimon Glass enum bootmenu_key { 42*2e192b24SSimon Glass KEY_NONE = 0, 43*2e192b24SSimon Glass KEY_UP, 44*2e192b24SSimon Glass KEY_DOWN, 45*2e192b24SSimon Glass KEY_SELECT, 46*2e192b24SSimon Glass }; 47*2e192b24SSimon Glass 48*2e192b24SSimon Glass static char *bootmenu_getoption(unsigned short int n) 49*2e192b24SSimon Glass { 50*2e192b24SSimon Glass char name[MAX_ENV_SIZE]; 51*2e192b24SSimon Glass 52*2e192b24SSimon Glass if (n > MAX_COUNT) 53*2e192b24SSimon Glass return NULL; 54*2e192b24SSimon Glass 55*2e192b24SSimon Glass sprintf(name, "bootmenu_%d", n); 56*2e192b24SSimon Glass return getenv(name); 57*2e192b24SSimon Glass } 58*2e192b24SSimon Glass 59*2e192b24SSimon Glass static void bootmenu_print_entry(void *data) 60*2e192b24SSimon Glass { 61*2e192b24SSimon Glass struct bootmenu_entry *entry = data; 62*2e192b24SSimon Glass int reverse = (entry->menu->active == entry->num); 63*2e192b24SSimon Glass 64*2e192b24SSimon Glass /* 65*2e192b24SSimon Glass * Move cursor to line where the entry will be drown (entry->num) 66*2e192b24SSimon Glass * First 3 lines contain bootmenu header + 1 empty line 67*2e192b24SSimon Glass */ 68*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, entry->num + 4, 1); 69*2e192b24SSimon Glass 70*2e192b24SSimon Glass puts(" "); 71*2e192b24SSimon Glass 72*2e192b24SSimon Glass if (reverse) 73*2e192b24SSimon Glass puts(ANSI_COLOR_REVERSE); 74*2e192b24SSimon Glass 75*2e192b24SSimon Glass puts(entry->title); 76*2e192b24SSimon Glass 77*2e192b24SSimon Glass if (reverse) 78*2e192b24SSimon Glass puts(ANSI_COLOR_RESET); 79*2e192b24SSimon Glass } 80*2e192b24SSimon Glass 81*2e192b24SSimon Glass static void bootmenu_autoboot_loop(struct bootmenu_data *menu, 82*2e192b24SSimon Glass enum bootmenu_key *key, int *esc) 83*2e192b24SSimon Glass { 84*2e192b24SSimon Glass int i, c; 85*2e192b24SSimon Glass 86*2e192b24SSimon Glass if (menu->delay > 0) { 87*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); 88*2e192b24SSimon Glass printf(" Hit any key to stop autoboot: %2d ", menu->delay); 89*2e192b24SSimon Glass } 90*2e192b24SSimon Glass 91*2e192b24SSimon Glass while (menu->delay > 0) { 92*2e192b24SSimon Glass for (i = 0; i < 100; ++i) { 93*2e192b24SSimon Glass if (!tstc()) { 94*2e192b24SSimon Glass WATCHDOG_RESET(); 95*2e192b24SSimon Glass mdelay(10); 96*2e192b24SSimon Glass continue; 97*2e192b24SSimon Glass } 98*2e192b24SSimon Glass 99*2e192b24SSimon Glass menu->delay = -1; 100*2e192b24SSimon Glass c = getc(); 101*2e192b24SSimon Glass 102*2e192b24SSimon Glass switch (c) { 103*2e192b24SSimon Glass case '\e': 104*2e192b24SSimon Glass *esc = 1; 105*2e192b24SSimon Glass *key = KEY_NONE; 106*2e192b24SSimon Glass break; 107*2e192b24SSimon Glass case '\r': 108*2e192b24SSimon Glass *key = KEY_SELECT; 109*2e192b24SSimon Glass break; 110*2e192b24SSimon Glass default: 111*2e192b24SSimon Glass *key = KEY_NONE; 112*2e192b24SSimon Glass break; 113*2e192b24SSimon Glass } 114*2e192b24SSimon Glass 115*2e192b24SSimon Glass break; 116*2e192b24SSimon Glass } 117*2e192b24SSimon Glass 118*2e192b24SSimon Glass if (menu->delay < 0) 119*2e192b24SSimon Glass break; 120*2e192b24SSimon Glass 121*2e192b24SSimon Glass --menu->delay; 122*2e192b24SSimon Glass printf("\b\b\b%2d ", menu->delay); 123*2e192b24SSimon Glass } 124*2e192b24SSimon Glass 125*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); 126*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE); 127*2e192b24SSimon Glass 128*2e192b24SSimon Glass if (menu->delay == 0) 129*2e192b24SSimon Glass *key = KEY_SELECT; 130*2e192b24SSimon Glass } 131*2e192b24SSimon Glass 132*2e192b24SSimon Glass static void bootmenu_loop(struct bootmenu_data *menu, 133*2e192b24SSimon Glass enum bootmenu_key *key, int *esc) 134*2e192b24SSimon Glass { 135*2e192b24SSimon Glass int c; 136*2e192b24SSimon Glass 137*2e192b24SSimon Glass while (!tstc()) { 138*2e192b24SSimon Glass WATCHDOG_RESET(); 139*2e192b24SSimon Glass mdelay(10); 140*2e192b24SSimon Glass } 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass c = getc(); 143*2e192b24SSimon Glass 144*2e192b24SSimon Glass switch (*esc) { 145*2e192b24SSimon Glass case 0: 146*2e192b24SSimon Glass /* First char of ANSI escape sequence '\e' */ 147*2e192b24SSimon Glass if (c == '\e') { 148*2e192b24SSimon Glass *esc = 1; 149*2e192b24SSimon Glass *key = KEY_NONE; 150*2e192b24SSimon Glass } 151*2e192b24SSimon Glass break; 152*2e192b24SSimon Glass case 1: 153*2e192b24SSimon Glass /* Second char of ANSI '[' */ 154*2e192b24SSimon Glass if (c == '[') { 155*2e192b24SSimon Glass *esc = 2; 156*2e192b24SSimon Glass *key = KEY_NONE; 157*2e192b24SSimon Glass } else { 158*2e192b24SSimon Glass *esc = 0; 159*2e192b24SSimon Glass } 160*2e192b24SSimon Glass break; 161*2e192b24SSimon Glass case 2: 162*2e192b24SSimon Glass case 3: 163*2e192b24SSimon Glass /* Third char of ANSI (number '1') - optional */ 164*2e192b24SSimon Glass if (*esc == 2 && c == '1') { 165*2e192b24SSimon Glass *esc = 3; 166*2e192b24SSimon Glass *key = KEY_NONE; 167*2e192b24SSimon Glass break; 168*2e192b24SSimon Glass } 169*2e192b24SSimon Glass 170*2e192b24SSimon Glass *esc = 0; 171*2e192b24SSimon Glass 172*2e192b24SSimon Glass /* ANSI 'A' - key up was pressed */ 173*2e192b24SSimon Glass if (c == 'A') 174*2e192b24SSimon Glass *key = KEY_UP; 175*2e192b24SSimon Glass /* ANSI 'B' - key down was pressed */ 176*2e192b24SSimon Glass else if (c == 'B') 177*2e192b24SSimon Glass *key = KEY_DOWN; 178*2e192b24SSimon Glass /* other key was pressed */ 179*2e192b24SSimon Glass else 180*2e192b24SSimon Glass *key = KEY_NONE; 181*2e192b24SSimon Glass 182*2e192b24SSimon Glass break; 183*2e192b24SSimon Glass } 184*2e192b24SSimon Glass 185*2e192b24SSimon Glass /* enter key was pressed */ 186*2e192b24SSimon Glass if (c == '\r') 187*2e192b24SSimon Glass *key = KEY_SELECT; 188*2e192b24SSimon Glass } 189*2e192b24SSimon Glass 190*2e192b24SSimon Glass static char *bootmenu_choice_entry(void *data) 191*2e192b24SSimon Glass { 192*2e192b24SSimon Glass struct bootmenu_data *menu = data; 193*2e192b24SSimon Glass struct bootmenu_entry *iter; 194*2e192b24SSimon Glass enum bootmenu_key key = KEY_NONE; 195*2e192b24SSimon Glass int esc = 0; 196*2e192b24SSimon Glass int i; 197*2e192b24SSimon Glass 198*2e192b24SSimon Glass while (1) { 199*2e192b24SSimon Glass if (menu->delay >= 0) { 200*2e192b24SSimon Glass /* Autoboot was not stopped */ 201*2e192b24SSimon Glass bootmenu_autoboot_loop(menu, &key, &esc); 202*2e192b24SSimon Glass } else { 203*2e192b24SSimon Glass /* Some key was pressed, so autoboot was stopped */ 204*2e192b24SSimon Glass bootmenu_loop(menu, &key, &esc); 205*2e192b24SSimon Glass } 206*2e192b24SSimon Glass 207*2e192b24SSimon Glass switch (key) { 208*2e192b24SSimon Glass case KEY_UP: 209*2e192b24SSimon Glass if (menu->active > 0) 210*2e192b24SSimon Glass --menu->active; 211*2e192b24SSimon Glass /* no menu key selected, regenerate menu */ 212*2e192b24SSimon Glass return NULL; 213*2e192b24SSimon Glass case KEY_DOWN: 214*2e192b24SSimon Glass if (menu->active < menu->count - 1) 215*2e192b24SSimon Glass ++menu->active; 216*2e192b24SSimon Glass /* no menu key selected, regenerate menu */ 217*2e192b24SSimon Glass return NULL; 218*2e192b24SSimon Glass case KEY_SELECT: 219*2e192b24SSimon Glass iter = menu->first; 220*2e192b24SSimon Glass for (i = 0; i < menu->active; ++i) 221*2e192b24SSimon Glass iter = iter->next; 222*2e192b24SSimon Glass return iter->key; 223*2e192b24SSimon Glass default: 224*2e192b24SSimon Glass break; 225*2e192b24SSimon Glass } 226*2e192b24SSimon Glass } 227*2e192b24SSimon Glass 228*2e192b24SSimon Glass /* never happens */ 229*2e192b24SSimon Glass debug("bootmenu: this should not happen"); 230*2e192b24SSimon Glass return NULL; 231*2e192b24SSimon Glass } 232*2e192b24SSimon Glass 233*2e192b24SSimon Glass static void bootmenu_destroy(struct bootmenu_data *menu) 234*2e192b24SSimon Glass { 235*2e192b24SSimon Glass struct bootmenu_entry *iter = menu->first; 236*2e192b24SSimon Glass struct bootmenu_entry *next; 237*2e192b24SSimon Glass 238*2e192b24SSimon Glass while (iter) { 239*2e192b24SSimon Glass next = iter->next; 240*2e192b24SSimon Glass free(iter->title); 241*2e192b24SSimon Glass free(iter->command); 242*2e192b24SSimon Glass free(iter); 243*2e192b24SSimon Glass iter = next; 244*2e192b24SSimon Glass } 245*2e192b24SSimon Glass free(menu); 246*2e192b24SSimon Glass } 247*2e192b24SSimon Glass 248*2e192b24SSimon Glass static struct bootmenu_data *bootmenu_create(int delay) 249*2e192b24SSimon Glass { 250*2e192b24SSimon Glass unsigned short int i = 0; 251*2e192b24SSimon Glass const char *option; 252*2e192b24SSimon Glass struct bootmenu_data *menu; 253*2e192b24SSimon Glass struct bootmenu_entry *iter = NULL; 254*2e192b24SSimon Glass 255*2e192b24SSimon Glass int len; 256*2e192b24SSimon Glass char *sep; 257*2e192b24SSimon Glass struct bootmenu_entry *entry; 258*2e192b24SSimon Glass 259*2e192b24SSimon Glass menu = malloc(sizeof(struct bootmenu_data)); 260*2e192b24SSimon Glass if (!menu) 261*2e192b24SSimon Glass return NULL; 262*2e192b24SSimon Glass 263*2e192b24SSimon Glass menu->delay = delay; 264*2e192b24SSimon Glass menu->active = 0; 265*2e192b24SSimon Glass menu->first = NULL; 266*2e192b24SSimon Glass 267*2e192b24SSimon Glass while ((option = bootmenu_getoption(i))) { 268*2e192b24SSimon Glass sep = strchr(option, '='); 269*2e192b24SSimon Glass if (!sep) { 270*2e192b24SSimon Glass printf("Invalid bootmenu entry: %s\n", option); 271*2e192b24SSimon Glass break; 272*2e192b24SSimon Glass } 273*2e192b24SSimon Glass 274*2e192b24SSimon Glass entry = malloc(sizeof(struct bootmenu_entry)); 275*2e192b24SSimon Glass if (!entry) 276*2e192b24SSimon Glass goto cleanup; 277*2e192b24SSimon Glass 278*2e192b24SSimon Glass len = sep-option; 279*2e192b24SSimon Glass entry->title = malloc(len + 1); 280*2e192b24SSimon Glass if (!entry->title) { 281*2e192b24SSimon Glass free(entry); 282*2e192b24SSimon Glass goto cleanup; 283*2e192b24SSimon Glass } 284*2e192b24SSimon Glass memcpy(entry->title, option, len); 285*2e192b24SSimon Glass entry->title[len] = 0; 286*2e192b24SSimon Glass 287*2e192b24SSimon Glass len = strlen(sep + 1); 288*2e192b24SSimon Glass entry->command = malloc(len + 1); 289*2e192b24SSimon Glass if (!entry->command) { 290*2e192b24SSimon Glass free(entry->title); 291*2e192b24SSimon Glass free(entry); 292*2e192b24SSimon Glass goto cleanup; 293*2e192b24SSimon Glass } 294*2e192b24SSimon Glass memcpy(entry->command, sep + 1, len); 295*2e192b24SSimon Glass entry->command[len] = 0; 296*2e192b24SSimon Glass 297*2e192b24SSimon Glass sprintf(entry->key, "%d", i); 298*2e192b24SSimon Glass 299*2e192b24SSimon Glass entry->num = i; 300*2e192b24SSimon Glass entry->menu = menu; 301*2e192b24SSimon Glass entry->next = NULL; 302*2e192b24SSimon Glass 303*2e192b24SSimon Glass if (!iter) 304*2e192b24SSimon Glass menu->first = entry; 305*2e192b24SSimon Glass else 306*2e192b24SSimon Glass iter->next = entry; 307*2e192b24SSimon Glass 308*2e192b24SSimon Glass iter = entry; 309*2e192b24SSimon Glass ++i; 310*2e192b24SSimon Glass 311*2e192b24SSimon Glass if (i == MAX_COUNT - 1) 312*2e192b24SSimon Glass break; 313*2e192b24SSimon Glass } 314*2e192b24SSimon Glass 315*2e192b24SSimon Glass /* Add U-Boot console entry at the end */ 316*2e192b24SSimon Glass if (i <= MAX_COUNT - 1) { 317*2e192b24SSimon Glass entry = malloc(sizeof(struct bootmenu_entry)); 318*2e192b24SSimon Glass if (!entry) 319*2e192b24SSimon Glass goto cleanup; 320*2e192b24SSimon Glass 321*2e192b24SSimon Glass entry->title = strdup("U-Boot console"); 322*2e192b24SSimon Glass if (!entry->title) { 323*2e192b24SSimon Glass free(entry); 324*2e192b24SSimon Glass goto cleanup; 325*2e192b24SSimon Glass } 326*2e192b24SSimon Glass 327*2e192b24SSimon Glass entry->command = strdup(""); 328*2e192b24SSimon Glass if (!entry->command) { 329*2e192b24SSimon Glass free(entry->title); 330*2e192b24SSimon Glass free(entry); 331*2e192b24SSimon Glass goto cleanup; 332*2e192b24SSimon Glass } 333*2e192b24SSimon Glass 334*2e192b24SSimon Glass sprintf(entry->key, "%d", i); 335*2e192b24SSimon Glass 336*2e192b24SSimon Glass entry->num = i; 337*2e192b24SSimon Glass entry->menu = menu; 338*2e192b24SSimon Glass entry->next = NULL; 339*2e192b24SSimon Glass 340*2e192b24SSimon Glass if (!iter) 341*2e192b24SSimon Glass menu->first = entry; 342*2e192b24SSimon Glass else 343*2e192b24SSimon Glass iter->next = entry; 344*2e192b24SSimon Glass 345*2e192b24SSimon Glass iter = entry; 346*2e192b24SSimon Glass ++i; 347*2e192b24SSimon Glass } 348*2e192b24SSimon Glass 349*2e192b24SSimon Glass menu->count = i; 350*2e192b24SSimon Glass return menu; 351*2e192b24SSimon Glass 352*2e192b24SSimon Glass cleanup: 353*2e192b24SSimon Glass bootmenu_destroy(menu); 354*2e192b24SSimon Glass return NULL; 355*2e192b24SSimon Glass } 356*2e192b24SSimon Glass 357*2e192b24SSimon Glass static void bootmenu_show(int delay) 358*2e192b24SSimon Glass { 359*2e192b24SSimon Glass int init = 0; 360*2e192b24SSimon Glass void *choice = NULL; 361*2e192b24SSimon Glass char *title = NULL; 362*2e192b24SSimon Glass char *command = NULL; 363*2e192b24SSimon Glass struct menu *menu; 364*2e192b24SSimon Glass struct bootmenu_data *bootmenu; 365*2e192b24SSimon Glass struct bootmenu_entry *iter; 366*2e192b24SSimon Glass char *option, *sep; 367*2e192b24SSimon Glass 368*2e192b24SSimon Glass /* If delay is 0 do not create menu, just run first entry */ 369*2e192b24SSimon Glass if (delay == 0) { 370*2e192b24SSimon Glass option = bootmenu_getoption(0); 371*2e192b24SSimon Glass if (!option) { 372*2e192b24SSimon Glass puts("bootmenu option 0 was not found\n"); 373*2e192b24SSimon Glass return; 374*2e192b24SSimon Glass } 375*2e192b24SSimon Glass sep = strchr(option, '='); 376*2e192b24SSimon Glass if (!sep) { 377*2e192b24SSimon Glass puts("bootmenu option 0 is invalid\n"); 378*2e192b24SSimon Glass return; 379*2e192b24SSimon Glass } 380*2e192b24SSimon Glass run_command(sep+1, 0); 381*2e192b24SSimon Glass return; 382*2e192b24SSimon Glass } 383*2e192b24SSimon Glass 384*2e192b24SSimon Glass bootmenu = bootmenu_create(delay); 385*2e192b24SSimon Glass if (!bootmenu) 386*2e192b24SSimon Glass return; 387*2e192b24SSimon Glass 388*2e192b24SSimon Glass menu = menu_create(NULL, bootmenu->delay, 1, bootmenu_print_entry, 389*2e192b24SSimon Glass bootmenu_choice_entry, bootmenu); 390*2e192b24SSimon Glass if (!menu) { 391*2e192b24SSimon Glass bootmenu_destroy(bootmenu); 392*2e192b24SSimon Glass return; 393*2e192b24SSimon Glass } 394*2e192b24SSimon Glass 395*2e192b24SSimon Glass for (iter = bootmenu->first; iter; iter = iter->next) { 396*2e192b24SSimon Glass if (!menu_item_add(menu, iter->key, iter)) 397*2e192b24SSimon Glass goto cleanup; 398*2e192b24SSimon Glass } 399*2e192b24SSimon Glass 400*2e192b24SSimon Glass /* Default menu entry is always first */ 401*2e192b24SSimon Glass menu_default_set(menu, "0"); 402*2e192b24SSimon Glass 403*2e192b24SSimon Glass puts(ANSI_CURSOR_HIDE); 404*2e192b24SSimon Glass puts(ANSI_CLEAR_CONSOLE); 405*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, 1, 1); 406*2e192b24SSimon Glass 407*2e192b24SSimon Glass init = 1; 408*2e192b24SSimon Glass 409*2e192b24SSimon Glass if (menu_get_choice(menu, &choice)) { 410*2e192b24SSimon Glass iter = choice; 411*2e192b24SSimon Glass title = strdup(iter->title); 412*2e192b24SSimon Glass command = strdup(iter->command); 413*2e192b24SSimon Glass } 414*2e192b24SSimon Glass 415*2e192b24SSimon Glass cleanup: 416*2e192b24SSimon Glass menu_destroy(menu); 417*2e192b24SSimon Glass bootmenu_destroy(bootmenu); 418*2e192b24SSimon Glass 419*2e192b24SSimon Glass if (init) { 420*2e192b24SSimon Glass puts(ANSI_CURSOR_SHOW); 421*2e192b24SSimon Glass puts(ANSI_CLEAR_CONSOLE); 422*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, 1, 1); 423*2e192b24SSimon Glass } 424*2e192b24SSimon Glass 425*2e192b24SSimon Glass if (title && command) { 426*2e192b24SSimon Glass debug("Starting entry '%s'\n", title); 427*2e192b24SSimon Glass free(title); 428*2e192b24SSimon Glass run_command(command, 0); 429*2e192b24SSimon Glass free(command); 430*2e192b24SSimon Glass } 431*2e192b24SSimon Glass 432*2e192b24SSimon Glass #ifdef CONFIG_POSTBOOTMENU 433*2e192b24SSimon Glass run_command(CONFIG_POSTBOOTMENU, 0); 434*2e192b24SSimon Glass #endif 435*2e192b24SSimon Glass } 436*2e192b24SSimon Glass 437*2e192b24SSimon Glass void menu_display_statusline(struct menu *m) 438*2e192b24SSimon Glass { 439*2e192b24SSimon Glass struct bootmenu_entry *entry; 440*2e192b24SSimon Glass struct bootmenu_data *menu; 441*2e192b24SSimon Glass 442*2e192b24SSimon Glass if (menu_default_choice(m, (void *)&entry) < 0) 443*2e192b24SSimon Glass return; 444*2e192b24SSimon Glass 445*2e192b24SSimon Glass menu = entry->menu; 446*2e192b24SSimon Glass 447*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, 1, 1); 448*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE); 449*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, 2, 1); 450*2e192b24SSimon Glass puts(" *** U-Boot Boot Menu ***"); 451*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE_TO_END); 452*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, 3, 1); 453*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE); 454*2e192b24SSimon Glass 455*2e192b24SSimon Glass /* First 3 lines are bootmenu header + 2 empty lines between entries */ 456*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); 457*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE); 458*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, menu->count + 6, 1); 459*2e192b24SSimon Glass puts(" Press UP/DOWN to move, ENTER to select"); 460*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE_TO_END); 461*2e192b24SSimon Glass printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); 462*2e192b24SSimon Glass puts(ANSI_CLEAR_LINE); 463*2e192b24SSimon Glass } 464*2e192b24SSimon Glass 465*2e192b24SSimon Glass #ifdef CONFIG_MENU_SHOW 466*2e192b24SSimon Glass int menu_show(int bootdelay) 467*2e192b24SSimon Glass { 468*2e192b24SSimon Glass bootmenu_show(bootdelay); 469*2e192b24SSimon Glass return -1; /* -1 - abort boot and run monitor code */ 470*2e192b24SSimon Glass } 471*2e192b24SSimon Glass #endif 472*2e192b24SSimon Glass 473*2e192b24SSimon Glass int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 474*2e192b24SSimon Glass { 475*2e192b24SSimon Glass char *delay_str = NULL; 476*2e192b24SSimon Glass int delay = 10; 477*2e192b24SSimon Glass 478*2e192b24SSimon Glass #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 479*2e192b24SSimon Glass delay = CONFIG_BOOTDELAY; 480*2e192b24SSimon Glass #endif 481*2e192b24SSimon Glass 482*2e192b24SSimon Glass if (argc >= 2) 483*2e192b24SSimon Glass delay_str = argv[1]; 484*2e192b24SSimon Glass 485*2e192b24SSimon Glass if (!delay_str) 486*2e192b24SSimon Glass delay_str = getenv("bootmenu_delay"); 487*2e192b24SSimon Glass 488*2e192b24SSimon Glass if (delay_str) 489*2e192b24SSimon Glass delay = (int)simple_strtol(delay_str, NULL, 10); 490*2e192b24SSimon Glass 491*2e192b24SSimon Glass bootmenu_show(delay); 492*2e192b24SSimon Glass return 0; 493*2e192b24SSimon Glass } 494*2e192b24SSimon Glass 495*2e192b24SSimon Glass U_BOOT_CMD( 496*2e192b24SSimon Glass bootmenu, 2, 1, do_bootmenu, 497*2e192b24SSimon Glass "ANSI terminal bootmenu", 498*2e192b24SSimon Glass "[delay]\n" 499*2e192b24SSimon Glass " - show ANSI terminal bootmenu with autoboot delay" 500*2e192b24SSimon Glass ); 501