Patchwork [U-Boot,v2,8/8] ARM: Present a menu of bootable options on boot

login
register
mail settings
Submitter Suriyan Ramasami
Date April 10, 2013, 1:12 p.m.
Message ID <1365599537-14138-9-git-send-email-suriyan.r@gmail.com>
Download mbox | patch
Permalink /patch/235392/
State Superseded
Headers show

Comments

Suriyan Ramasami - April 10, 2013, 1:12 p.m.
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.

Signed-off-by: Suriyan Ramasami <suriyan.r@gmail.com>
---
Changes in v2:
	- Coding style changes

 board/Seagate/goflexhome/goflexhomemenu.c |  415 +++++++++++++++++++++++++++++
 1 files changed, 415 insertions(+), 0 deletions(-)
 create mode 100644 board/Seagate/goflexhome/goflexhomemenu.c
Rob Herring - April 11, 2013, 1:43 a.m.
On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami <suriyan.r@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 <suriyan.r@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 <suriyan.r@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
Suriyan Ramasami - April 11, 2013, 4:27 a.m.
I shall probably move it to a generic location with a more generic name.
Any reocmmendations?

- Suriyan


On Wed, Apr 10, 2013 at 6:43 PM, Rob Herring <robherring2@gmail.com> wrote:

> On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami <suriyan.r@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 <suriyan.r@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 <suriyan.r@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
>
Mike Dunn - April 11, 2013, 1:02 p.m.
On 04/10/2013 06:43 PM, Rob Herring wrote:
> On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami <suriyan.r@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 <suriyan.r@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.


I was thinking along these lines as well for the treo 680.  Suriyan, perhaps we
can collaborate, with the guidance of the maintainers here.

Mike
Suriyan Ramasami - April 11, 2013, 7:51 p.m.
Sounds good to me.

I shall attempt a generic version and call it cmd_bootscan.c in the common
directory.

- Suriyan


On Thu, Apr 11, 2013 at 6:02 AM, Mike Dunn <mikedunn@newsguy.com> wrote:

> On 04/10/2013 06:43 PM, Rob Herring wrote:
> > On Wed, Apr 10, 2013 at 8:12 AM, Suriyan Ramasami <suriyan.r@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 <suriyan.r@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.
>
>
> I was thinking along these lines as well for the treo 680.  Suriyan,
> perhaps we
> can collaborate, with the guidance of the maintainers here.
>
> Mike
>
Tom Rini - April 12, 2013, 1:56 p.m.
On Thu, Apr 11, 2013 at 12:51:03PM -0700, Suriyan Ramasami wrote:

> Sounds good to me.
> 
> I shall attempt a generic version and call it cmd_bootscan.c in the common
> directory.

A good first pass.  Please keep board/ait/cam_enc_4xx/cam_enc_4xx.c in
mind as that has a similar set of things going on.  Thanks!

Patch

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 <suriyan.r@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 */