Give the user a choosable menu of probable bootables to boot from.

Signed-off-by: Suriyan Ramasami <suriya...@gmail.com>
---
 board/Seagate/goflexhome/goflexhomemenu.c |  381 +++++++++++++++++++++++++++++
 1 files changed, 381 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..8866da6
--- /dev/null
+++ b/board/Seagate/goflexhome/goflexhomemenu.c
@@ -0,0 +1,381 @@
+/*
+ * 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
+
+typedef struct menu_bootables {
+       char    interface[5];
+       char    drive;
+       int     device;
+       int     partition;
+       char    filename[64];
+       char    fstype;         /* f => fat, e => ext2/4 0 => invalid */
+} menu_bootables_t;
+
+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(menu_bootables_t menu_bootlist[], char 
*choice)
+{
+char *s, *last_menu_choice;
+char menu_command[128];
+char load_command[16];
+int index;
+int 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", "setenv bootargs ${console} 
ubi.mtd=2,2048 root=ubi0:root rootfstype=ubifs debug");
+               setenv("menu_bootcmd", "setenv bootcmd nand read.e 0x800000 
0x100000 0x600000");
+               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, "setenv bootcmd echo Dropping you to u-boot 
prompt") !=  0) {
+                       setenv("menu_bootcmd", "setenv bootcmd echo Dropping 
you to u-boot prompt");
+                       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, "setenv bootargs $console rootdelay=10 root=${menu_root} 
debug") != 0) {
+               setenv("menu_bootargs", "setenv bootargs ${console} 
rootdelay=10 root=${menu_root} debug");
+               call_saveenv = 1;
+       }
+       switch (menu_bootlist[index].fstype) {
+       case 'e':
+               strcpy(load_command, "ext4load");
+               break;
+       case 'f':
+               strcpy(load_command, "fatload");
+               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(menu_bootables_t 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("Bootables:\nChoice\tIntface\tDrive\tDevice\tPart\tFS\tFileName\n---------------------------------------------------------------",
 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, "* Last boot options (None, 
and no bootables found!)");
+               }
+       }
+       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(menu_bootables_t menu_bootlist[], int 
*bootindex) {
+char *filenames[] = { "/uImage", "/boot/uImage", "" };
+int 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(menu_bootables_t));
+       }
+}
+
+static void goflexhome_populate_partitions(menu_bootables_t 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(menu_bootables_t 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(menu_bootables_t menu_bootlist[])
+{
+/* ide is always first */
+char *interfaces[] = { "ide", "usb", "" };
+int bootindex = 0;
+int 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)
+{
+menu_bootables_t menu_bootlist[MENU_MAX_BOOTABLES];
+int retval;
+
+#if 0
+       set_default_env();
+       saveenv();
+#endif
+
+        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

Reply via email to