| /* | 
 |  * (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 long do_fat_read(const char *, void *, unsigned long, int); | 
 | extern int do_fat_fsload(cmd_tbl_t *, int, int, char * const []); | 
 |  | 
 | static int load_rescue_image(ulong); | 
 |  | 
 | void cm5200_fwupdate(void) | 
 | { | 
 | 	cmd_tbl_t *bcmd; | 
 | 	char *rsargs; | 
 | 	char *tmp = NULL; | 
 | 	char ka[16]; | 
 | 	char * const 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", (ulong)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 * const 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; | 
 | } |