On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami <suriya...@gmail.com> wrote: > Initialize usb and ide. > Scan through the usb for storage and boot capable partitions. > Scan through the ide interface for boot capable partitions. > Present such bootable options to the user to choose to boot from > If the user does not choose any choose the default option > the default option is the option chosen by the user the last time > If no such default option exists, boot from the first possible > bootable option.
This all sounds very generic but... > > Signed-off-by: Suriyan Ramasami <suriya...@gmail.com> > --- > Changes in v2: > - Coding style changes > > board/Seagate/goflexhome/goflexhomemenu.c | 415 > +++++++++++++++++++++++++++++ but this is not a generic location. This feature would interest me and probably Stephen as well. Rob > 1 files changed, 415 insertions(+), 0 deletions(-) > create mode 100644 board/Seagate/goflexhome/goflexhomemenu.c > > diff --git a/board/Seagate/goflexhome/goflexhomemenu.c > b/board/Seagate/goflexhome/goflexhomemenu.c > new file mode 100644 > index 0000000..6169cf8 > --- /dev/null > +++ b/board/Seagate/goflexhome/goflexhomemenu.c > @@ -0,0 +1,415 @@ > +/* > + * Copyright (C) 2013 Suriyan Ramasami <suriya...@gmail.com> > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > + * MA 02110-1301 USA > + */ > + > +#include <common.h> > + > +#if defined(CONFIG_MENU) > +/* Menu related code begins here */ > + > +/* Added to use the various usb/fat/ext4fs interfaces */ > +#include <usb.h> > +#include <ext4fs.h> > +#include <menu.h> > + > +#define MENU_MAX_DEVICES 10 > +#define MENU_MAX_PARTITIONS 10 > +#define MENU_MAX_BOOTABLES 10 > + > +#define MENU_EXIT 1 > +#define MENU_SHOW 2 > + > +#define MENU_DEFAULT_BOOTARGS \ > + "setenv bootargs ${console} ubi.mtd=2,2048 " \ > + "root=ubi0:root rootfstype=ubifs debug" > + > +#define MENU_DEFAULT_BOOTCMD \ > + "setenv bootcmd nand read.e 0x800000 0x100000 0x600000" > + > +#define MENU_PROMPT_BOOTCMD \ > + "setenv bootcmd echo Dropping you to u-boot" > + > +#define MENU_CHOSEN_BOOTARGS \ > + "setenv bootargs $console rootdelay=10 root=${menu_root} debug" > + > +#define MENU_OPTIONS_HEADER \ > + "Bootables:\nChoice\tIntface\tDrive\tDevice\tPart\tFS\tFileName\n" \ > + "---------------------------------------------------------------" > + > +#define MENU_DEFAULT_NOBOOTABLES \ > + "* Last boot options (None, and no bootables found!" > + > +struct menu_bootables { > + char interface[5]; > + char drive; > + int device; > + int partition; > + char filename[64]; > + char fstype; /* f => fat, e => ext2/4 0 => invalid */ > +}; > + > +static void goflexhome_menuprint(void *print_buffer) > +{ > + printf("%s\n", (char *)print_buffer); > +} > + > +/* > + * We shall use menu_<> variables to capture the state of past menu > + * choices. > + * menu_bootargs corresponds to bootargs > + * menu_bootcmd corresponds to bootcmd > + * menu_choice corresponds to the last choice that was picked > + * menu_choice will be NULL the first time and also > + * if a choice was never made. In that case we should pick > + * to boot from the 1st bootable option if present. > +*/ > +static int goflexhome_evaluate_env(void) > +{ > +char *s; > + > + run_command("run menu_bootargs", 0); > + s = getenv("bootargs"); > + printf("bootargs is %s\n", s); > + run_command("run menu_bootcmd", 0); > + s = getenv("bootcmd"); > + printf("bootcmd is %s\n", s); > + if (run_command("run bootcmd", 0) != 0) { > + /* We failed to boot, present the menu */ > + return MENU_SHOW; > + } > + if (strncmp(s, "echo", 4) == 0) { > + /* User wants the u-boot prmpt */ > + return MENU_EXIT; > + } > + run_command("bootm", 0); > + > + /* We are here, we failed to boot */ > + return MENU_SHOW; > +} > + > +static int goflexhome_handle_choice(struct menu_bootables menu_bootlist[], > + char *choice) > +{ > +char *s, *last_menu_choice; > +char menu_command[128]; > +char load_command[16]; > +int index; > +int call_saveenv; > + > + call_saveenv = 0; > + if (choice == NULL) { > + /* Exit menu and let it do its auto boot */ > + return MENU_EXIT; > + } > + printf("\nYou chose: %s\n", choice); > + > + last_menu_choice = getenv("menu_choice"); > + if (last_menu_choice == NULL) { > + /* User has not yet chosen before */ > + /* Lets default to boot from nand */ > + setenv("menu_bootargs", MENU_DEFAULT_BOOTARGS); > + setenv("menu_bootcmd", MENU_DEFAULT_BOOTCMD); > + call_saveenv = 1; > + } > + if (choice[0] == '*') { > + /* User wants same thing that was chosen the last time */ > + return MENU_EXIT; > + } > + if (last_menu_choice && strcmp(choice, last_menu_choice) != 0) { > + /* Save the choice chosen */ > + setenv("menu_choice", choice); > + call_saveenv = 1; > + } > + if (choice[0] == '+') { > + /* User wants u-boot prompt */ > + s = getenv("menu_bootcmd"); > + if (strcmp(s, MENU_PROMPT_BOOTCMD) != 0) { > + setenv("menu_bootcmd", MENU_PROMPT_BOOTCMD); > + saveenv(); > + } > + return MENU_EXIT; > + } > + > + /* Steps to set the env variables to the chosen values */ > + index = simple_strtoul(choice, NULL, 10); > + sprintf(menu_command, "/dev/sd%c%d", menu_bootlist[index].drive, > + menu_bootlist[index].partition); > + s = getenv("menu_root"); > + if (strcmp(s, menu_command) != 0) { > + setenv("menu_root", menu_command); > + call_saveenv = 1; > + } > + s = getenv("menu_bootargs"); > + if (strcmp(s, MENU_CHOSEN_BOOTARGS) != 0) { > + setenv("menu_bootargs", MENU_CHOSEN_BOOTARGS); > + call_saveenv = 1; > + } > + switch (menu_bootlist[index].fstype) { > + case 'e': > + strcpy(load_command, "ext4load"); > + break; > + default: > + return MENU_EXIT; > + } > + > + /* Lets try to load and check the image */ > + sprintf(menu_command, "%s %s %d:%d %x %s", > + load_command, > + menu_bootlist[index].interface, > + menu_bootlist[index].device, > + menu_bootlist[index].partition, > + CONFIG_SYS_LOAD_ADDR, > + menu_bootlist[index].filename); > + if (run_command(menu_command, 0) != 0) { > + /* Could not load image */ > + printf("Selected image could not be loaded ...\n"); > + return MENU_SHOW; > + } > + sprintf(menu_command, "iminfo %x", CONFIG_SYS_LOAD_ADDR); > + if (run_command(menu_command, 0) != 0) { > + /* The image is not a valid image */ > + printf("Selected image is not valid ...\n"); > + return MENU_SHOW; > + } > + > + sprintf(menu_command, "setenv bootcmd %s %s %d:%d %x %s", > + load_command, > + menu_bootlist[index].interface, > + menu_bootlist[index].device, > + menu_bootlist[index].partition, > + CONFIG_SYS_LOAD_ADDR, > + menu_bootlist[index].filename); > + s = getenv("menu_bootcmd"); > + if (strcmp(s, menu_command) != 0) { > + setenv("menu_bootcmd", menu_command); > + call_saveenv = 1; > + } > + if (call_saveenv) > + saveenv(); > + return MENU_EXIT; > +} > + > +static int goflexhome_menu(struct menu_bootables menu_bootlist[], int > bootdelay) > +{ > +int index; > +struct menu *m; > +char menu_key[MENU_MAX_BOOTABLES][5]; > +char menu_entry[MENU_MAX_BOOTABLES][64]; > +char *menu_choice; > +char *last_menu_choice; > +char choice_menu_entry[64]; > +char choice_menu[3]; > + > + m = menu_create(MENU_OPTIONS_HEADER, 60, 1, goflexhome_menuprint, > + NULL, NULL); > + for (index = 0; index < MENU_MAX_BOOTABLES; index++) { > + if (menu_bootlist[index].fstype == '0') > + break; > + snprintf(menu_key[index], sizeof(menu_key[index]), "%d", > index); > + snprintf(menu_entry[index], sizeof(menu_entry[index]), > + "%d\t%s\t%c\t%d\t%d\t%c\t%s", index, > + menu_bootlist[index].interface, > + menu_bootlist[index].drive, > + menu_bootlist[index].device, > + menu_bootlist[index].partition, > + menu_bootlist[index].fstype, > + menu_bootlist[index].filename); > + if (menu_item_add(m, menu_key[index], menu_entry[index]) != > 1) { > + menu_destroy(m); > + return MENU_EXIT; > + } > + } > + > + /* Prep for what should be the default menu choice */ > + /* If chosen before, choose the last boot options */ > + /* If nothing chosen yet, then choose the first bootable option */ > + /* If nothing chosen yet, and no first bootable option, then boot */ > + /* from nand */ > + last_menu_choice = getenv("menu_choice"); > + sprintf(choice_menu, "*"); > + if (last_menu_choice) { > + sprintf(choice_menu_entry, "* Last boot options (%s)", > + last_menu_choice); > + } else { > + /* There was no last boot option */ > + /* If there is at least 1 boot entry, make that the default */ > + if (menu_bootlist[0].fstype != '0') { > + setenv("menu_choice", menu_entry[0]); > + sprintf(choice_menu_entry, menu_entry[0]); > + } else { > + sprintf(choice_menu_entry, MENU_DEFAULT_NOBOOTABLES); > + } > + } > + if (menu_item_add(m, choice_menu, choice_menu_entry) != 1) { > + menu_destroy(m); > + return MENU_EXIT; > + } > + /* Mark this as the default choice. */ > + menu_default_set(m, "*"); > + if (menu_item_add(m, "+", "+ UBoot prompt") != 1) { > + menu_destroy(m); > + return MENU_EXIT; > + } > + > + menu_get_choice(m, (void **)&menu_choice); > + return goflexhome_handle_choice(menu_bootlist, menu_choice); > +} > + > +static void goflexhome_filesearch(struct menu_bootables menu_bootlist[], > + int *bootindex) { > +char *filenames[] = { "/uImage", "/boot/uImage", "" }; > +int index; > + > + index = 0; > + while (filenames[index][0] != '\0') { > + switch (menu_bootlist[*bootindex].fstype) { > + case 'e': > + if (ext4fs_open(filenames[index]) == -1) { > + index++; > + continue; > + } > + break; > + > + default: > + break; > + } > + > + /* Got a hit, record it */ > + strcpy(menu_bootlist[*bootindex].filename, filenames[index]); > + index++; > + (*bootindex)++; > + if (*bootindex >= MENU_MAX_BOOTABLES) > + break; > + /* Prep next bootlist structure */ > + memcpy(&menu_bootlist[*bootindex], > + &menu_bootlist[*bootindex - 1], > + sizeof(struct menu_bootables)); > + } > +} > + > +static void goflexhome_populate_partitions(struct menu_bootables > *menu_bootlist, > + block_dev_desc_t *dev_desc, > + int *bootindex) > +{ > +int part; > +disk_partition_t disk_part; > + > + part = menu_bootlist[*bootindex].partition; > + > + /* Get the partition structure */ > + if (get_partition_info(dev_desc, part, &disk_part)) > + return; > + > + /* Try to check if its extX */ > + if (ext4fs_probe(dev_desc, &disk_part) == 0) { > + menu_bootlist[*bootindex].fstype = 'e'; > + goflexhome_filesearch(menu_bootlist, bootindex); > + ext4fs_close(); > + return; > + } > +} > + > +static void goflexhome_populate_devices(struct menu_bootables > menu_bootlist[], > + int *bootindex) > +{ > +block_dev_desc_t *dev_desc; > +int device; > +int part; > + > + /* Populate bootlist from each device and the partitions within */ > + for (device = 0; device < MENU_MAX_DEVICES; device++) { > + dev_desc = get_dev(menu_bootlist[*bootindex].interface, > device); > + if (dev_desc == NULL) > + continue; > + menu_bootlist[*bootindex].device = device; > + for (part = 0; part < MENU_MAX_PARTITIONS; part++) { > + menu_bootlist[*bootindex].partition = part; > + goflexhome_populate_partitions(menu_bootlist, > dev_desc, > + bootindex); > + } > + } > +} > + > +/* menu_bootlist[] can hold a max of MENU_MAX_BOOTABLES entries */ > +static void goflexhome_populate_bootlist(struct menu_bootables > menu_bootlist[]) > +{ > +/* ide is always first */ > +char *interfaces[] = { "ide", "usb", "" }; > +int bootindex; > +int i; > + > + bootindex = 0; > + i = 0; > + /* Lets initialize the usb sub system */ > + usb_init(); > + usb_stor_scan(0); > + > + /* This scans the partitions in the IDE storage */ > + ide_init(); > + > + /* Populate bootlist from each interface */ > + while ((interfaces[i][0] != '\0') && > + (bootindex < MENU_MAX_BOOTABLES)) { > + strcpy(menu_bootlist[bootindex].interface, interfaces[i]); > + goflexhome_populate_devices(menu_bootlist, &bootindex); > + i++; > + } > + if (bootindex < MENU_MAX_BOOTABLES) { > + /* End marker of list */ > + menu_bootlist[bootindex].fstype = '0'; > + } > + > + /* Lets set the drive letter */ > + menu_bootlist[0].drive = 'a'; > + for (i = 1; i < bootindex; i++) { > + if (menu_bootlist[i].fstype == '0') > + break; > + /* Increase drive letter when interface changes */ > + /* Or when device numbers change for same interface */ > + menu_bootlist[i].drive = menu_bootlist[i - 1].drive; > + if (strcmp(menu_bootlist[i].interface, > + menu_bootlist[i - 1].interface) != 0) { > + menu_bootlist[i].drive++; > + } else { > + if (menu_bootlist[i].device > > + menu_bootlist[i - 1].device) { > + menu_bootlist[i].drive++; > + } > + } > + } > +} > + > +int menu_show(int bootdelay) > +{ > +struct menu_bootables menu_bootlist[MENU_MAX_BOOTABLES]; > +int retval; > + > + goflexhome_populate_bootlist(menu_bootlist); > + do { > + retval = goflexhome_menu(menu_bootlist, bootdelay); > + if (retval == MENU_EXIT) > + retval = goflexhome_evaluate_env(); > + } while (retval == MENU_SHOW); > + > + return 0; > +} > + > +#endif /* CONFIG_MENU */ > -- > 1.7.1 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot