From patchwork Mon Apr 8 03:44:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suriyan Ramasami X-Patchwork-Id: 234570 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id A8F1C2C00C6 for ; Mon, 8 Apr 2013 14:23:44 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5D2874A31B; Mon, 8 Apr 2013 06:22:22 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id X7PrOEeUa2I8; Mon, 8 Apr 2013 06:22:22 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 11D3F4A2BB; Mon, 8 Apr 2013 06:21:06 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EE5814A24B for ; Mon, 8 Apr 2013 05:53:05 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id edyu2wQhR7IM for ; Mon, 8 Apr 2013 05:53:05 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ia0-f173.google.com (mail-ia0-f173.google.com [209.85.210.173]) by theia.denx.de (Postfix) with ESMTPS id 13DB74A21E for ; Mon, 8 Apr 2013 05:53:00 +0200 (CEST) Received: by mail-ia0-f173.google.com with SMTP id h37so4817769iak.4 for ; Sun, 07 Apr 2013 20:52:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=VALZ7/Cjnl2HFLap2CJkj+DTymz6B4vDpBRiTq7OFuM=; b=aIkWlDZozYD/gnNyWk8JnhIW9t+4oxgVPQeDbajzPK8fsw7rvYLkpU4soEkAx294cI rzVpsDbe2t0D4oxZ3zg4eBo2XwTrwOkHKJ31UR0tflkmHu36zYE+CimUGvqNFaChGlf6 e9hY8du+LnmZ94H0yX4/8EeII7WXXBKB4DVw5s7P85Gb2+CB1gp9feCaK3kz1ac66aRL 7XoDxcxXfFyXL5p/pQ0JnlCsYKY47IlmB+OehtBgrprQovcvbzM6Z9s59Z3PGf3/nkLX K6/WIfxmsFdCbFaXwEgma6GbczkR8iC4JE+/HZgJMf5j7ReRj2m1U6P7KkkU8asi7E8g AiPg== X-Received: by 10.50.136.167 with SMTP id qb7mr5468701igb.98.1365392744292; Sun, 07 Apr 2013 20:45:44 -0700 (PDT) Received: from localhost.localdomain (75-101-50-252.dsl.static.sonic.net. [75.101.50.252]) by mx.google.com with ESMTPS id qn10sm14599495igc.6.2013.04.07.20.45.43 (version=TLSv1 cipher=RC4-SHA bits=128/128); Sun, 07 Apr 2013 20:45:43 -0700 (PDT) From: Suriyan Ramasami To: u-boot@lists.denx.de Date: Sun, 7 Apr 2013 20:44:50 -0700 Message-Id: <1365392690-8668-9-git-send-email-suriyan.r@gmail.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1365392690-8668-1-git-send-email-suriyan.r@gmail.com> References: <1365392690-8668-1-git-send-email-suriyan.r@gmail.com> X-Mailman-Approved-At: Mon, 08 Apr 2013 06:20:55 +0200 Cc: ecc@cmu.edu Subject: [U-Boot] [PATCH 8/8] ARM: Add Seagate GoFlexHome support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Give the user a choosable menu of probable bootables to boot from. Signed-off-by: Suriyan Ramasami --- 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 + * + * 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 + +#if defined(CONFIG_MENU) +/* Menu related code begins here */ + +/* Added to use the various usb/fat/ext4fs interfaces */ +#include +#include +#include + +#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 */