| /* |
| * (C) Copyright 2007 Schindler Lift Inc. |
| * (C) Copyright 2007 DENX Software Engineering |
| * |
| * Author: Michel Marti <mma@objectxp.com> |
| * Adapted for U-Boot 1.2 by Piotr Kruszynski <ppk@semihalf.com>: |
| * - code clean-up |
| * - bugfix for overwriting bootargs by user |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <common.h> |
| #include <command.h> |
| #include <malloc.h> |
| #include <image.h> |
| #include <usb.h> |
| #include <fat.h> |
| |
| #include "fwupdate.h" |
| |
| extern int do_bootm(cmd_tbl_t *, int, int, char *[]); |
| extern long do_fat_read(const char *, void *, unsigned long, int); |
| extern int do_fat_fsload(cmd_tbl_t *, int, int, char *[]); |
| |
| static int load_rescue_image(ulong); |
| |
| void cm5200_fwupdate(void) |
| { |
| cmd_tbl_t *bcmd; |
| char *rsargs; |
| char *tmp = NULL; |
| char ka[16]; |
| char *argv[3] = { "bootm", ka, NULL }; |
| |
| /* Check if rescue system is disabled... */ |
| if (getenv("norescue")) { |
| printf(LOG_PREFIX "Rescue System disabled.\n"); |
| return; |
| } |
| |
| /* Check if we have a USB storage device and load image */ |
| if (load_rescue_image(LOAD_ADDR)) |
| return; |
| |
| bcmd = find_cmd("bootm"); |
| if (!bcmd) |
| return; |
| |
| sprintf(ka, "%lx", LOAD_ADDR); |
| |
| /* prepare our bootargs */ |
| rsargs = getenv("rs-args"); |
| if (!rsargs) |
| rsargs = RS_BOOTARGS; |
| else { |
| tmp = malloc(strlen(rsargs+1)); |
| if (!tmp) { |
| printf(LOG_PREFIX "Memory allocation failed\n"); |
| return; |
| } |
| strcpy(tmp, rsargs); |
| rsargs = tmp; |
| } |
| |
| setenv("bootargs", rsargs); |
| |
| if (rsargs == tmp) |
| free(rsargs); |
| |
| printf(LOG_PREFIX "Starting update system (bootargs=%s)...\n", rsargs); |
| do_bootm(bcmd, 0, 2, argv); |
| } |
| |
| static int load_rescue_image(ulong addr) |
| { |
| disk_partition_t info; |
| int devno; |
| int partno; |
| int i; |
| char fwdir[64]; |
| char nxri[128]; |
| char *tmp; |
| char dev[7]; |
| char addr_str[16]; |
| char *argv[6] = { "fatload", "usb", dev, addr_str, nxri, NULL }; |
| block_dev_desc_t *stor_dev = NULL; |
| cmd_tbl_t *bcmd; |
| |
| /* Get name of firmware directory */ |
| tmp = getenv("fw-dir"); |
| |
| /* Copy it into fwdir */ |
| strncpy(fwdir, tmp ? tmp : FW_DIR, sizeof(fwdir)); |
| fwdir[sizeof(fwdir) - 1] = 0; /* Terminate string */ |
| |
| printf(LOG_PREFIX "Checking for firmware image directory '%s' on USB" |
| " storage...\n", fwdir); |
| usb_stop(); |
| if (usb_init() != 0) |
| return 1; |
| |
| /* Check for storage device */ |
| if (usb_stor_scan(1) != 0) { |
| usb_stop(); |
| return 1; |
| } |
| |
| /* Detect storage device */ |
| for (devno = 0; devno < USB_MAX_STOR_DEV; devno++) { |
| stor_dev = usb_stor_get_dev(devno); |
| if (stor_dev->type != DEV_TYPE_UNKNOWN) |
| break; |
| } |
| if (!stor_dev || stor_dev->type == DEV_TYPE_UNKNOWN) { |
| printf(LOG_PREFIX "No valid storage device found...\n"); |
| usb_stop(); |
| return 1; |
| } |
| |
| /* Detect partition */ |
| for (partno = -1, i = 0; i < 6; i++) { |
| if (get_partition_info(stor_dev, i, &info) == 0) { |
| if (fat_register_device(stor_dev, i) == 0) { |
| /* Check if rescue image is present */ |
| FW_DEBUG("Looking for firmware directory '%s'" |
| " on partition %d\n", fwdir, i); |
| if (do_fat_read(fwdir, NULL, 0, LS_NO) == -1) { |
| FW_DEBUG("No NX rescue image on " |
| "partition %d.\n", i); |
| partno = -2; |
| } else { |
| partno = i; |
| FW_DEBUG("Partition %d contains " |
| "firmware directory\n", partno); |
| break; |
| } |
| } |
| } |
| } |
| |
| if (partno < 0) { |
| switch (partno) { |
| case -1: |
| printf(LOG_PREFIX "Error: No valid (FAT) partition " |
| "detected\n"); |
| break; |
| case -2: |
| printf(LOG_PREFIX "Error: No NX rescue image on FAT " |
| "partition\n"); |
| break; |
| default: |
| printf(LOG_PREFIX "Error: Failed with code %d\n", |
| partno); |
| } |
| usb_stop(); |
| return 1; |
| } |
| |
| /* Load the rescue image */ |
| bcmd = find_cmd("fatload"); |
| if (!bcmd) { |
| printf(LOG_PREFIX "Error - 'fatload' command not present.\n"); |
| usb_stop(); |
| return 1; |
| } |
| |
| tmp = getenv("nx-rescue-image"); |
| sprintf(nxri, "%s/%s", fwdir, tmp ? tmp : RESCUE_IMAGE); |
| sprintf(dev, "%d:%d", devno, partno); |
| sprintf(addr_str, "%lx", addr); |
| |
| FW_DEBUG("fat_fsload device='%s', addr='%s', file: %s\n", |
| dev, addr_str, nxri); |
| |
| if (do_fat_fsload(bcmd, 0, 5, argv) != 0) { |
| usb_stop(); |
| return 1; |
| } |
| |
| /* Stop USB */ |
| usb_stop(); |
| return 0; |
| } |