summaryrefslogtreecommitdiffstats
path: root/u-boot/common
diff options
context:
space:
mode:
authorH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
committerH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
commit92988a21ad4c4c9504295ccb580c9f806134471b (patch)
tree5effc9f14170112450de05c67dafbe8d5034d595 /u-boot/common
parentca2b506783b676c95762c54ea24dcfdaae1947c9 (diff)
downloadbootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.zip
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.gz
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.bz2
added boot script files to repository
Diffstat (limited to 'u-boot/common')
-rw-r--r--u-boot/common/Makefile197
-rw-r--r--u-boot/common/bedbug.c1252
-rw-r--r--u-boot/common/cmd_ambapp.c280
-rw-r--r--u-boot/common/cmd_bdinfo.c462
-rw-r--r--u-boot/common/cmd_bedbug.c421
-rw-r--r--u-boot/common/cmd_bmp.c255
-rw-r--r--u-boot/common/cmd_boot.c74
-rw-r--r--u-boot/common/cmd_bootldr.c175
-rw-r--r--u-boot/common/cmd_bootm.c1500
-rw-r--r--u-boot/common/cmd_cache.c98
-rw-r--r--u-boot/common/cmd_console.c70
-rw-r--r--u-boot/common/cmd_cplbinfo.c60
-rw-r--r--u-boot/common/cmd_cramfs.c216
-rw-r--r--u-boot/common/cmd_dataflash_mmc_mux.c64
-rw-r--r--u-boot/common/cmd_date.c226
-rw-r--r--u-boot/common/cmd_dcr.c237
-rw-r--r--u-boot/common/cmd_df.c36
-rw-r--r--u-boot/common/cmd_diag.c76
-rw-r--r--u-boot/common/cmd_display.c70
-rw-r--r--u-boot/common/cmd_dtt.c60
-rw-r--r--u-boot/common/cmd_echo.c58
-rw-r--r--u-boot/common/cmd_eeprom.c440
-rw-r--r--u-boot/common/cmd_elf.c368
-rw-r--r--u-boot/common/cmd_exit.c42
-rw-r--r--u-boot/common/cmd_ext2.c260
-rw-r--r--u-boot/common/cmd_fat.c186
-rw-r--r--u-boot/common/cmd_fdc.c846
-rw-r--r--u-boot/common/cmd_fdos.c151
-rw-r--r--u-boot/common/cmd_fdt.c829
-rw-r--r--u-boot/common/cmd_flash.c742
-rw-r--r--u-boot/common/cmd_fpga.c386
-rw-r--r--u-boot/common/cmd_help.c50
-rw-r--r--u-boot/common/cmd_i2c.c1553
-rw-r--r--u-boot/common/cmd_ide.c2027
-rw-r--r--u-boot/common/cmd_immap.c719
-rw-r--r--u-boot/common/cmd_irq.c55
-rw-r--r--u-boot/common/cmd_itest.c193
-rw-r--r--u-boot/common/cmd_jffs2.c637
-rw-r--r--u-boot/common/cmd_license.c56
-rw-r--r--u-boot/common/cmd_load.c1119
-rw-r--r--u-boot/common/cmd_log.c317
-rw-r--r--u-boot/common/cmd_mac.c49
-rw-r--r--u-boot/common/cmd_mem.c1362
-rw-r--r--u-boot/common/cmd_mfsl.c404
-rw-r--r--u-boot/common/cmd_mgdisk.c71
-rw-r--r--u-boot/common/cmd_mii.c452
-rw-r--r--u-boot/common/cmd_misc.c55
-rw-r--r--u-boot/common/cmd_mmc.c251
-rw-r--r--u-boot/common/cmd_mp.c90
-rw-r--r--u-boot/common/cmd_mtdparts.c2092
-rw-r--r--u-boot/common/cmd_nand.c897
-rw-r--r--u-boot/common/cmd_net.c385
-rw-r--r--u-boot/common/cmd_nvedit.c941
-rw-r--r--u-boot/common/cmd_onenand.c602
-rw-r--r--u-boot/common/cmd_otp.c238
-rw-r--r--u-boot/common/cmd_pci.c509
-rw-r--r--u-boot/common/cmd_pcmcia.c365
-rw-r--r--u-boot/common/cmd_portio.c161
-rw-r--r--u-boot/common/cmd_reginfo.c243
-rw-r--r--u-boot/common/cmd_reiser.c237
-rw-r--r--u-boot/common/cmd_sata.c200
-rw-r--r--u-boot/common/cmd_scsi.c629
-rw-r--r--u-boot/common/cmd_setexpr.c94
-rw-r--r--u-boot/common/cmd_sf.c193
-rw-r--r--u-boot/common/cmd_source.c239
-rw-r--r--u-boot/common/cmd_spi.c156
-rw-r--r--u-boot/common/cmd_spibootldr.c37
-rw-r--r--u-boot/common/cmd_strings.c46
-rw-r--r--u-boot/common/cmd_terminal.c92
-rw-r--r--u-boot/common/cmd_test.c173
-rw-r--r--u-boot/common/cmd_tsi148.c491
-rw-r--r--u-boot/common/cmd_ubi.c636
-rw-r--r--u-boot/common/cmd_ubifs.c191
-rw-r--r--u-boot/common/cmd_universe.c386
-rw-r--r--u-boot/common/cmd_usb.c742
-rw-r--r--u-boot/common/cmd_version.c47
-rw-r--r--u-boot/common/cmd_vfd.c102
-rw-r--r--u-boot/common/cmd_ximg.c275
-rw-r--r--u-boot/common/cmd_yaffs2.c213
-rw-r--r--u-boot/common/command.c481
-rw-r--r--u-boot/common/console.c722
-rw-r--r--u-boot/common/ddr_spd.c118
-rw-r--r--u-boot/common/dlmalloc.c3341
-rw-r--r--u-boot/common/dlmalloc.src3265
-rw-r--r--u-boot/common/env_common.c278
-rw-r--r--u-boot/common/env_dataflash.c126
-rw-r--r--u-boot/common/env_eeprom.c303
-rw-r--r--u-boot/common/env_embedded.c214
-rw-r--r--u-boot/common/env_flash.c380
-rw-r--r--u-boot/common/env_mgdisk.c84
-rw-r--r--u-boot/common/env_mmc.c167
-rw-r--r--u-boot/common/env_nand.c452
-rw-r--r--u-boot/common/env_nowhere.c58
-rw-r--r--u-boot/common/env_nvram.c140
-rw-r--r--u-boot/common/env_onenand.c151
-rw-r--r--u-boot/common/env_sf.c382
-rw-r--r--u-boot/common/exports.c42
-rw-r--r--u-boot/common/fdt_support.c1225
-rw-r--r--u-boot/common/flash.c232
-rw-r--r--u-boot/common/hush.c3630
-rw-r--r--u-boot/common/hwconfig.c288
-rw-r--r--u-boot/common/image.c3062
-rw-r--r--u-boot/common/iomux.c175
-rw-r--r--u-boot/common/kallsyms.c44
-rw-r--r--u-boot/common/kgdb.c608
-rw-r--r--u-boot/common/kgdb_stubs.c64
-rw-r--r--u-boot/common/lcd.c855
-rw-r--r--u-boot/common/lynxkdi.c68
-rw-r--r--u-boot/common/main.c1427
-rw-r--r--u-boot/common/memsize.c94
-rw-r--r--u-boot/common/miiphyutil.c483
-rw-r--r--u-boot/common/modem.c118
-rw-r--r--u-boot/common/s_record.c195
-rw-r--r--u-boot/common/serial.c293
-rw-r--r--u-boot/common/stdio.c244
-rw-r--r--u-boot/common/system_map.c8
-rw-r--r--u-boot/common/update.c315
-rw-r--r--u-boot/common/usb.c1388
-rw-r--r--u-boot/common/usb_kbd.c756
-rw-r--r--u-boot/common/usb_storage.c1449
-rw-r--r--u-boot/common/xyzModem.c849
121 files changed, 59783 insertions, 0 deletions
diff --git a/u-boot/common/Makefile b/u-boot/common/Makefile
new file mode 100644
index 0000000..048df0c
--- /dev/null
+++ b/u-boot/common/Makefile
@@ -0,0 +1,197 @@
+#
+# (C) Copyright 2004-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB = $(obj)libcommon.o
+
+# core
+COBJS-y += main.o
+COBJS-y += console.o
+COBJS-y += command.o
+COBJS-y += dlmalloc.o
+COBJS-y += exports.o
+COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o
+COBJS-y += image.o
+COBJS-y += memsize.o
+COBJS-y += s_record.o
+COBJS-$(CONFIG_SERIAL_MULTI) += serial.o
+COBJS-y += stdio.o
+COBJS-y += xyzModem.o
+
+# core command
+COBJS-y += cmd_boot.o
+COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o
+COBJS-y += cmd_help.o
+COBJS-y += cmd_nvedit.o
+COBJS-y += cmd_version.o
+
+# environment
+COBJS-y += env_common.o
+COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
+COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
+XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
+COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_embedded.o
+XCOBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_embedded.o
+COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_embedded.o
+COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
+COBJS-$(CONFIG_ENV_IS_IN_MG_DISK) += env_mgdisk.o
+COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o
+COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
+COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o
+COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o
+COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
+COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
+
+# command
+COBJS-$(CONFIG_CMD_AMBAPP) += cmd_ambapp.o
+COBJS-$(CONFIG_SOURCE) += cmd_source.o
+COBJS-$(CONFIG_CMD_SOURCE) += cmd_source.o
+COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
+COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
+COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o
+COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
+COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o
+COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o
+COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o
+COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o
+COBJS-$(CONFIG_CMD_DATE) += cmd_date.o
+ifdef CONFIG_4xx
+COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o
+endif
+ifdef CONFIG_POST
+COBJS-$(CONFIG_CMD_DIAG) += cmd_diag.o
+endif
+COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o
+COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o
+COBJS-$(CONFIG_CMD_ECHO) += cmd_echo.o
+COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o
+COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
+COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
+COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
+COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
+COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
+COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
+COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o
+COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o
+COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o
+ifdef CONFIG_FPGA
+COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
+endif
+COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
+COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o
+COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o
+COBJS-$(CONFIG_CMD_IRQ) += cmd_irq.o
+COBJS-$(CONFIG_CMD_ITEST) += cmd_itest.o
+COBJS-$(CONFIG_CMD_JFFS2) += cmd_jffs2.o
+COBJS-$(CONFIG_CMD_CRAMFS) += cmd_cramfs.o
+COBJS-$(CONFIG_CMD_LICENSE) += cmd_license.o
+COBJS-y += cmd_load.o
+COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o
+COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o
+COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o
+COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o
+COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o
+COBJS-$(CONFIG_MII) += miiphyutil.o
+COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
+COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
+COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
+COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
+COBJS-$(CONFIG_MP) += cmd_mp.o
+COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
+COBJS-$(CONFIG_CMD_NAND) += cmd_nand.o
+COBJS-$(CONFIG_CMD_NET) += cmd_net.o
+COBJS-$(CONFIG_CMD_ONENAND) += cmd_onenand.o
+COBJS-$(CONFIG_CMD_OTP) += cmd_otp.o
+ifdef CONFIG_PCI
+COBJS-$(CONFIG_CMD_PCI) += cmd_pci.o
+endif
+COBJS-y += cmd_pcmcia.o
+COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o
+COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
+COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o
+COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o
+COBJS-$(CONFIG_CMD_SF) += cmd_sf.o
+COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o
+COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o
+COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o
+COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o
+COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o
+COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
+COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o
+COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o
+COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o
+COBJS-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o
+COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o
+ifdef CONFIG_CMD_USB
+COBJS-y += cmd_usb.o
+COBJS-y += usb.o
+COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
+endif
+COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
+COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
+COBJS-$(CONFIG_VFD) += cmd_vfd.o
+
+# others
+COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o
+COBJS-$(CONFIG_HWCONFIG) += hwconfig.o
+COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o
+COBJS-y += flash.o
+COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o
+COBJS-$(CONFIG_KALLSYMS) += kallsyms.o
+COBJS-$(CONFIG_LCD) += lcd.o
+COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o
+COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o
+COBJS-$(CONFIG_UPDATE_TFTP) += update.o
+COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
+
+
+COBJS := $(sort $(COBJS-y))
+XCOBJS := $(sort $(XCOBJS-y))
+SRCS := $(COBJS:.o=.c) $(XCOBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+XOBJS := $(addprefix $(obj),$(XCOBJS))
+
+CPPFLAGS += -I..
+
+all: $(LIB) $(XOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+$(obj)env_embedded.o: $(src)env_embedded.c $(obj)../tools/envcrc
+ $(CC) $(AFLAGS) -Wa,--no-warn \
+ -DENV_CRC=$(shell $(obj)../tools/envcrc) \
+ -c -o $@ $(src)env_embedded.c
+
+$(obj)../tools/envcrc:
+ $(MAKE) -C ../tools
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/u-boot/common/bedbug.c b/u-boot/common/bedbug.c
new file mode 100644
index 0000000..60109cf
--- /dev/null
+++ b/u-boot/common/bedbug.c
@@ -0,0 +1,1252 @@
+/* $Id$ */
+
+#include <common.h>
+
+#include <linux/ctype.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/ppc.h>
+#include <bedbug/regs.h>
+#include <bedbug/tables.h>
+
+#define Elf32_Word unsigned long
+
+/* USE_SOURCE_CODE enables some symbolic debugging functions of this
+ code. This is only useful if the program will have access to the
+ source code for the binary being examined.
+*/
+
+/* #define USE_SOURCE_CODE 1 */
+
+#ifdef USE_SOURCE_CODE
+extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
+extern struct symreflist *symByAddr;
+extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
+#endif /* USE_SOURCE_CODE */
+
+int print_operands __P ((struct ppc_ctx *));
+int get_operand_value __P ((struct opcode *, unsigned long,
+ enum OP_FIELD, unsigned long *));
+struct opcode *find_opcode __P ((unsigned long));
+struct opcode *find_opcode_by_name __P ((char *));
+char *spr_name __P ((int));
+int spr_value __P ((char *));
+char *tbr_name __P ((int));
+int tbr_value __P ((char *));
+int parse_operand __P ((unsigned long, struct opcode *,
+ struct operand *, char *, int *));
+int get_word __P ((char **, char *));
+long read_number __P ((char *));
+int downstring __P ((char *));
+
+
+/*======================================================================
+ * Entry point for the PPC disassembler.
+ *
+ * Arguments:
+ * memaddr The address to start disassembling from.
+ *
+ * virtual If this value is non-zero, then this will be
+ * used as the base address for the output and
+ * symbol lookups. If this value is zero then
+ * memaddr is used as the absolute address.
+ *
+ * num_instr The number of instructions to disassemble. Since
+ * each instruction is 32 bits long, this can be
+ * computed if you know the total size of the region.
+ *
+ * pfunc The address of a function that is called to print
+ * each line of output. The function should take a
+ * single character pointer as its parameters a la puts.
+ *
+ * flags Sets options for the output. This is a
+ * bitwise-inclusive-OR of the following
+ * values. Note that only one of the radix
+ * options may be set.
+ *
+ * F_RADOCTAL - output radix is unsigned base 8.
+ * F_RADUDECIMAL - output radix is unsigned base 10.
+ * F_RADSDECIMAL - output radix is signed base 10.
+ * F_RADHEX - output radix is unsigned base 16.
+ * F_SIMPLE - use simplified mnemonics.
+ * F_SYMBOL - lookup symbols for addresses.
+ * F_INSTR - output raw instruction.
+ * F_LINENO - show line # info if available.
+ *
+ * Returns TRUE if the area was successfully disassembled or FALSE if
+ * a problem was encountered with accessing the memory.
+ */
+
+int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr,
+ int (*pfunc) (const char *), unsigned long flags)
+{
+ int i;
+ struct ppc_ctx ctx;
+
+#ifdef USE_SOURCE_CODE
+ int line_no = 0;
+ int last_line_no = 0;
+ char funcname[128] = { 0 };
+ char filename[256] = { 0 };
+ char last_funcname[128] = { 0 };
+ int symoffset;
+ char *symname;
+ char *cursym = (char *) 0;
+#endif /* USE_SOURCE_CODE */
+ /*------------------------------------------------------------*/
+
+ ctx.flags = flags;
+ ctx.virtual = virtual;
+
+ /* Figure out the output radix before we go any further */
+
+ if (ctx.flags & F_RADOCTAL) {
+ /* Unsigned octal output */
+ strcpy (ctx.radix_fmt, "O%o");
+ } else if (ctx.flags & F_RADUDECIMAL) {
+ /* Unsigned decimal output */
+ strcpy (ctx.radix_fmt, "%u");
+ } else if (ctx.flags & F_RADSDECIMAL) {
+ /* Signed decimal output */
+ strcpy (ctx.radix_fmt, "%d");
+ } else {
+ /* Unsigned hex output */
+ strcpy (ctx.radix_fmt, "0x%x");
+ }
+
+ if (ctx.virtual == 0) {
+ ctx.virtual = memaddr;
+ }
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_SYMBOL) {
+ if (symByAddr == 0) /* no symbols loaded */
+ ctx.flags &= ~F_SYMBOL;
+ else {
+ cursym = (char *) 0;
+ symoffset = 0;
+ }
+ }
+#endif /* USE_SOURCE_CODE */
+
+ /* format each line as "XXXXXXXX: <symbol> IIIIIIII disassembly" where,
+ XXXXXXXX is the memory address in hex,
+ <symbol> is the symbolic location if F_SYMBOL is set.
+ IIIIIIII is the raw machine code in hex if F_INSTR is set,
+ and disassembly is the disassembled machine code with numbers
+ formatted according to the 'radix' parameter */
+
+ for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_LINENO) {
+ if ((line_info_from_addr ((Elf32_Word) ctx.virtual, filename,
+ funcname, &line_no) == TRUE) &&
+ ((line_no != last_line_no) ||
+ (strcmp (last_funcname, funcname) != 0))) {
+ print_source_line (filename, funcname, line_no, pfunc);
+ }
+ last_line_no = line_no;
+ strcpy (last_funcname, funcname);
+ }
+#endif /* USE_SOURCE_CODE */
+
+ sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual);
+ ctx.datalen = 10;
+
+#ifdef USE_SOURCE_CODE
+ if (ctx.flags & F_SYMBOL) {
+ if ((symname =
+ symbol_name_from_addr ((Elf32_Word) ctx.virtual,
+ TRUE, 0)) != 0) {
+ cursym = symname;
+ symoffset = 0;
+ } else {
+ if ((cursym == 0) &&
+ ((symname =
+ symbol_name_from_addr ((Elf32_Word) ctx.virtual,
+ FALSE, &symoffset)) != 0)) {
+ cursym = symname;
+ } else {
+ symoffset += 4;
+ }
+ }
+
+ if (cursym != 0) {
+ sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
+ ctx.datalen = strlen (ctx.data);
+ sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
+ strcat (ctx.data, ">");
+ ctx.datalen = strlen (ctx.data);
+ }
+ }
+#endif /* USE_SOURCE_CODE */
+
+ ctx.instr = INSTRUCTION (memaddr);
+
+ if (ctx.flags & F_INSTR) {
+ /* Find the opcode structure for this opcode. If one is not found
+ then it must be an illegal instruction */
+ sprintf (&ctx.data[ctx.datalen],
+ " %02lx %02lx %02lx %02lx ",
+ ((ctx.instr >> 24) & 0xff),
+ ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
+ (ctx.instr & 0xff));
+ ctx.datalen += 18;
+ } else {
+ strcat (ctx.data, " ");
+ ctx.datalen += 3;
+ }
+
+ if ((ctx.op = find_opcode (ctx.instr)) == 0) {
+ /* Illegal Opcode */
+ sprintf (&ctx.data[ctx.datalen], " .long 0x%08lx",
+ ctx.instr);
+ ctx.datalen += 24;
+ (*pfunc) (ctx.data);
+ continue;
+ }
+
+ if (((ctx.flags & F_SIMPLE) == 0) ||
+ (ctx.op->hfunc == 0) || ((*ctx.op->hfunc) (&ctx) == FALSE)) {
+ sprintf (&ctx.data[ctx.datalen], "%-7s ", ctx.op->name);
+ ctx.datalen += 8;
+ print_operands (&ctx);
+ }
+
+ (*pfunc) (ctx.data);
+ }
+
+ return TRUE;
+} /* disppc */
+
+
+
+/*======================================================================
+ * Called by the disassembler to print the operands for an instruction.
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * always returns 0.
+ */
+
+int print_operands (struct ppc_ctx *ctx)
+{
+ int open_parens = 0;
+ int field;
+ unsigned long operand;
+ struct operand *opr;
+
+#ifdef USE_SOURCE_CODE
+ char *symname;
+ int offset;
+#endif /* USE_SOURCE_CODE */
+ /*------------------------------------------------------------*/
+
+ /* Walk through the operands and list each in order */
+ for (field = 0; ctx->op->fields[field] != 0; ++field) {
+ if (ctx->op->fields[field] > n_operands) {
+ continue; /* bad operand ?! */
+ }
+
+ opr = &operands[ctx->op->fields[field] - 1];
+
+ if (opr->hint & OH_SILENT) {
+ continue;
+ }
+
+ if ((field > 0) && !open_parens) {
+ strcat (ctx->data, ",");
+ ctx->datalen++;
+ }
+
+ operand = (ctx->instr >> opr->shift) & ((1 << opr->bits) - 1);
+
+ if (opr->hint & OH_ADDR) {
+ if ((operand & (1 << (opr->bits - 1))) != 0) {
+ operand = operand - (1 << opr->bits);
+ }
+
+ if (ctx->op->hint & H_RELATIVE)
+ operand = (operand << 2) + (unsigned long) ctx->virtual;
+ else
+ operand = (operand << 2);
+
+
+ sprintf (&ctx->data[ctx->datalen], "0x%lx", operand);
+ ctx->datalen = strlen (ctx->data);
+
+#ifdef USE_SOURCE_CODE
+ if ((ctx->flags & F_SYMBOL) &&
+ ((symname =
+ symbol_name_from_addr (operand, 0, &offset)) != 0)) {
+ sprintf (&ctx->data[ctx->datalen], " <%s", symname);
+ if (offset != 0) {
+ strcat (ctx->data, "+");
+ ctx->datalen = strlen (ctx->data);
+ sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
+ offset);
+ }
+ strcat (ctx->data, ">");
+ }
+#endif /* USE_SOURCE_CODE */
+ }
+
+ else if (opr->hint & OH_REG) {
+ if ((operand == 0) &&
+ (opr->field == O_rA) && (ctx->op->hint & H_RA0_IS_0)) {
+ strcat (ctx->data, "0");
+ } else {
+ sprintf (&ctx->data[ctx->datalen], "r%d", (short) operand);
+ }
+
+ if (open_parens) {
+ strcat (ctx->data, ")");
+ open_parens--;
+ }
+ }
+
+ else if (opr->hint & OH_SPR) {
+ strcat (ctx->data, spr_name (operand));
+ }
+
+ else if (opr->hint & OH_TBR) {
+ strcat (ctx->data, tbr_name (operand));
+ }
+
+ else if (opr->hint & OH_LITERAL) {
+ switch (opr->field) {
+ case O_cr2:
+ strcat (ctx->data, "cr2");
+ ctx->datalen += 3;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ else {
+ sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
+ (unsigned short) operand);
+
+ if (open_parens) {
+ strcat (ctx->data, ")");
+ open_parens--;
+ }
+
+ else if (opr->hint & OH_OFFSET) {
+ strcat (ctx->data, "(");
+ open_parens++;
+ }
+ }
+
+ ctx->datalen = strlen (ctx->data);
+ }
+
+ return 0;
+} /* print_operands */
+
+
+
+/*======================================================================
+ * Called to get the value of an arbitrary operand with in an instruction.
+ *
+ * Arguments:
+ * op The pointer to the opcode structure to which
+ * the operands belong.
+ *
+ * instr The instruction (32 bits) containing the opcode
+ * and the operands to print. By the time that
+ * this routine is called the operand has already
+ * been added to the output.
+ *
+ * field The field (operand) to get the value of.
+ *
+ * value The address of an unsigned long to be filled in
+ * with the value of the operand if it is found. This
+ * will only be filled in if the function returns
+ * TRUE. This may be passed as 0 if the value is
+ * not required.
+ *
+ * Returns TRUE if the operand was found or FALSE if it was not.
+ */
+
+int get_operand_value (struct opcode *op, unsigned long instr,
+ enum OP_FIELD field, unsigned long *value)
+{
+ int i;
+ struct operand *opr;
+
+ /*------------------------------------------------------------*/
+
+ if (field > n_operands) {
+ return FALSE; /* bad operand ?! */
+ }
+
+ /* Walk through the operands and list each in order */
+ for (i = 0; op->fields[i] != 0; ++i) {
+ if (op->fields[i] != field) {
+ continue;
+ }
+
+ opr = &operands[op->fields[i] - 1];
+
+ if (value) {
+ *value = (instr >> opr->shift) & ((1 << opr->bits) - 1);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+} /* operand_value */
+
+
+
+/*======================================================================
+ * Called by the disassembler to match an opcode value to an opcode structure.
+ *
+ * Arguments:
+ * instr The instruction (32 bits) to match. This value
+ * may contain operand values as well as the opcode
+ * since they will be masked out anyway for this
+ * search.
+ *
+ * Returns the address of an opcode struct (from the opcode table) if the
+ * operand successfully matched an entry, or 0 if no match was found.
+ */
+
+struct opcode *find_opcode (unsigned long instr)
+{
+ struct opcode *ptr;
+ int top = 0;
+ int bottom = n_opcodes - 1;
+ int idx;
+
+ /*------------------------------------------------------------*/
+
+ while (top <= bottom) {
+ idx = (top + bottom) >> 1;
+ ptr = &opcodes[idx];
+
+ if ((instr & ptr->mask) < ptr->opcode) {
+ bottom = idx - 1;
+ } else if ((instr & ptr->mask) > ptr->opcode) {
+ top = idx + 1;
+ } else {
+ return ptr;
+ }
+ }
+
+ return (struct opcode *) 0;
+} /* find_opcode */
+
+
+
+/*======================================================================
+ * Called by the assembler to match an opcode name to an opcode structure.
+ *
+ * Arguments:
+ * name The text name of the opcode, e.g. "b", "mtspr", etc.
+ *
+ * The opcodes are sorted numerically by their instruction binary code
+ * so a search for the name cannot use the binary search used by the
+ * other find routine.
+ *
+ * Returns the address of an opcode struct (from the opcode table) if the
+ * name successfully matched an entry, or 0 if no match was found.
+ */
+
+struct opcode *find_opcode_by_name (char *name)
+{
+ int idx;
+
+ /*------------------------------------------------------------*/
+
+ downstring (name);
+
+ for (idx = 0; idx < n_opcodes; ++idx) {
+ if (!strcmp (name, opcodes[idx].name))
+ return &opcodes[idx];
+ }
+
+ return (struct opcode *) 0;
+} /* find_opcode_by_name */
+
+
+
+/*======================================================================
+ * Convert the 'spr' operand from its numeric value to its symbolic name.
+ *
+ * Arguments:
+ * value The value of the 'spr' operand. This value should
+ * be unmodified from its encoding in the instruction.
+ * the split-field computations will be performed
+ * here before the switch.
+ *
+ * Returns the address of a character array containing the name of the
+ * special purpose register defined by the 'value' parameter, or the
+ * address of a character array containing "???" if no match was found.
+ */
+
+char *spr_name (int value)
+{
+ unsigned short spr;
+ static char other[10];
+ int i;
+
+ /*------------------------------------------------------------*/
+
+ /* spr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ spr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
+
+ for (i = 0; i < n_sprs; ++i) {
+ if (spr == spr_map[i].spr_val)
+ return spr_map[i].spr_name;
+ }
+
+ sprintf (other, "%d", spr);
+ return other;
+} /* spr_name */
+
+
+
+/*======================================================================
+ * Convert the 'spr' operand from its symbolic name to its numeric value
+ *
+ * Arguments:
+ * name The symbolic name of the 'spr' operand. The
+ * split-field encoding will be done by this routine.
+ * NOTE: name can be a number.
+ *
+ * Returns the numeric value for the spr appropriate for encoding a machine
+ * instruction. Returns 0 if unable to find the SPR.
+ */
+
+int spr_value (char *name)
+{
+ struct spr_info *sprp;
+ int spr;
+ int i;
+
+ /*------------------------------------------------------------*/
+
+ if (!name || !*name)
+ return 0;
+
+ if (isdigit ((int) name[0])) {
+ i = htonl (read_number (name));
+ spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
+ return spr;
+ }
+
+ downstring (name);
+
+ for (i = 0; i < n_sprs; ++i) {
+ sprp = &spr_map[i];
+
+ if (strcmp (name, sprp->spr_name) == 0) {
+ /* spr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+ i = htonl (sprp->spr_val);
+ spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
+
+ return spr;
+ }
+ }
+
+ return 0;
+} /* spr_value */
+
+
+
+/*======================================================================
+ * Convert the 'tbr' operand from its numeric value to its symbolic name.
+ *
+ * Arguments:
+ * value The value of the 'tbr' operand. This value should
+ * be unmodified from its encoding in the instruction.
+ * the split-field computations will be performed
+ * here before the switch.
+ *
+ * Returns the address of a character array containing the name of the
+ * time base register defined by the 'value' parameter, or the address
+ * of a character array containing "???" if no match was found.
+ */
+
+char *tbr_name (int value)
+{
+ unsigned short tbr;
+
+ /*------------------------------------------------------------*/
+
+ /* tbr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ tbr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
+
+ if (tbr == 268)
+ return "TBL";
+
+ else if (tbr == 269)
+ return "TBU";
+
+
+ return "???";
+} /* tbr_name */
+
+
+
+/*======================================================================
+ * Convert the 'tbr' operand from its symbolic name to its numeric value.
+ *
+ * Arguments:
+ * name The symbolic name of the 'tbr' operand. The
+ * split-field encoding will be done by this routine.
+ *
+ * Returns the numeric value for the spr appropriate for encoding a machine
+ * instruction. Returns 0 if unable to find the TBR.
+ */
+
+int tbr_value (char *name)
+{
+ int tbr;
+ int val;
+
+ /*------------------------------------------------------------*/
+
+ if (!name || !*name)
+ return 0;
+
+ downstring (name);
+
+ if (isdigit ((int) name[0])) {
+ val = read_number (name);
+
+ if (val != 268 && val != 269)
+ return 0;
+ } else if (strcmp (name, "tbl") == 0)
+ val = 268;
+ else if (strcmp (name, "tbu") == 0)
+ val = 269;
+ else
+ return 0;
+
+ /* tbr is a 10 bit field whose interpretation has the high and low
+ five-bit fields reversed from their encoding in the operand */
+
+ val = htonl (val);
+ tbr = ((val >> 5) & 0x1f) | ((val & 0x1f) << 5);
+ return tbr;
+} /* tbr_name */
+
+
+
+/*======================================================================
+ * The next several functions (handle_xxx) are the routines that handle
+ * disassembling the opcodes with simplified mnemonics.
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * Returns TRUE if the simpler form was printed or FALSE if it was not.
+ */
+
+int handle_bc (struct ppc_ctx *ctx)
+{
+ unsigned long bo;
+ unsigned long bi;
+ static struct opcode blt = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
+ 0, "blt", H_RELATIVE
+ };
+ static struct opcode bne =
+ { B_OPCODE (16, 0, 0), B_MASK, {O_cr2, O_BD, 0},
+ 0, "bne", H_RELATIVE
+ };
+ static struct opcode bdnz = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
+ 0, "bdnz", H_RELATIVE
+ };
+
+ /*------------------------------------------------------------*/
+
+ if (get_operand_value (ctx->op, ctx->instr, O_BO, &bo) == FALSE)
+ return FALSE;
+
+ if (get_operand_value (ctx->op, ctx->instr, O_BI, &bi) == FALSE)
+ return FALSE;
+
+ if ((bo == 12) && (bi == 0)) {
+ ctx->op = &blt;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return TRUE;
+ } else if ((bo == 4) && (bi == 10)) {
+ ctx->op = &bne;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return TRUE;
+ } else if ((bo == 16) && (bi == 0)) {
+ ctx->op = &bdnz;
+ sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
+ ctx->datalen += 8;
+ print_operands (ctx);
+ return TRUE;
+ }
+
+ return FALSE;
+} /* handle_blt */
+
+
+
+/*======================================================================
+ * Outputs source line information for the disassembler. This should
+ * be modified in the future to lookup the actual line of source code
+ * from the file, but for now this will do.
+ *
+ * Arguments:
+ * filename The address of a character array containing the
+ * absolute path and file name of the source file.
+ *
+ * funcname The address of a character array containing the
+ * name of the function (not C++ demangled (yet))
+ * to which this code belongs.
+ *
+ * line_no An integer specifying the source line number that
+ * generated this code.
+ *
+ * pfunc The address of a function to call to print the output.
+ *
+ *
+ * Returns TRUE if it was able to output the line info, or false if it was
+ * not.
+ */
+
+int print_source_line (char *filename, char *funcname,
+ int line_no, int (*pfunc) (const char *))
+{
+ char out_buf[256];
+
+ /*------------------------------------------------------------*/
+
+ (*pfunc) (""); /* output a newline */
+ sprintf (out_buf, "%s %s(): line %d", filename, funcname, line_no);
+ (*pfunc) (out_buf);
+
+ return TRUE;
+} /* print_source_line */
+
+
+
+/*======================================================================
+ * Entry point for the PPC assembler.
+ *
+ * Arguments:
+ * asm_buf An array of characters containing the assembly opcode
+ * and operands to convert to a POWERPC machine
+ * instruction.
+ *
+ * Returns the machine instruction or zero.
+ */
+
+unsigned long asmppc (unsigned long memaddr, char *asm_buf, int *err)
+{
+ struct opcode *opc;
+ struct operand *oper[MAX_OPERANDS];
+ unsigned long instr;
+ unsigned long param;
+ char *ptr = asm_buf;
+ char scratch[20];
+ int i;
+ int w_operands = 0; /* wanted # of operands */
+ int n_operands = 0; /* # of operands read */
+ int asm_debug = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (err)
+ *err = 0;
+
+ if (get_word (&ptr, scratch) == 0)
+ return 0;
+
+ /* Lookup the opcode structure based on the opcode name */
+ if ((opc = find_opcode_by_name (scratch)) == (struct opcode *) 0) {
+ if (err)
+ *err = E_ASM_BAD_OPCODE;
+ return 0;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Opcode = \"%s\"\n", opc->name);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ if (opc->fields[i] == 0)
+ break;
+ ++w_operands;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Expecting %d operands\n", w_operands);
+ }
+
+ instr = opc->opcode;
+
+ /* read each operand */
+ while (n_operands < w_operands) {
+
+ oper[n_operands] = &operands[opc->fields[n_operands] - 1];
+
+ if (oper[n_operands]->hint & OH_SILENT) {
+ /* Skip silent operands, they are covered in opc->opcode */
+
+ if (asm_debug) {
+ printf ("asmppc: Operand %d \"%s\" SILENT\n", n_operands,
+ oper[n_operands]->name);
+ }
+
+ ++n_operands;
+ continue;
+ }
+
+ if (get_word (&ptr, scratch) == 0)
+ break;
+
+ if (asm_debug) {
+ printf ("asmppc: Operand %d \"%s\" : \"%s\"\n", n_operands,
+ oper[n_operands]->name, scratch);
+ }
+
+ if ((param = parse_operand (memaddr, opc, oper[n_operands],
+ scratch, err)) == -1)
+ return 0;
+
+ instr |= param;
+ ++n_operands;
+ }
+
+ if (n_operands < w_operands) {
+ if (err)
+ *err = E_ASM_NUM_OPERANDS;
+ return 0;
+ }
+
+ if (asm_debug) {
+ printf ("asmppc: Instruction = 0x%08lx\n", instr);
+ }
+
+ return instr;
+} /* asmppc */
+
+
+
+/*======================================================================
+ * Called by the assembler to interpret a single operand
+ *
+ * Arguments:
+ * ctx A pointer to the disassembler context record.
+ *
+ * Returns 0 if the operand is ok, or -1 if it is bad.
+ */
+
+int parse_operand (unsigned long memaddr, struct opcode *opc,
+ struct operand *oper, char *txt, int *err)
+{
+ long data;
+ long mask;
+ int is_neg = 0;
+
+ /*------------------------------------------------------------*/
+
+ mask = (1 << oper->bits) - 1;
+
+ if (oper->hint & OH_ADDR) {
+ data = read_number (txt);
+
+ if (opc->hint & H_RELATIVE)
+ data = data - memaddr;
+
+ if (data < 0)
+ is_neg = 1;
+
+ data >>= 2;
+ data &= (mask >> 1);
+
+ if (is_neg)
+ data |= 1 << (oper->bits - 1);
+ }
+
+ else if (oper->hint & OH_REG) {
+ if (txt[0] == 'r' || txt[0] == 'R')
+ txt++;
+ else if (txt[0] == '%' && (txt[1] == 'r' || txt[1] == 'R'))
+ txt += 2;
+
+ data = read_number (txt);
+ if (data > 31) {
+ if (err)
+ *err = E_ASM_BAD_REGISTER;
+ return -1;
+ }
+
+ data = htonl (data);
+ }
+
+ else if (oper->hint & OH_SPR) {
+ if ((data = spr_value (txt)) == 0) {
+ if (err)
+ *err = E_ASM_BAD_SPR;
+ return -1;
+ }
+ }
+
+ else if (oper->hint & OH_TBR) {
+ if ((data = tbr_value (txt)) == 0) {
+ if (err)
+ *err = E_ASM_BAD_TBR;
+ return -1;
+ }
+ }
+
+ else {
+ data = htonl (read_number (txt));
+ }
+
+ return (data & mask) << oper->shift;
+} /* parse_operand */
+
+
+char *asm_error_str (int err)
+{
+ switch (err) {
+ case E_ASM_BAD_OPCODE:
+ return "Bad opcode";
+ case E_ASM_NUM_OPERANDS:
+ return "Bad number of operands";
+ case E_ASM_BAD_REGISTER:
+ return "Bad register number";
+ case E_ASM_BAD_SPR:
+ return "Bad SPR name or number";
+ case E_ASM_BAD_TBR:
+ return "Bad TBR name or number";
+ }
+
+ return "";
+} /* asm_error_str */
+
+
+
+/*======================================================================
+ * Copy a word from one buffer to another, ignores leading white spaces.
+ *
+ * Arguments:
+ * src The address of a character pointer to the
+ * source buffer.
+ * dest A pointer to a character buffer to write the word
+ * into.
+ *
+ * Returns the number of non-white space characters copied, or zero.
+ */
+
+int get_word (char **src, char *dest)
+{
+ char *ptr = *src;
+ int nchars = 0;
+
+ /*------------------------------------------------------------*/
+
+ /* Eat white spaces */
+ while (*ptr && isblank (*ptr))
+ ptr++;
+
+ if (*ptr == 0) {
+ *src = ptr;
+ return 0;
+ }
+
+ /* Find the text of the word */
+ while (*ptr && !isblank (*ptr) && (*ptr != ','))
+ dest[nchars++] = *ptr++;
+ ptr = (*ptr == ',') ? ptr + 1 : ptr;
+ dest[nchars] = 0;
+
+ *src = ptr;
+ return nchars;
+} /* get_word */
+
+
+
+/*======================================================================
+ * Convert a numeric string to a number, be aware of base notations.
+ *
+ * Arguments:
+ * txt The numeric string.
+ *
+ * Returns the converted numeric value.
+ */
+
+long read_number (char *txt)
+{
+ long val;
+ int is_neg = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (txt == 0 || *txt == 0)
+ return 0;
+
+ if (*txt == '-') {
+ is_neg = 1;
+ ++txt;
+ }
+
+ if (txt[0] == '0' && (txt[1] == 'x' || txt[1] == 'X')) /* hex */
+ val = simple_strtoul (&txt[2], NULL, 16);
+ else /* decimal */
+ val = simple_strtoul (txt, NULL, 10);
+
+ if (is_neg)
+ val = -val;
+
+ return val;
+} /* read_number */
+
+
+int downstring (char *s)
+{
+ if (!s || !*s)
+ return 0;
+
+ while (*s) {
+ if (isupper (*s))
+ *s = tolower (*s);
+ s++;
+ }
+
+ return 0;
+} /* downstring */
+
+
+
+/*======================================================================
+ * Examines the instruction at the current address and determines the
+ * next address to be executed. This will take into account branches
+ * of different types so that a "step" and "next" operations can be
+ * supported.
+ *
+ * Arguments:
+ * nextaddr The address (to be filled in) of the next
+ * instruction to execute. This will only be a valid
+ * address if TRUE is returned.
+ *
+ * step_over A flag indicating how to compute addresses for
+ * branch statements:
+ * TRUE = Step over the branch (next)
+ * FALSE = step into the branch (step)
+ *
+ * Returns TRUE if it was able to compute the address. Returns FALSE if
+ * it has a problem reading the current instruction or one of the registers.
+ */
+
+int find_next_address (unsigned char *nextaddr, int step_over,
+ struct pt_regs *regs)
+{
+ unsigned long pc; /* SRR0 register from PPC */
+ unsigned long ctr; /* CTR register from PPC */
+ unsigned long cr; /* CR register from PPC */
+ unsigned long lr; /* LR register from PPC */
+ unsigned long instr; /* instruction at SRR0 */
+ unsigned long next; /* computed instruction for 'next' */
+ unsigned long step; /* computed instruction for 'step' */
+ unsigned long addr = 0; /* target address operand */
+ unsigned long aa = 0; /* AA operand */
+ unsigned long lk = 0; /* LK operand */
+ unsigned long bo = 0; /* BO operand */
+ unsigned long bi = 0; /* BI operand */
+ struct opcode *op = 0; /* opcode structure for 'instr' */
+ int ctr_ok = 0;
+ int cond_ok = 0;
+ int conditional = 0;
+ int branch = 0;
+
+ /*------------------------------------------------------------*/
+
+ if (nextaddr == 0 || regs == 0) {
+ printf ("find_next_address: bad args");
+ return FALSE;
+ }
+
+ pc = regs->nip & 0xfffffffc;
+ instr = INSTRUCTION (pc);
+
+ if ((op = find_opcode (instr)) == (struct opcode *) 0) {
+ printf ("find_next_address: can't parse opcode 0x%lx", instr);
+ return FALSE;
+ }
+
+ ctr = regs->ctr;
+ cr = regs->ccr;
+ lr = regs->link;
+
+ switch (op->opcode) {
+ case B_OPCODE (16, 0, 0): /* bc */
+ case B_OPCODE (16, 0, 1): /* bcl */
+ case B_OPCODE (16, 1, 0): /* bca */
+ case B_OPCODE (16, 1, 1): /* bcla */
+ if (!get_operand_value (op, instr, O_BD, &addr) ||
+ !get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_AA, &aa) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return FALSE;
+
+ if ((addr & (1 << 13)) != 0)
+ addr = addr - (1 << 14);
+ addr <<= 2;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ case I_OPCODE (18, 0, 0): /* b */
+ case I_OPCODE (18, 0, 1): /* bl */
+ case I_OPCODE (18, 1, 0): /* ba */
+ case I_OPCODE (18, 1, 1): /* bla */
+ if (!get_operand_value (op, instr, O_LI, &addr) ||
+ !get_operand_value (op, instr, O_AA, &aa) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return FALSE;
+
+ if ((addr & (1 << 23)) != 0)
+ addr = addr - (1 << 24);
+ addr <<= 2;
+ conditional = 0;
+ branch = 1;
+ break;
+
+ case XL_OPCODE (19, 528, 0): /* bcctr */
+ case XL_OPCODE (19, 528, 1): /* bcctrl */
+ if (!get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return FALSE;
+
+ addr = ctr;
+ aa = 1;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ case XL_OPCODE (19, 16, 0): /* bclr */
+ case XL_OPCODE (19, 16, 1): /* bclrl */
+ if (!get_operand_value (op, instr, O_BO, &bo) ||
+ !get_operand_value (op, instr, O_BI, &bi) ||
+ !get_operand_value (op, instr, O_LK, &lk))
+ return FALSE;
+
+ addr = lr;
+ aa = 1;
+ conditional = 1;
+ branch = 1;
+ break;
+
+ default:
+ conditional = 0;
+ branch = 0;
+ break;
+ }
+
+ if (conditional) {
+ switch ((bo & 0x1e) >> 1) {
+ case 0: /* 0000y */
+ if (--ctr != 0)
+ ctr_ok = 1;
+
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 1: /* 0001y */
+ if (--ctr == 0)
+ ctr_ok = 1;
+
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 2: /* 001zy */
+ ctr_ok = 1;
+ cond_ok = !(cr & (1 << (31 - bi)));
+ break;
+
+ case 4: /* 0100y */
+ if (--ctr != 0)
+ ctr_ok = 1;
+
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 5: /* 0101y */
+ if (--ctr == 0)
+ ctr_ok = 1;
+
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 6: /* 011zy */
+ ctr_ok = 1;
+ cond_ok = cr & (1 << (31 - bi));
+ break;
+
+ case 8: /* 1z00y */
+ if (--ctr != 0)
+ ctr_ok = cond_ok = 1;
+ break;
+
+ case 9: /* 1z01y */
+ if (--ctr == 0)
+ ctr_ok = cond_ok = 1;
+ break;
+
+ case 10: /* 1z1zz */
+ ctr_ok = cond_ok = 1;
+ break;
+ }
+ }
+
+ if (branch && (!conditional || (ctr_ok && cond_ok))) {
+ if (aa)
+ step = addr;
+ else
+ step = addr + pc;
+
+ if (lk)
+ next = pc + 4;
+ else
+ next = step;
+ } else {
+ step = next = pc + 4;
+ }
+
+ if (step_over == TRUE)
+ *(unsigned long *) nextaddr = next;
+ else
+ *(unsigned long *) nextaddr = step;
+
+ return TRUE;
+} /* find_next_address */
+
+
+/*
+ * Copyright (c) 2000 William L. Pitts and W. Gerald Hicks
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
diff --git a/u-boot/common/cmd_ambapp.c b/u-boot/common/cmd_ambapp.c
new file mode 100644
index 0000000..fa7d7e2
--- /dev/null
+++ b/u-boot/common/cmd_ambapp.c
@@ -0,0 +1,280 @@
+/*
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * AMBA Plug&Play information list command
+ *
+ */
+#include <common.h>
+#include <command.h>
+#include <ambapp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* We put these variables into .data section so that they are zero
+ * when entering the AMBA Plug & Play routines (in cpu/cpu/ambapp.c)
+ * the first time. BSS is not garantueed to be zero since BSS
+ * hasn't been cleared the first times entering the CPU AMBA functions.
+ *
+ * The AMBA PnP routines call these functions if ambapp_???_print is set.
+ *
+ */
+int ambapp_apb_print __attribute__ ((section(".data"))) = 0;
+int ambapp_ahb_print __attribute__ ((section(".data"))) = 0;
+
+typedef struct {
+ int device_id;
+ char *name;
+} ambapp_device_name;
+
+static ambapp_device_name gaisler_devices[] = {
+ {GAISLER_LEON3, "GAISLER_LEON3"},
+ {GAISLER_LEON3DSU, "GAISLER_LEON3DSU"},
+ {GAISLER_ETHAHB, "GAISLER_ETHAHB"},
+ {GAISLER_ETHMAC, "GAISLER_ETHMAC"},
+ {GAISLER_APBMST, "GAISLER_APBMST"},
+ {GAISLER_AHBUART, "GAISLER_AHBUART"},
+ {GAISLER_SRCTRL, "GAISLER_SRCTRL"},
+ {GAISLER_SDCTRL, "GAISLER_SDCTRL"},
+ {GAISLER_APBUART, "GAISLER_APBUART"},
+ {GAISLER_IRQMP, "GAISLER_IRQMP"},
+ {GAISLER_AHBRAM, "GAISLER_AHBRAM"},
+ {GAISLER_GPTIMER, "GAISLER_GPTIMER"},
+ {GAISLER_PCITRG, "GAISLER_PCITRG"},
+ {GAISLER_PCISBRG, "GAISLER_PCISBRG"},
+ {GAISLER_PCIFBRG, "GAISLER_PCIFBRG"},
+ {GAISLER_PCITRACE, "GAISLER_PCITRACE"},
+ {GAISLER_AHBTRACE, "GAISLER_AHBTRACE"},
+ {GAISLER_ETHDSU, "GAISLER_ETHDSU"},
+ {GAISLER_PIOPORT, "GAISLER_PIOPORT"},
+ {GAISLER_AHBJTAG, "GAISLER_AHBJTAG"},
+ {GAISLER_ATACTRL, "GAISLER_ATACTRL"},
+ {GAISLER_VGA, "GAISLER_VGA"},
+ {GAISLER_KBD, "GAISLER_KBD"},
+ {GAISLER_L2TIME, "GAISLER_L2TIME"},
+ {GAISLER_L2C, "GAISLER_L2C"},
+ {GAISLER_PLUGPLAY, "GAISLER_PLUGPLAY"},
+ {GAISLER_SPW, "GAISLER_SPW"},
+ {GAISLER_SPW2, "GAISLER_SPW2"},
+ {GAISLER_EHCI, "GAISLER_EHCI"},
+ {GAISLER_UHCI, "GAISLER_UHCI"},
+ {GAISLER_AHBSTAT, "GAISLER_AHBSTAT"},
+ {GAISLER_DDR2SPA, "GAISLER_DDR2SPA"},
+ {GAISLER_DDRSPA, "GAISLER_DDRSPA"},
+ {0, NULL}
+};
+
+static ambapp_device_name esa_devices[] = {
+ {ESA_LEON2, "ESA_LEON2"},
+ {ESA_MCTRL, "ESA_MCTRL"},
+ {0, NULL}
+};
+
+static ambapp_device_name opencores_devices[] = {
+ {OPENCORES_PCIBR, "OPENCORES_PCIBR"},
+ {OPENCORES_ETHMAC, "OPENCORES_ETHMAC"},
+ {0, NULL}
+};
+
+typedef struct {
+ unsigned int vendor_id;
+ char *name;
+ ambapp_device_name *devices;
+} ambapp_vendor_devnames;
+
+static ambapp_vendor_devnames vendors[] = {
+ {VENDOR_GAISLER, "VENDOR_GAISLER", gaisler_devices},
+ {VENDOR_ESA, "VENDOR_ESA", esa_devices},
+ {VENDOR_OPENCORES, "VENDOR_OPENCORES", opencores_devices},
+ {0, NULL, 0}
+};
+
+static char *ambapp_get_devname(ambapp_device_name * devs, int id)
+{
+ if (!devs)
+ return NULL;
+
+ while (devs->device_id > 0) {
+ if (devs->device_id == id)
+ return devs->name;
+ devs++;
+ }
+ return NULL;
+}
+
+char *ambapp_device_id2str(int vendor, int id)
+{
+ ambapp_vendor_devnames *ven = &vendors[0];
+
+ while (ven->vendor_id > 0) {
+ if (ven->vendor_id == vendor) {
+ return ambapp_get_devname(ven->devices, id);
+ }
+ ven++;
+ }
+ return NULL;
+}
+
+char *ambapp_vendor_id2str(int vendor)
+{
+ ambapp_vendor_devnames *ven = &vendors[0];
+
+ while (ven->vendor_id > 0) {
+ if (ven->vendor_id == vendor) {
+ return ven->name;
+ }
+ ven++;
+ }
+ return NULL;
+}
+
+static char *unknown = "unknown";
+
+/* Print one APB device */
+void ambapp_print_apb(apbctrl_pp_dev * apb, ambapp_ahbdev * apbmst, int index)
+{
+ char *dev_str, *ven_str;
+ int irq, ver, vendor, deviceid;
+ unsigned int address, apbmst_base, mask;
+
+ vendor = amba_vendor(apb->conf);
+ deviceid = amba_device(apb->conf);
+ irq = amba_irq(apb->conf);
+ ver = amba_ver(apb->conf);
+ apbmst_base = apbmst->address[0] & LEON3_IO_AREA;
+ address = (apbmst_base | (((apb->bar & 0xfff00000) >> 12))) &
+ (((apb->bar & 0x0000fff0) << 4) | 0xfff00000);
+
+ mask = amba_membar_mask(apb->bar) << 8;
+ mask = ((~mask) & 0x000fffff) + 1;
+
+ ven_str = ambapp_vendor_id2str(vendor);
+ if (!ven_str) {
+ ven_str = unknown;
+ dev_str = unknown;
+ } else {
+ dev_str = ambapp_device_id2str(vendor, deviceid);
+ if (!dev_str)
+ dev_str = unknown;
+ }
+
+ printf("0x%02x:0x%02x:0x%02x: %s %s\n"
+ " apb: 0x%08x - 0x%08x\n"
+ " irq: %-2d (ver: %-2d)\n",
+ index, vendor, deviceid, ven_str, dev_str, address,
+ address + mask, irq, ver);
+}
+
+void ambapp_print_ahb(ahbctrl_pp_dev * ahb, int index)
+{
+ char *dev_str, *ven_str;
+ int irq, ver, vendor, deviceid;
+ unsigned int addr, mask;
+ int j;
+
+ vendor = amba_vendor(ahb->conf);
+ deviceid = amba_device(ahb->conf);
+ irq = amba_irq(ahb->conf);
+ ver = amba_ver(ahb->conf);
+
+ ven_str = ambapp_vendor_id2str(vendor);
+ if (!ven_str) {
+ ven_str = unknown;
+ dev_str = unknown;
+ } else {
+ dev_str = ambapp_device_id2str(vendor, deviceid);
+ if (!dev_str)
+ dev_str = unknown;
+ }
+
+ printf("0x%02x:0x%02x:0x%02x: %s %s\n",
+ index, vendor, deviceid, ven_str, dev_str);
+
+ for (j = 0; j < 4; j++) {
+ addr = amba_membar_start(ahb->bars[j]);
+ if (amba_membar_type(ahb->bars[j]) == 0)
+ continue;
+ if (amba_membar_type(ahb->bars[j]) == AMBA_TYPE_AHBIO)
+ addr = AMBA_TYPE_AHBIO_ADDR(addr);
+ mask = amba_membar_mask(ahb->bars[j]) << 20;
+ printf(" mem: 0x%08x - 0x%08x\n", addr, addr + ((~mask) + 1));
+ }
+
+ printf(" irq: %-2d (ver: %d)\n", irq, ver);
+}
+
+int do_ambapp_print(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+
+ /* Print AHB Masters */
+ puts("--------- AHB Masters ---------\n");
+ ambapp_apb_print = 0;
+ ambapp_ahb_print = 1;
+ ambapp_ahbmst_count(99, 99); /* Get vendor&device 99 = nonexistent... */
+
+ /* Print AHB Slaves */
+ puts("--------- AHB Slaves ---------\n");
+ ambapp_ahbslv_count(99, 99); /* Get vendor&device 99 = nonexistent... */
+
+ /* Print APB Slaves */
+ puts("--------- APB Slaves ---------\n");
+ ambapp_apb_print = 1;
+ ambapp_ahb_print = 0;
+ ambapp_apb_count(99, 99); /* Get vendor&device 99 = nonexistent... */
+
+ /* Reset, no futher printing */
+ ambapp_apb_print = 0;
+ ambapp_ahb_print = 0;
+ puts("\n");
+ return 0;
+}
+
+int ambapp_init_reloc(void)
+{
+ ambapp_vendor_devnames *vend = vendors;
+ ambapp_device_name *dev;
+
+ while (vend->vendor_id && vend->name) {
+ vend->name = (char *)((unsigned int)vend->name + gd->reloc_off);
+ vend->devices =
+ (ambapp_device_name *) ((unsigned int)vend->devices +
+ gd->reloc_off);;
+ dev = vend->devices;
+ vend++;
+ if (!dev)
+ continue;
+ while (dev->device_id && dev->name) {
+ dev->name =
+ (char *)((unsigned int)dev->name + gd->reloc_off);;
+ dev++;
+ }
+ }
+ return 0;
+}
+
+U_BOOT_CMD(
+ ambapp, 1, 1, do_ambapp_print,
+ "list AMBA Plug&Play information",
+ "ambapp\n"
+ " - lists AMBA (AHB & APB) Plug&Play devices present on the system"
+);
diff --git a/u-boot/common/cmd_bdinfo.c b/u-boot/common/cmd_bdinfo.c
new file mode 100644
index 0000000..bba7374
--- /dev/null
+++ b/u-boot/common/cmd_bdinfo.c
@@ -0,0 +1,462 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void print_num(const char *, ulong);
+
+#if !(defined(CONFIG_ARM) || defined(CONFIG_M68K)) || defined(CONFIG_CMD_NET)
+static void print_eth(int idx);
+#endif
+
+#if (!defined(CONFIG_ARM) && !defined(CONFIG_X86))
+static void print_lnum(const char *, u64);
+#endif
+
+#if defined(CONFIG_PPC)
+static void print_str(const char *, const char *);
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ char buf[32];
+
+#ifdef DEBUG
+ print_num ("bd address", (ulong)bd );
+#endif
+ print_num ("memstart", bd->bi_memstart );
+ print_lnum ("memsize", bd->bi_memsize );
+ print_num ("flashstart", bd->bi_flashstart );
+ print_num ("flashsize", bd->bi_flashsize );
+ print_num ("flashoffset", bd->bi_flashoffset );
+ print_num ("sramstart", bd->bi_sramstart );
+ print_num ("sramsize", bd->bi_sramsize );
+#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || \
+ defined(CONFIG_8260) || defined(CONFIG_E500)
+ print_num ("immr_base", bd->bi_immr_base );
+#endif
+ print_num ("bootflags", bd->bi_bootflags );
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_XILINX_405) || \
+ defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ print_str ("procfreq", strmhz(buf, bd->bi_procfreq));
+ print_str ("plb_busfreq", strmhz(buf, bd->bi_plb_busfreq));
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP) || defined(CONFIG_XILINX_405) || \
+ defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ print_str ("pci_busfreq", strmhz(buf, bd->bi_pci_busfreq));
+#endif
+#else /* ! CONFIG_405GP, CONFIG_405CR, CONFIG_405EP, CONFIG_XILINX_405, CONFIG_440EP CONFIG_440GR */
+#if defined(CONFIG_CPM2)
+ print_str ("vco", strmhz(buf, bd->bi_vco));
+ print_str ("sccfreq", strmhz(buf, bd->bi_sccfreq));
+ print_str ("brgfreq", strmhz(buf, bd->bi_brgfreq));
+#endif
+ print_str ("intfreq", strmhz(buf, bd->bi_intfreq));
+#if defined(CONFIG_CPM2)
+ print_str ("cpmfreq", strmhz(buf, bd->bi_cpmfreq));
+#endif
+ print_str ("busfreq", strmhz(buf, bd->bi_busfreq));
+#endif /* CONFIG_405GP, CONFIG_405CR, CONFIG_405EP, CONFIG_XILINX_405, CONFIG_440EP CONFIG_440GR */
+#if defined(CONFIG_MPC8220)
+ print_str ("inpfreq", strmhz(buf, bd->bi_inpfreq));
+ print_str ("flbfreq", strmhz(buf, bd->bi_flbfreq));
+ print_str ("pcifreq", strmhz(buf, bd->bi_pcifreq));
+ print_str ("vcofreq", strmhz(buf, bd->bi_vcofreq));
+ print_str ("pevfreq", strmhz(buf, bd->bi_pevfreq));
+#endif
+
+ print_eth(0);
+#if defined(CONFIG_HAS_ETH1)
+ print_eth(1);
+#endif
+#if defined(CONFIG_HAS_ETH2)
+ print_eth(2);
+#endif
+#if defined(CONFIG_HAS_ETH3)
+ print_eth(3);
+#endif
+#if defined(CONFIG_HAS_ETH4)
+ print_eth(4);
+#endif
+#if defined(CONFIG_HAS_ETH5)
+ print_eth(5);
+#endif
+
+#ifdef CONFIG_HERMES
+ print_str ("ethspeed", strmhz(buf, bd->bi_ethspeed));
+#endif
+ printf ("IP addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %6ld bps\n", bd->bi_baudrate );
+ print_num ("relocaddr", gd->relocaddr);
+ return 0;
+}
+
+#elif defined(CONFIG_NIOS2)
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+
+ print_num ("mem start", (ulong)bd->bi_memstart);
+ print_lnum ("mem size", (u64)bd->bi_memsize);
+ print_num ("flash start", (ulong)bd->bi_flashstart);
+ print_num ("flash size", (ulong)bd->bi_flashsize);
+ print_num ("flash offset", (ulong)bd->bi_flashoffset);
+
+#if defined(CONFIG_SYS_SRAM_BASE)
+ print_num ("sram start", (ulong)bd->bi_sramstart);
+ print_num ("sram size", (ulong)bd->bi_sramsize);
+#endif
+
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+
+ printf ("baudrate = %ld bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#elif defined(CONFIG_MICROBLAZE)
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ print_num ("mem start ", (ulong)bd->bi_memstart);
+ print_lnum ("mem size ", (u64)bd->bi_memsize);
+ print_num ("flash start ", (ulong)bd->bi_flashstart);
+ print_num ("flash size ", (ulong)bd->bi_flashsize);
+ print_num ("flash offset ", (ulong)bd->bi_flashoffset);
+#if defined(CONFIG_SYS_SRAM_BASE)
+ print_num ("sram start ", (ulong)bd->bi_sramstart);
+ print_num ("sram size ", (ulong)bd->bi_sramsize);
+#endif
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+ printf ("baudrate = %ld bps\n", (ulong)bd->bi_baudrate);
+ return 0;
+}
+
+#elif defined(CONFIG_SPARC)
+
+int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+
+#ifdef DEBUG
+ print_num("bd address ", (ulong) bd);
+#endif
+ print_num("memstart ", bd->bi_memstart);
+ print_lnum("memsize ", bd->bi_memsize);
+ print_num("flashstart ", bd->bi_flashstart);
+ print_num("CONFIG_SYS_MONITOR_BASE ", CONFIG_SYS_MONITOR_BASE);
+ print_num("CONFIG_ENV_ADDR ", CONFIG_ENV_ADDR);
+ printf("CONFIG_SYS_RELOC_MONITOR_BASE = 0x%lx (%d)\n", CONFIG_SYS_RELOC_MONITOR_BASE,
+ CONFIG_SYS_MONITOR_LEN);
+ printf("CONFIG_SYS_MALLOC_BASE = 0x%lx (%d)\n", CONFIG_SYS_MALLOC_BASE,
+ CONFIG_SYS_MALLOC_LEN);
+ printf("CONFIG_SYS_INIT_SP_OFFSET = 0x%lx (%d)\n", CONFIG_SYS_INIT_SP_OFFSET,
+ CONFIG_SYS_STACK_SIZE);
+ printf("CONFIG_SYS_PROM_OFFSET = 0x%lx (%d)\n", CONFIG_SYS_PROM_OFFSET,
+ CONFIG_SYS_PROM_SIZE);
+ printf("CONFIG_SYS_GBL_DATA_OFFSET = 0x%lx (%d)\n", CONFIG_SYS_GBL_DATA_OFFSET,
+ GENERATED_GBL_DATA_SIZE);
+
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+ printf("baudrate = %6ld bps\n", bd->bi_baudrate);
+ return 0;
+}
+
+#elif defined(CONFIG_M68K)
+
+static void print_str(const char *, const char *);
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ char buf[32];
+
+ print_num ("memstart", (ulong)bd->bi_memstart);
+ print_lnum ("memsize", (u64)bd->bi_memsize);
+ print_num ("flashstart", (ulong)bd->bi_flashstart);
+ print_num ("flashsize", (ulong)bd->bi_flashsize);
+ print_num ("flashoffset", (ulong)bd->bi_flashoffset);
+#if defined(CONFIG_SYS_INIT_RAM_ADDR)
+ print_num ("sramstart", (ulong)bd->bi_sramstart);
+ print_num ("sramsize", (ulong)bd->bi_sramsize);
+#endif
+#if defined(CONFIG_SYS_MBAR)
+ print_num ("mbar", bd->bi_mbar_base);
+#endif
+ print_str ("cpufreq", strmhz(buf, bd->bi_intfreq));
+ print_str ("busfreq", strmhz(buf, bd->bi_busfreq));
+#ifdef CONFIG_PCI
+ print_str ("pcifreq", strmhz(buf, bd->bi_pcifreq));
+#endif
+#ifdef CONFIG_EXTRA_CLOCK
+ print_str ("flbfreq", strmhz(buf, bd->bi_flbfreq));
+ print_str ("inpfreq", strmhz(buf, bd->bi_inpfreq));
+ print_str ("vcofreq", strmhz(buf, bd->bi_vcofreq));
+#endif
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+#if defined(CONFIG_HAS_ETH1)
+ print_eth(1);
+#endif
+#if defined(CONFIG_HAS_ETH2)
+ print_eth(2);
+#endif
+#if defined(CONFIG_HAS_ETH3)
+ print_eth(3);
+#endif
+
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+ printf ("baudrate = %ld bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#elif defined(CONFIG_BLACKFIN)
+
+static void print_str(const char *, const char *);
+
+int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ char buf[32];
+
+ printf("U-Boot = %s\n", bd->bi_r_version);
+ printf("CPU = %s\n", bd->bi_cpu);
+ printf("Board = %s\n", bd->bi_board_name);
+ print_str("VCO", strmhz(buf, bd->bi_vco));
+ print_str("CCLK", strmhz(buf, bd->bi_cclk));
+ print_str("SCLK", strmhz(buf, bd->bi_sclk));
+
+ print_num("boot_params", (ulong)bd->bi_boot_params);
+ print_num("memstart", (ulong)bd->bi_memstart);
+ print_lnum("memsize", (u64)bd->bi_memsize);
+ print_num("flashstart", (ulong)bd->bi_flashstart);
+ print_num("flashsize", (ulong)bd->bi_flashsize);
+ print_num("flashoffset", (ulong)bd->bi_flashoffset);
+
+ print_eth(0);
+ printf("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf("baudrate = %d bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#elif defined(CONFIG_MIPS)
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+
+ print_num ("boot_params", (ulong)bd->bi_boot_params);
+ print_num ("memstart", (ulong)bd->bi_memstart);
+ print_lnum ("memsize", (u64)bd->bi_memsize);
+ print_num ("flashstart", (ulong)bd->bi_flashstart);
+ print_num ("flashsize", (ulong)bd->bi_flashsize);
+ print_num ("flashoffset", (ulong)bd->bi_flashoffset);
+
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %d bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#elif defined(CONFIG_AVR32)
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ bd_t *bd = gd->bd;
+
+ print_num ("boot_params", (ulong)bd->bi_boot_params);
+ print_num ("memstart", (ulong)bd->bi_memstart);
+ print_lnum ("memsize", (u64)bd->bi_memsize);
+ print_num ("flashstart", (ulong)bd->bi_flashstart);
+ print_num ("flashsize", (ulong)bd->bi_flashsize);
+ print_num ("flashoffset", (ulong)bd->bi_flashoffset);
+
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %lu bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#elif defined(CONFIG_ARM)
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ bd_t *bd = gd->bd;
+
+ print_num ("arch_number", bd->bi_arch_number);
+ print_num ("boot_params", (ulong)bd->bi_boot_params);
+
+ for (i=0; i<CONFIG_NR_DRAM_BANKS; ++i) {
+ print_num("DRAM bank", i);
+ print_num("-> start", bd->bi_dram[i].start);
+ print_num("-> size", bd->bi_dram[i].size);
+ }
+
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+ printf ("baudrate = %d bps\n", bd->bi_baudrate);
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+ print_num ("TLB addr", gd->tlb_addr);
+#endif
+ print_num ("relocaddr", gd->relocaddr);
+ print_num ("reloc off", gd->reloc_off);
+ print_num ("irq_sp", gd->irq_sp); /* irq stack pointer */
+ print_num ("sp start ", gd->start_addr_sp);
+ print_num ("FB base ", gd->fb_base);
+ return 0;
+}
+
+#elif defined(CONFIG_SH)
+
+int do_bdinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ print_num ("mem start ", (ulong)bd->bi_memstart);
+ print_lnum ("mem size ", (u64)bd->bi_memsize);
+ print_num ("flash start ", (ulong)bd->bi_flashstart);
+ print_num ("flash size ", (ulong)bd->bi_flashsize);
+ print_num ("flash offset ", (ulong)bd->bi_flashoffset);
+
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+#endif
+ printf ("baudrate = %ld bps\n", (ulong)bd->bi_baudrate);
+ return 0;
+}
+
+#elif defined(CONFIG_X86)
+
+static void print_str(const char *, const char *);
+
+int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ bd_t *bd = gd->bd;
+ char buf[32];
+
+ print_num ("boot_params", (ulong)bd->bi_boot_params);
+ print_num ("bi_memstart", bd->bi_memstart);
+ print_num ("bi_memsize", bd->bi_memsize);
+ print_num ("bi_flashstart", bd->bi_flashstart);
+ print_num ("bi_flashsize", bd->bi_flashsize);
+ print_num ("bi_flashoffset", bd->bi_flashoffset);
+ print_num ("bi_sramstart", bd->bi_sramstart);
+ print_num ("bi_sramsize", bd->bi_sramsize);
+ print_num ("bi_bootflags", bd->bi_bootflags);
+ print_str ("cpufreq", strmhz(buf, bd->bi_intfreq));
+ print_str ("busfreq", strmhz(buf, bd->bi_busfreq));
+
+ for (i=0; i<CONFIG_NR_DRAM_BANKS; ++i) {
+ print_num("DRAM bank", i);
+ print_num("-> start", bd->bi_dram[i].start);
+ print_num("-> size", bd->bi_dram[i].size);
+ }
+
+#if defined(CONFIG_CMD_NET)
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ print_str ("ethspeed", strmhz(buf, bd->bi_ethspeed));
+#endif
+ printf ("baudrate = %d bps\n", bd->bi_baudrate);
+
+ return 0;
+}
+
+#else
+ #error "a case for this architecture does not exist!"
+#endif
+
+static void print_num(const char *name, ulong value)
+{
+ printf ("%-12s= 0x%08lX\n", name, value);
+}
+
+#if !(defined(CONFIG_ARM) || defined(CONFIG_M68K)) || defined(CONFIG_CMD_NET)
+static void print_eth(int idx)
+{
+ char name[10], *val;
+ if (idx)
+ sprintf(name, "eth%iaddr", idx);
+ else
+ strcpy(name, "ethaddr");
+ val = getenv(name);
+ if (!val)
+ val = "(not set)";
+ printf("%-12s= %s\n", name, val);
+}
+#endif
+
+#if (!defined(CONFIG_ARM) && !defined(CONFIG_X86))
+static void print_lnum(const char *name, u64 value)
+{
+ printf ("%-12s= 0x%.8llX\n", name, value);
+}
+#endif
+
+#if defined(CONFIG_PPC) || \
+ defined(CONFIG_M68K) || \
+ defined(CONFIG_BLACKFIN) || \
+ defined(CONFIG_X86)
+static void print_str(const char *name, const char *str)
+{
+ printf ("%-12s= %6s MHz\n", name, str);
+}
+#endif /* CONFIG_PPC */
+
+
+/* -------------------------------------------------------------------- */
+
+U_BOOT_CMD(
+ bdinfo, 1, 1, do_bdinfo,
+ "print Board Info structure",
+ ""
+);
diff --git a/u-boot/common/cmd_bedbug.c b/u-boot/common/cmd_bedbug.c
new file mode 100644
index 0000000..2bd62e2
--- /dev/null
+++ b/u-boot/common/cmd_bedbug.c
@@ -0,0 +1,421 @@
+/*
+ * BedBug Functions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <net.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void show_regs __P ((struct pt_regs *));
+extern int run_command __P ((const char *, int));
+extern char console_buffer[];
+
+ulong dis_last_addr = 0; /* Last address disassembled */
+ulong dis_last_len = 20; /* Default disassembler length */
+CPU_DEBUG_CTX bug_ctx; /* Bedbug context structure */
+
+
+/* ======================================================================
+ * U-Boot's puts function does not append a newline, so the bedbug stuff
+ * will use this for the output of the dis/assembler.
+ * ====================================================================== */
+
+int bedbug_puts (const char *str)
+{
+ /* -------------------------------------------------- */
+
+ printf ("%s\r\n", str);
+ return 0;
+} /* bedbug_puts */
+
+
+
+/* ======================================================================
+ * Initialize the bug_ctx structure used by the bedbug debugger. This is
+ * specific to the CPU since each has different debug registers and
+ * settings.
+ * ====================================================================== */
+
+void bedbug_init (void)
+{
+ /* -------------------------------------------------- */
+
+#if defined(CONFIG_4xx)
+ void bedbug405_init (void);
+
+ bedbug405_init ();
+#elif defined(CONFIG_8xx)
+ void bedbug860_init (void);
+
+ bedbug860_init ();
+#endif
+
+#if defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260)
+ /* Processors that are 603e core based */
+ void bedbug603e_init (void);
+
+ bedbug603e_init ();
+#endif
+
+ return;
+} /* bedbug_init */
+
+
+
+/* ======================================================================
+ * Entry point from the interpreter to the disassembler. Repeated calls
+ * will resume from the last disassembled address.
+ * ====================================================================== */
+int do_bedbug_dis (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr; /* Address to start disassembly from */
+ ulong len; /* # of instructions to disassemble */
+
+ /* -------------------------------------------------- */
+
+ /* Setup to go from the last address if none is given */
+ addr = dis_last_addr;
+ len = dis_last_len;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command */
+ addr = simple_strtoul (argv[1], NULL, 16);
+
+ /* If an extra param is given then it is the length */
+ if (argc > 2)
+ len = simple_strtoul (argv[2], NULL, 16);
+ }
+
+ /* Run the disassembler */
+ disppc ((unsigned char *) addr, 0, len, bedbug_puts, F_RADHEX);
+
+ dis_last_addr = addr + (len * 4);
+ dis_last_len = len;
+ return 0;
+} /* do_bedbug_dis */
+
+U_BOOT_CMD (ds, 3, 1, do_bedbug_dis,
+ "disassemble memory",
+ "ds <address> [# instructions]");
+
+/* ======================================================================
+ * Entry point from the interpreter to the assembler. Assembles
+ * instructions in consecutive memory locations until a '.' (period) is
+ * entered on a line by itself.
+ * ====================================================================== */
+int do_bedbug_asm (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ long mem_addr; /* Address to assemble into */
+ unsigned long instr; /* Machine code for text */
+ char prompt[15]; /* Prompt string for user input */
+ int asm_err; /* Error code from the assembler */
+
+ /* -------------------------------------------------- */
+ int rcode = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ printf ("\nEnter '.' when done\n");
+ mem_addr = simple_strtoul (argv[1], NULL, 16);
+
+ while (1) {
+ putc ('\n');
+ disppc ((unsigned char *) mem_addr, 0, 1, bedbug_puts,
+ F_RADHEX);
+
+ sprintf (prompt, "%08lx: ", mem_addr);
+ readline (prompt);
+
+ if (console_buffer[0] && strcmp (console_buffer, ".")) {
+ if ((instr =
+ asmppc (mem_addr, console_buffer,
+ &asm_err)) != 0) {
+ *(unsigned long *) mem_addr = instr;
+ mem_addr += 4;
+ } else {
+ printf ("*** Error: %s ***\n",
+ asm_error_str (asm_err));
+ rcode = 1;
+ }
+ } else {
+ break;
+ }
+ }
+ return rcode;
+} /* do_bedbug_asm */
+
+U_BOOT_CMD (as, 2, 0, do_bedbug_asm,
+ "assemble memory", "as <address>");
+
+/* ======================================================================
+ * Used to set a break point from the interpreter. Simply calls into the
+ * CPU-specific break point set routine.
+ * ====================================================================== */
+
+int do_bedbug_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ /* -------------------------------------------------- */
+ if (bug_ctx.do_break)
+ (*bug_ctx.do_break) (cmdtp, flag, argc, argv);
+ return 0;
+
+} /* do_bedbug_break */
+
+U_BOOT_CMD (break, 3, 0, do_bedbug_break,
+ "set or clear a breakpoint",
+ " - Set or clear a breakpoint\n"
+ "break <address> - Break at an address\n"
+ "break off <bp#> - Disable breakpoint.\n"
+ "break show - List breakpoints.");
+
+/* ======================================================================
+ * Called from the debug interrupt routine. Simply calls the CPU-specific
+ * breakpoint handling routine.
+ * ====================================================================== */
+
+void do_bedbug_breakpoint (struct pt_regs *regs)
+{
+ /* -------------------------------------------------- */
+
+ if (bug_ctx.break_isr)
+ (*bug_ctx.break_isr) (regs);
+
+ return;
+} /* do_bedbug_breakpoint */
+
+
+
+/* ======================================================================
+ * Called from the CPU-specific breakpoint handling routine. Enter a
+ * mini main loop until the stopped flag is cleared from the breakpoint
+ * context.
+ *
+ * This handles the parts of the debugger that are common to all CPU's.
+ * ====================================================================== */
+
+void bedbug_main_loop (unsigned long addr, struct pt_regs *regs)
+{
+ int len; /* Length of command line */
+ int flag; /* Command flags */
+ int rc = 0; /* Result from run_command */
+ char prompt_str[20]; /* Prompt string */
+ static char lastcommand[CONFIG_SYS_CBSIZE] = { 0 }; /* previous command */
+ /* -------------------------------------------------- */
+
+ if (bug_ctx.clear)
+ (*bug_ctx.clear) (bug_ctx.current_bp);
+
+ printf ("Breakpoint %d: ", bug_ctx.current_bp);
+ disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
+
+ bug_ctx.stopped = 1;
+ bug_ctx.regs = regs;
+
+ sprintf (prompt_str, "BEDBUG.%d =>", bug_ctx.current_bp);
+
+ /* A miniature main loop */
+ while (bug_ctx.stopped) {
+ len = readline (prompt_str);
+
+ flag = 0; /* assume no special flags for now */
+
+ if (len > 0)
+ strcpy (lastcommand, console_buffer);
+ else if (len == 0)
+ flag |= CMD_FLAG_REPEAT;
+
+ if (len == -1)
+ printf ("<INTERRUPT>\n");
+ else
+ rc = run_command (lastcommand, flag);
+
+ if (rc <= 0) {
+ /* invalid command or not repeatable, forget it */
+ lastcommand[0] = 0;
+ }
+ }
+
+ bug_ctx.regs = NULL;
+ bug_ctx.current_bp = 0;
+
+ return;
+} /* bedbug_main_loop */
+
+
+
+/* ======================================================================
+ * Interpreter command to continue from a breakpoint. Just clears the
+ * stopped flag in the context so that the breakpoint routine will
+ * return.
+ * ====================================================================== */
+int do_bedbug_continue (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ /* -------------------------------------------------- */
+
+ if (!bug_ctx.stopped) {
+ printf ("Not at a breakpoint\n");
+ return 1;
+ }
+
+ bug_ctx.stopped = 0;
+ return 0;
+} /* do_bedbug_continue */
+
+U_BOOT_CMD (continue, 1, 0, do_bedbug_continue,
+ "continue from a breakpoint",
+ "");
+
+/* ======================================================================
+ * Interpreter command to continue to the next instruction, stepping into
+ * subroutines. Works by calling the find_next_addr() routine to compute
+ * the address passes control to the CPU-specific set breakpoint routine
+ * for the current breakpoint number.
+ * ====================================================================== */
+int do_bedbug_step (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr; /* Address to stop at */
+
+ /* -------------------------------------------------- */
+
+ if (!bug_ctx.stopped) {
+ printf ("Not at a breakpoint\n");
+ return 1;
+ }
+
+ if (!find_next_address ((unsigned char *) &addr, FALSE, bug_ctx.regs))
+ return 1;
+
+ if (bug_ctx.set)
+ (*bug_ctx.set) (bug_ctx.current_bp, addr);
+
+ bug_ctx.stopped = 0;
+ return 0;
+} /* do_bedbug_step */
+
+U_BOOT_CMD (step, 1, 1, do_bedbug_step,
+ "single step execution.",
+ "");
+
+/* ======================================================================
+ * Interpreter command to continue to the next instruction, stepping over
+ * subroutines. Works by calling the find_next_addr() routine to compute
+ * the address passes control to the CPU-specific set breakpoint routine
+ * for the current breakpoint number.
+ * ====================================================================== */
+int do_bedbug_next (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr; /* Address to stop at */
+
+ /* -------------------------------------------------- */
+
+ if (!bug_ctx.stopped) {
+ printf ("Not at a breakpoint\n");
+ return 1;
+ }
+
+ if (!find_next_address ((unsigned char *) &addr, TRUE, bug_ctx.regs))
+ return 1;
+
+ if (bug_ctx.set)
+ (*bug_ctx.set) (bug_ctx.current_bp, addr);
+
+ bug_ctx.stopped = 0;
+ return 0;
+} /* do_bedbug_next */
+
+U_BOOT_CMD (next, 1, 1, do_bedbug_next,
+ "single step execution, stepping over subroutines.",
+ "");
+
+/* ======================================================================
+ * Interpreter command to print the current stack. This assumes an EABI
+ * architecture, so it starts with GPR R1 and works back up the stack.
+ * ====================================================================== */
+int do_bedbug_stack (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long sp; /* Stack pointer */
+ unsigned long func; /* LR from stack */
+ int depth; /* Stack iteration level */
+ int skip = 1; /* Flag to skip the first entry */
+ unsigned long top; /* Top of memory address */
+
+ /* -------------------------------------------------- */
+
+ if (!bug_ctx.stopped) {
+ printf ("Not at a breakpoint\n");
+ return 1;
+ }
+
+ top = gd->bd->bi_memstart + gd->bd->bi_memsize;
+ depth = 0;
+
+ printf ("Depth PC\n");
+ printf ("----- --------\n");
+ printf ("%5d %08lx\n", depth++, bug_ctx.regs->nip);
+
+ sp = bug_ctx.regs->gpr[1];
+ func = *(unsigned long *) (sp + 4);
+
+ while ((func < top) && (sp < top)) {
+ if (!skip)
+ printf ("%5d %08lx\n", depth++, func);
+ else
+ --skip;
+
+ sp = *(unsigned long *) sp;
+ func = *(unsigned long *) (sp + 4);
+ }
+ return 0;
+} /* do_bedbug_stack */
+
+U_BOOT_CMD (where, 1, 1, do_bedbug_stack,
+ "Print the running stack.",
+ "");
+
+/* ======================================================================
+ * Interpreter command to dump the registers. Calls the CPU-specific
+ * show registers routine.
+ * ====================================================================== */
+int do_bedbug_rdump (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ /* -------------------------------------------------- */
+
+ if (!bug_ctx.stopped) {
+ printf ("Not at a breakpoint\n");
+ return 1;
+ }
+
+ show_regs (bug_ctx.regs);
+ return 0;
+} /* do_bedbug_rdump */
+
+U_BOOT_CMD (rdump, 1, 1, do_bedbug_rdump,
+ "Show registers.", "");
+/* ====================================================================== */
+
+
+/*
+ * Copyright (c) 2001 William L. Pitts
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
diff --git a/u-boot/common/cmd_bmp.c b/u-boot/common/cmd_bmp.c
new file mode 100644
index 0000000..23fc82f
--- /dev/null
+++ b/u-boot/common/cmd_bmp.c
@@ -0,0 +1,255 @@
+/*
+ * (C) Copyright 2002
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * BMP handling routines
+ */
+
+#include <common.h>
+#include <lcd.h>
+#include <bmp_layout.h>
+#include <command.h>
+#include <asm/byteorder.h>
+#include <malloc.h>
+
+static int bmp_info (ulong addr);
+static int bmp_display (ulong addr, int x, int y);
+
+/*
+ * Allocate and decompress a BMP image using gunzip().
+ *
+ * Returns a pointer to the decompressed image data. Must be freed by
+ * the caller after use.
+ *
+ * Returns NULL if decompression failed, or if the decompressed data
+ * didn't contain a valid BMP signature.
+ */
+#ifdef CONFIG_VIDEO_BMP_GZIP
+bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp)
+{
+ void *dst;
+ unsigned long len;
+ bmp_image_t *bmp;
+
+ /*
+ * Decompress bmp image
+ */
+ len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
+ dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
+ if (dst == NULL) {
+ puts("Error: malloc in gunzip failed!\n");
+ return NULL;
+ }
+ if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)addr, &len) != 0) {
+ free(dst);
+ return NULL;
+ }
+ if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)
+ puts("Image could be truncated"
+ " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
+
+ bmp = dst;
+
+ /*
+ * Check for bmp mark 'BM'
+ */
+ if (!((bmp->header.signature[0] == 'B') &&
+ (bmp->header.signature[1] == 'M'))) {
+ free(dst);
+ return NULL;
+ }
+
+ debug("Gzipped BMP image detected!\n");
+
+ return bmp;
+}
+#else
+bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp)
+{
+ return NULL;
+}
+#endif
+
+static int do_bmp_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr;
+
+ switch (argc) {
+ case 1: /* use load_addr as default address */
+ addr = load_addr;
+ break;
+ case 2: /* use argument */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ return (bmp_info(addr));
+}
+
+static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr;
+ int x = 0, y = 0;
+
+ switch (argc) {
+ case 1: /* use load_addr as default address */
+ addr = load_addr;
+ break;
+ case 2: /* use argument */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ break;
+ case 4:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ x = simple_strtoul(argv[2], NULL, 10);
+ y = simple_strtoul(argv[3], NULL, 10);
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ return (bmp_display(addr, x, y));
+}
+
+static cmd_tbl_t cmd_bmp_sub[] = {
+ U_BOOT_CMD_MKENT(info, 3, 0, do_bmp_info, "", ""),
+ U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""),
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+void bmp_reloc(void) {
+ fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub));
+}
+#endif
+
+/*
+ * Subroutine: do_bmp
+ *
+ * Description: Handler for 'bmp' command..
+ *
+ * Inputs: argv[1] contains the subcommand
+ *
+ * Return: None
+ *
+ */
+static int do_bmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ /* Strip off leading 'bmp' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ bmp, 5, 1, do_bmp,
+ "manipulate BMP image data",
+ "info <imageAddr> - display image info\n"
+ "bmp display <imageAddr> [x y] - display image at x,y"
+);
+
+/*
+ * Subroutine: bmp_info
+ *
+ * Description: Show information about bmp file in memory
+ *
+ * Inputs: addr address of the bmp file
+ *
+ * Return: None
+ *
+ */
+static int bmp_info(ulong addr)
+{
+ bmp_image_t *bmp=(bmp_image_t *)addr;
+ unsigned long len;
+
+ if (!((bmp->header.signature[0]=='B') &&
+ (bmp->header.signature[1]=='M')))
+ bmp = gunzip_bmp(addr, &len);
+
+ if (bmp == NULL) {
+ printf("There is no valid bmp file at the given address\n");
+ return 1;
+ }
+
+ printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width),
+ le32_to_cpu(bmp->header.height));
+ printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count));
+ printf("Compression : %d\n", le32_to_cpu(bmp->header.compression));
+
+ if ((unsigned long)bmp != addr)
+ free(bmp);
+
+ return(0);
+}
+
+/*
+ * Subroutine: bmp_display
+ *
+ * Description: Display bmp file located in memory
+ *
+ * Inputs: addr address of the bmp file
+ *
+ * Return: None
+ *
+ */
+static int bmp_display(ulong addr, int x, int y)
+{
+ int ret;
+ bmp_image_t *bmp = (bmp_image_t *)addr;
+ unsigned long len;
+
+ if (!((bmp->header.signature[0]=='B') &&
+ (bmp->header.signature[1]=='M')))
+ bmp = gunzip_bmp(addr, &len);
+
+ if (!bmp) {
+ printf("There is no valid bmp file at the given address\n");
+ return 1;
+ }
+
+#if defined(CONFIG_LCD)
+ extern int lcd_display_bitmap (ulong, int, int);
+
+ ret = lcd_display_bitmap ((unsigned long)bmp, x, y);
+#elif defined(CONFIG_VIDEO)
+ extern int video_display_bitmap (ulong, int, int);
+
+ ret = video_display_bitmap ((unsigned long)bmp, x, y);
+#else
+# error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO
+#endif
+
+ if ((unsigned long)bmp != addr)
+ free(bmp);
+
+ return ret;
+}
diff --git a/u-boot/common/cmd_boot.c b/u-boot/common/cmd_boot.c
new file mode 100644
index 0000000..7b603d3
--- /dev/null
+++ b/u-boot/common/cmd_boot.c
@@ -0,0 +1,74 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Misc boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+
+/* Allow ports to override the default behavior */
+__attribute__((weak))
+unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
+{
+ return entry (argc, argv);
+}
+
+int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, rc;
+ int rcode = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ printf ("## Starting application at 0x%08lX ...\n", addr);
+
+ /*
+ * pass address parameter as argv[0] (aka command name),
+ * and all remaining args
+ */
+ rc = do_go_exec ((void *)addr, argc - 1, argv + 1);
+ if (rc != 0) rcode = 1;
+
+ printf ("## Application terminated, rc = 0x%lX\n", rc);
+ return rcode;
+}
+
+/* -------------------------------------------------------------------- */
+
+U_BOOT_CMD(
+ go, CONFIG_SYS_MAXARGS, 1, do_go,
+ "start application at address 'addr'",
+ "addr [arg ...]\n - start application at address 'addr'\n"
+ " passing 'arg' as arguments"
+);
+
+U_BOOT_CMD(
+ reset, 1, 0, do_reset,
+ "Perform RESET of the CPU",
+ ""
+);
diff --git a/u-boot/common/cmd_bootldr.c b/u-boot/common/cmd_bootldr.c
new file mode 100644
index 0000000..535b931
--- /dev/null
+++ b/u-boot/common/cmd_bootldr.c
@@ -0,0 +1,175 @@
+/*
+ * U-boot - bootldr.c
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/bootrom.h>
+
+/* Simple sanity check on the specified address to make sure it contains
+ * an LDR image of some sort.
+ */
+static bool ldr_valid_signature(uint8_t *data)
+{
+#if defined(__ADSPBF561__)
+
+ /* BF56x has a 4 byte global header */
+ if (data[3] == 0xA0)
+ return true;
+
+#elif defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \
+ defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) || \
+ defined(__ADSPBF538__) || defined(__ADSPBF539__)
+
+ /* all the BF53x should start at this address mask */
+ uint32_t addr;
+ memmove(&addr, data, sizeof(addr));
+ if ((addr & 0xFF0FFF0F) == 0xFF000000)
+ return true;
+#else
+
+ /* everything newer has a magic byte */
+ uint32_t count;
+ memmove(&count, data + 8, sizeof(count));
+ if (data[3] == 0xAD && count == 0)
+ return true;
+
+#endif
+
+ return false;
+}
+
+/* If the Blackfin is new enough, the Blackfin on-chip ROM supports loading
+ * LDRs from random memory addresses. So whenever possible, use that. In
+ * the older cases (BF53x/BF561), parse the LDR format ourselves.
+ */
+#define ZEROFILL 0x0001
+#define RESVECT 0x0002
+#define INIT 0x0008
+#define IGNORE 0x0010
+#define FINAL 0x8000
+static void ldr_load(uint8_t *base_addr)
+{
+#if defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \
+ /*defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) ||*/\
+ defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__)
+
+ uint32_t addr;
+ uint32_t count;
+ uint16_t flags;
+
+ /* the bf56x has a 4 byte global header ... but it is useless to
+ * us when booting an LDR from a memory address, so skip it
+ */
+# ifdef __ADSPBF561__
+ base_addr += 4;
+# endif
+
+ memmove(&flags, base_addr + 8, sizeof(flags));
+ bfin_write_EVT1(flags & RESVECT ? 0xFFA00000 : 0xFFA08000);
+
+ do {
+ /* block header may not be aligned */
+ memmove(&addr, base_addr, sizeof(addr));
+ memmove(&count, base_addr+4, sizeof(count));
+ memmove(&flags, base_addr+8, sizeof(flags));
+ base_addr += sizeof(addr) + sizeof(count) + sizeof(flags);
+
+ printf("loading to 0x%08x (0x%x bytes) flags: 0x%04x\n",
+ addr, count, flags);
+
+ if (!(flags & IGNORE)) {
+ if (flags & ZEROFILL)
+ memset((void *)addr, 0x00, count);
+ else
+ memcpy((void *)addr, base_addr, count);
+
+ if (flags & INIT) {
+ void (*init)(void) = (void *)addr;
+ init();
+ }
+ }
+
+ if (!(flags & ZEROFILL))
+ base_addr += count;
+ } while (!(flags & FINAL));
+
+#endif
+}
+
+/* For BF537, we use the _BOOTROM_BOOT_DXE_FLASH funky ROM function.
+ * For all other BF53x/BF56x, we just call the entry point.
+ * For everything else (newer), we use _BOOTROM_MEMBOOT ROM function.
+ */
+static void ldr_exec(void *addr)
+{
+#if defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__)
+
+ /* restore EVT1 to reset value as this is what the bootrom uses as
+ * the default entry point when booting the final block of LDRs
+ */
+ bfin_write_EVT1(L1_INST_SRAM);
+ __asm__("call (%0);" : : "a"(_BOOTROM_MEMBOOT), "q7"(addr) : "RETS", "memory");
+
+#elif defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \
+ defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__)
+
+ void (*ldr_entry)(void) = (void *)bfin_read_EVT1();
+ ldr_entry();
+
+#else
+
+ int32_t (*BOOTROM_MEM)(void *, int32_t, int32_t, void *) = (void *)_BOOTROM_MEMBOOT;
+ BOOTROM_MEM(addr, 0, 0, NULL);
+
+#endif
+}
+
+/*
+ * the bootldr command loads an address, checks to see if there
+ * is a Boot stream that the on-chip BOOTROM can understand,
+ * and loads it via the BOOTROM Callback. It is possible
+ * to also add booting from SPI, or TWI, but this function does
+ * not currently support that.
+ */
+int do_bootldr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ void *addr;
+
+ /* Get the address */
+ if (argc < 2)
+ addr = (void *)load_addr;
+ else
+ addr = (void *)simple_strtoul(argv[1], NULL, 16);
+
+ /* Check if it is a LDR file */
+ if (ldr_valid_signature(addr)) {
+ printf("## Booting ldr image at 0x%p ...\n", addr);
+ ldr_load(addr);
+
+ icache_disable();
+ dcache_disable();
+
+ ldr_exec(addr);
+ } else
+ printf("## No ldr image at address 0x%p\n", addr);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ bootldr, 2, 0, do_bootldr,
+ "boot ldr image from memory",
+ "[addr]\n"
+ ""
+);
diff --git a/u-boot/common/cmd_bootm.c b/u-boot/common/cmd_bootm.c
new file mode 100644
index 0000000..18019d6
--- /dev/null
+++ b/u-boot/common/cmd_bootm.c
@@ -0,0 +1,1500 @@
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <image.h>
+#include <malloc.h>
+#include <u-boot/zlib.h>
+#include <bzlib.h>
+#include <environment.h>
+#include <lmb.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_CMD_USB)
+#include <usb.h>
+#endif
+
+#ifdef CONFIG_SYS_HUSH_PARSER
+#include <hush.h>
+#endif
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <fdt.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#ifdef CONFIG_LZMA
+#include <lzma/LzmaTypes.h>
+#include <lzma/LzmaDec.h>
+#include <lzma/LzmaTools.h>
+#endif /* CONFIG_LZMA */
+
+#ifdef CONFIG_LZO
+#include <linux/lzo.h>
+#endif /* CONFIG_LZO */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_BOOTM_LEN
+#define CONFIG_SYS_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */
+#endif
+
+#ifdef CONFIG_BZIP2
+extern void bz_internal_error(int);
+#endif
+
+#if defined(CONFIG_CMD_IMI)
+static int image_info (unsigned long addr);
+#endif
+
+#if defined(CONFIG_CMD_IMLS)
+#include <flash.h>
+#include <mtd/cfi_flash.h>
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+static int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+
+#ifdef CONFIG_SILENT_CONSOLE
+static void fixup_silent_linux (void);
+#endif
+
+static image_header_t *image_get_kernel (ulong img_addr, int verify);
+#if defined(CONFIG_FIT)
+static int fit_check_kernel (const void *fit, int os_noffset, int verify);
+#endif
+
+static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag,int argc, char * const argv[],
+ bootm_headers_t *images, ulong *os_data, ulong *os_len);
+
+/*
+ * Continue booting an OS image; caller already has:
+ * - copied image header to global variable `header'
+ * - checked header magic number, checksums (both header & image),
+ * - verified image architecture (PPC) and type (KERNEL or MULTI),
+ * - loaded (first part of) image to header load address,
+ * - disabled interrupts.
+ */
+typedef int boot_os_fn (int flag, int argc, char * const argv[],
+ bootm_headers_t *images); /* pointers to os/initrd/fdt */
+
+#ifdef CONFIG_BOOTM_LINUX
+extern boot_os_fn do_bootm_linux;
+#endif
+#ifdef CONFIG_BOOTM_NETBSD
+static boot_os_fn do_bootm_netbsd;
+#endif
+#if defined(CONFIG_LYNXKDI)
+static boot_os_fn do_bootm_lynxkdi;
+extern void lynxkdi_boot (image_header_t *);
+#endif
+#ifdef CONFIG_BOOTM_RTEMS
+static boot_os_fn do_bootm_rtems;
+#endif
+#if defined(CONFIG_BOOTM_OSE)
+static boot_os_fn do_bootm_ose;
+#endif
+#if defined(CONFIG_CMD_ELF)
+static boot_os_fn do_bootm_vxworks;
+static boot_os_fn do_bootm_qnxelf;
+int do_bootvx (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+#if defined(CONFIG_INTEGRITY)
+static boot_os_fn do_bootm_integrity;
+#endif
+
+static boot_os_fn *boot_os[] = {
+#ifdef CONFIG_BOOTM_LINUX
+ [IH_OS_LINUX] = do_bootm_linux,
+#endif
+#ifdef CONFIG_BOOTM_NETBSD
+ [IH_OS_NETBSD] = do_bootm_netbsd,
+#endif
+#ifdef CONFIG_LYNXKDI
+ [IH_OS_LYNXOS] = do_bootm_lynxkdi,
+#endif
+#ifdef CONFIG_BOOTM_RTEMS
+ [IH_OS_RTEMS] = do_bootm_rtems,
+#endif
+#if defined(CONFIG_BOOTM_OSE)
+ [IH_OS_OSE] = do_bootm_ose,
+#endif
+#if defined(CONFIG_CMD_ELF)
+ [IH_OS_VXWORKS] = do_bootm_vxworks,
+ [IH_OS_QNX] = do_bootm_qnxelf,
+#endif
+#ifdef CONFIG_INTEGRITY
+ [IH_OS_INTEGRITY] = do_bootm_integrity,
+#endif
+};
+
+static bootm_headers_t images; /* pointers to os/initrd/fdt images */
+
+/* Allow for arch specific config before we boot */
+void __arch_preboot_os(void)
+{
+ /* please define platform specific arch_preboot_os() */
+}
+void arch_preboot_os(void) __attribute__((weak, alias("__arch_preboot_os")));
+
+#if defined(__ARM__)
+ #define IH_INITRD_ARCH IH_ARCH_ARM
+#elif defined(__avr32__)
+ #define IH_INITRD_ARCH IH_ARCH_AVR32
+#elif defined(__bfin__)
+ #define IH_INITRD_ARCH IH_ARCH_BLACKFIN
+#elif defined(__I386__)
+ #define IH_INITRD_ARCH IH_ARCH_I386
+#elif defined(__M68K__)
+ #define IH_INITRD_ARCH IH_ARCH_M68K
+#elif defined(__microblaze__)
+ #define IH_INITRD_ARCH IH_ARCH_MICROBLAZE
+#elif defined(__mips__)
+ #define IH_INITRD_ARCH IH_ARCH_MIPS
+#elif defined(__nios2__)
+ #define IH_INITRD_ARCH IH_ARCH_NIOS2
+#elif defined(__PPC__)
+ #define IH_INITRD_ARCH IH_ARCH_PPC
+#elif defined(__sh__)
+ #define IH_INITRD_ARCH IH_ARCH_SH
+#elif defined(__sparc__)
+ #define IH_INITRD_ARCH IH_ARCH_SPARC
+#else
+# error Unknown CPU type
+#endif
+
+static void bootm_start_lmb(void)
+{
+#ifdef CONFIG_LMB
+ ulong mem_start;
+ phys_size_t mem_size;
+
+ lmb_init(&images.lmb);
+
+ mem_start = getenv_bootm_low();
+ mem_size = getenv_bootm_size();
+
+ lmb_add(&images.lmb, (phys_addr_t)mem_start, mem_size);
+
+ arch_lmb_reserve(&images.lmb);
+ board_lmb_reserve(&images.lmb);
+#else
+# define lmb_reserve(lmb, base, size)
+#endif
+}
+
+static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ void *os_hdr;
+ int ret;
+
+ memset ((void *)&images, 0, sizeof (images));
+ images.verify = getenv_yesno ("verify");
+
+ bootm_start_lmb();
+
+ /* get kernel image header, start address and length */
+ os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
+ &images, &images.os.image_start, &images.os.image_len);
+ if (images.os.image_len == 0) {
+ puts ("ERROR: can't get kernel image!\n");
+ return 1;
+ }
+
+ /* get image parameters */
+ switch (genimg_get_format (os_hdr)) {
+ case IMAGE_FORMAT_LEGACY:
+ images.os.type = image_get_type (os_hdr);
+ images.os.comp = image_get_comp (os_hdr);
+ images.os.os = image_get_os (os_hdr);
+
+ images.os.end = image_get_image_end (os_hdr);
+ images.os.load = image_get_load (os_hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ if (fit_image_get_type (images.fit_hdr_os,
+ images.fit_noffset_os, &images.os.type)) {
+ puts ("Can't get image type!\n");
+ show_boot_progress (-109);
+ return 1;
+ }
+
+ if (fit_image_get_comp (images.fit_hdr_os,
+ images.fit_noffset_os, &images.os.comp)) {
+ puts ("Can't get image compression!\n");
+ show_boot_progress (-110);
+ return 1;
+ }
+
+ if (fit_image_get_os (images.fit_hdr_os,
+ images.fit_noffset_os, &images.os.os)) {
+ puts ("Can't get image OS!\n");
+ show_boot_progress (-111);
+ return 1;
+ }
+
+ images.os.end = fit_get_end (images.fit_hdr_os);
+
+ if (fit_image_get_load (images.fit_hdr_os, images.fit_noffset_os,
+ &images.os.load)) {
+ puts ("Can't get image load address!\n");
+ show_boot_progress (-112);
+ return 1;
+ }
+ break;
+#endif
+ default:
+ puts ("ERROR: unknown image format type!\n");
+ return 1;
+ }
+
+ /* find kernel entry point */
+ if (images.legacy_hdr_valid) {
+ images.ep = image_get_ep (&images.legacy_hdr_os_copy);
+#if defined(CONFIG_FIT)
+ } else if (images.fit_uname_os) {
+ ret = fit_image_get_entry (images.fit_hdr_os,
+ images.fit_noffset_os, &images.ep);
+ if (ret) {
+ puts ("Can't get entry point property!\n");
+ return 1;
+ }
+#endif
+ } else {
+ puts ("Could not find kernel entry point!\n");
+ return 1;
+ }
+
+ if (((images.os.type == IH_TYPE_KERNEL) ||
+ (images.os.type == IH_TYPE_MULTI)) &&
+ (images.os.os == IH_OS_LINUX)) {
+ /* find ramdisk */
+ ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,
+ &images.rd_start, &images.rd_end);
+ if (ret) {
+ puts ("Ramdisk image is corrupt or invalid\n");
+ return 1;
+ }
+
+#if defined(CONFIG_OF_LIBFDT)
+ /* find flattened device tree */
+ ret = boot_get_fdt (flag, argc, argv, &images,
+ &images.ft_addr, &images.ft_len);
+ if (ret) {
+ puts ("Could not find a valid device tree\n");
+ return 1;
+ }
+
+ set_working_fdt_addr(images.ft_addr);
+#endif
+ }
+
+ images.os.start = (ulong)os_hdr;
+ images.state = BOOTM_STATE_START;
+
+ return 0;
+}
+
+#define BOOTM_ERR_RESET -1
+#define BOOTM_ERR_OVERLAP -2
+#define BOOTM_ERR_UNIMPLEMENTED -3
+static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
+{
+ uint8_t comp = os.comp;
+ ulong load = os.load;
+ ulong blob_start = os.start;
+ ulong blob_end = os.end;
+ ulong image_start = os.image_start;
+ ulong image_len = os.image_len;
+ uint unc_len = CONFIG_SYS_BOOTM_LEN;
+#if defined(CONFIG_LZMA) || defined(CONFIG_LZO)
+ int ret;
+#endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */
+
+ const char *type_name = genimg_get_type_name (os.type);
+
+ switch (comp) {
+ case IH_COMP_NONE:
+ if (load == blob_start) {
+ printf (" XIP %s ... ", type_name);
+ } else {
+ printf (" Loading %s ... ", type_name);
+ memmove_wd ((void *)load, (void *)image_start,
+ image_len, CHUNKSZ);
+ }
+ *load_end = load + image_len;
+ puts("OK\n");
+ break;
+#ifdef CONFIG_GZIP
+ case IH_COMP_GZIP:
+ printf (" Uncompressing %s ... ", type_name);
+ if (gunzip ((void *)load, unc_len,
+ (uchar *)image_start, &image_len) != 0) {
+ puts ("GUNZIP: uncompress, out-of-mem or overwrite error "
+ "- must RESET board to recover\n");
+ if (boot_progress)
+ show_boot_progress (-6);
+ return BOOTM_ERR_RESET;
+ }
+
+ *load_end = load + image_len;
+ break;
+#endif /* CONFIG_GZIP */
+#ifdef CONFIG_BZIP2
+ case IH_COMP_BZIP2:
+ printf (" Uncompressing %s ... ", type_name);
+ /*
+ * If we've got less than 4 MB of malloc() space,
+ * use slower decompression algorithm which requires
+ * at most 2300 KB of memory.
+ */
+ int i = BZ2_bzBuffToBuffDecompress ((char*)load,
+ &unc_len, (char *)image_start, image_len,
+ CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
+ if (i != BZ_OK) {
+ printf ("BUNZIP2: uncompress or overwrite error %d "
+ "- must RESET board to recover\n", i);
+ if (boot_progress)
+ show_boot_progress (-6);
+ return BOOTM_ERR_RESET;
+ }
+
+ *load_end = load + unc_len;
+ break;
+#endif /* CONFIG_BZIP2 */
+#ifdef CONFIG_LZMA
+ case IH_COMP_LZMA: {
+ SizeT lzma_len = unc_len;
+ printf (" Uncompressing %s ... ", type_name);
+
+ ret = lzmaBuffToBuffDecompress(
+ (unsigned char *)load, &lzma_len,
+ (unsigned char *)image_start, image_len);
+ unc_len = lzma_len;
+ if (ret != SZ_OK) {
+ printf ("LZMA: uncompress or overwrite error %d "
+ "- must RESET board to recover\n", ret);
+ show_boot_progress (-6);
+ return BOOTM_ERR_RESET;
+ }
+ *load_end = load + unc_len;
+ break;
+ }
+#endif /* CONFIG_LZMA */
+#ifdef CONFIG_LZO
+ case IH_COMP_LZO:
+ printf (" Uncompressing %s ... ", type_name);
+
+ ret = lzop_decompress((const unsigned char *)image_start,
+ image_len, (unsigned char *)load,
+ &unc_len);
+ if (ret != LZO_E_OK) {
+ printf ("LZO: uncompress or overwrite error %d "
+ "- must RESET board to recover\n", ret);
+ if (boot_progress)
+ show_boot_progress (-6);
+ return BOOTM_ERR_RESET;
+ }
+
+ *load_end = load + unc_len;
+ break;
+#endif /* CONFIG_LZO */
+ default:
+ printf ("Unimplemented compression type %d\n", comp);
+ return BOOTM_ERR_UNIMPLEMENTED;
+ }
+ puts ("OK\n");
+ debug (" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end);
+ if (boot_progress)
+ show_boot_progress (7);
+
+ if ((load < blob_end) && (*load_end > blob_start)) {
+ debug ("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end);
+ debug ("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end);
+
+ return BOOTM_ERR_OVERLAP;
+ }
+
+ return 0;
+}
+
+static int bootm_start_standalone(ulong iflag, int argc, char * const argv[])
+{
+ char *s;
+ int (*appl)(int, char * const []);
+
+ /* Don't start if "autostart" is set to "no" */
+ if (((s = getenv("autostart")) != NULL) && (strcmp(s, "no") == 0)) {
+ char buf[32];
+ sprintf(buf, "%lX", images.os.image_len);
+ setenv("filesize", buf);
+ return 0;
+ }
+ appl = (int (*)(int, char * const []))ntohl(images.ep);
+ (*appl)(argc-1, &argv[1]);
+
+ return 0;
+}
+
+/* we overload the cmd field with our state machine info instead of a
+ * function pointer */
+static cmd_tbl_t cmd_bootm_sub[] = {
+ U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
+ U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+ U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
+#endif
+#ifdef CONFIG_OF_LIBFDT
+ U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
+ U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
+ U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
+ U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
+};
+
+int do_bootm_subcommand (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int ret = 0;
+ int state;
+ cmd_tbl_t *c;
+ boot_os_fn *boot_fn;
+
+ c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
+
+ if (c) {
+ state = (int)c->cmd;
+
+ /* treat start special since it resets the state machine */
+ if (state == BOOTM_STATE_START) {
+ argc--;
+ argv++;
+ return bootm_start(cmdtp, flag, argc, argv);
+ }
+ } else {
+ /* Unrecognized command */
+ return cmd_usage(cmdtp);
+ }
+
+ if (images.state >= state) {
+ printf ("Trying to execute a command out of order\n");
+ return cmd_usage(cmdtp);
+ }
+
+ images.state |= state;
+ boot_fn = boot_os[images.os.os];
+
+ switch (state) {
+ ulong load_end;
+ case BOOTM_STATE_START:
+ /* should never occur */
+ break;
+ case BOOTM_STATE_LOADOS:
+ ret = bootm_load_os(images.os, &load_end, 0);
+ if (ret)
+ return ret;
+
+ lmb_reserve(&images.lmb, images.os.load,
+ (load_end - images.os.load));
+ break;
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+ case BOOTM_STATE_RAMDISK:
+ {
+ ulong rd_len = images.rd_end - images.rd_start;
+ char str[17];
+
+ ret = boot_ramdisk_high(&images.lmb, images.rd_start,
+ rd_len, &images.initrd_start, &images.initrd_end);
+ if (ret)
+ return ret;
+
+ sprintf(str, "%lx", images.initrd_start);
+ setenv("initrd_start", str);
+ sprintf(str, "%lx", images.initrd_end);
+ setenv("initrd_end", str);
+ }
+ break;
+#endif
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_SYS_BOOTMAPSZ)
+ case BOOTM_STATE_FDT:
+ {
+ ulong bootmap_base = getenv_bootm_low();
+ ret = boot_relocate_fdt(&images.lmb, bootmap_base,
+ &images.ft_addr, &images.ft_len);
+ break;
+ }
+#endif
+ case BOOTM_STATE_OS_CMDLINE:
+ ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images);
+ if (ret)
+ printf ("cmdline subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_BD_T:
+ ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images);
+ if (ret)
+ printf ("bdt subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_PREP:
+ ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images);
+ if (ret)
+ printf ("prep subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_GO:
+ disable_interrupts();
+ arch_preboot_os();
+ boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************************/
+/* bootm - boot application image from image in memory */
+/*******************************************************************/
+
+int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong iflag;
+ ulong load_end = 0;
+ int ret;
+ boot_os_fn *boot_fn;
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ static int relocated = 0;
+
+ /* relocate boot function table */
+ if (!relocated) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(boot_os); i++)
+ if (boot_os[i] != NULL)
+ boot_os[i] += gd->reloc_off;
+ relocated = 1;
+ }
+#endif
+
+ /* determine if we have a sub command */
+ if (argc > 1) {
+ char *endp;
+
+ simple_strtoul(argv[1], &endp, 16);
+ /* endp pointing to NULL means that argv[1] was just a
+ * valid number, pass it along to the normal bootm processing
+ *
+ * If endp is ':' or '#' assume a FIT identifier so pass
+ * along for normal processing.
+ *
+ * Right now we assume the first arg should never be '-'
+ */
+ if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
+ return do_bootm_subcommand(cmdtp, flag, argc, argv);
+ }
+
+ if (bootm_start(cmdtp, flag, argc, argv))
+ return 1;
+
+ /*
+ * We have reached the point of no return: we are going to
+ * overwrite all exception vector code, so we cannot easily
+ * recover from any failures any more...
+ */
+ iflag = disable_interrupts();
+
+#if defined(CONFIG_CMD_USB)
+ /*
+ * turn off USB to prevent the host controller from writing to the
+ * SDRAM while Linux is booting. This could happen (at least for OHCI
+ * controller), because the HCCA (Host Controller Communication Area)
+ * lies within the SDRAM and the host controller writes continously to
+ * this area (as busmaster!). The HccaFrameNumber is for example
+ * updated every 1 ms within the HCCA structure in SDRAM! For more
+ * details see the OpenHCI specification.
+ */
+ usb_stop();
+#endif
+
+ ret = bootm_load_os(images.os, &load_end, 1);
+
+ if (ret < 0) {
+ if (ret == BOOTM_ERR_RESET)
+ do_reset (cmdtp, flag, argc, argv);
+ if (ret == BOOTM_ERR_OVERLAP) {
+ if (images.legacy_hdr_valid) {
+ if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
+ puts ("WARNING: legacy format multi component "
+ "image overwritten\n");
+ } else {
+ puts ("ERROR: new format image overwritten - "
+ "must RESET the board to recover\n");
+ show_boot_progress (-113);
+ do_reset (cmdtp, flag, argc, argv);
+ }
+ }
+ if (ret == BOOTM_ERR_UNIMPLEMENTED) {
+ if (iflag)
+ enable_interrupts();
+ show_boot_progress (-7);
+ return 1;
+ }
+ }
+
+ lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
+
+ if (images.os.type == IH_TYPE_STANDALONE) {
+ if (iflag)
+ enable_interrupts();
+ /* This may return when 'autostart' is 'no' */
+ bootm_start_standalone(iflag, argc, argv);
+ return 0;
+ }
+
+ show_boot_progress (8);
+
+#ifdef CONFIG_SILENT_CONSOLE
+ if (images.os.os == IH_OS_LINUX)
+ fixup_silent_linux();
+#endif
+
+ boot_fn = boot_os[images.os.os];
+
+ if (boot_fn == NULL) {
+ if (iflag)
+ enable_interrupts();
+ printf ("ERROR: booting os '%s' (%d) is not supported\n",
+ genimg_get_os_name(images.os.os), images.os.os);
+ show_boot_progress (-8);
+ return 1;
+ }
+
+ arch_preboot_os();
+
+ boot_fn(0, argc, argv, &images);
+
+ show_boot_progress (-9);
+#ifdef DEBUG
+ puts ("\n## Control returned to monitor - resetting...\n");
+#endif
+ do_reset (cmdtp, flag, argc, argv);
+
+ return 1;
+}
+
+/**
+ * image_get_kernel - verify legacy format kernel image
+ * @img_addr: in RAM address of the legacy format image to be verified
+ * @verify: data CRC verification flag
+ *
+ * image_get_kernel() verifies legacy image integrity and returns pointer to
+ * legacy image header if image verification was completed successfully.
+ *
+ * returns:
+ * pointer to a legacy image header if valid image was found
+ * otherwise return NULL
+ */
+static image_header_t *image_get_kernel (ulong img_addr, int verify)
+{
+ image_header_t *hdr = (image_header_t *)img_addr;
+
+ if (!image_check_magic(hdr)) {
+ puts ("Bad Magic Number\n");
+ show_boot_progress (-1);
+ return NULL;
+ }
+ show_boot_progress (2);
+
+ if (!image_check_hcrc (hdr)) {
+ puts ("Bad Header Checksum\n");
+ show_boot_progress (-2);
+ return NULL;
+ }
+
+ show_boot_progress (3);
+ image_print_contents (hdr);
+
+ if (verify) {
+ puts (" Verifying Checksum ... ");
+ if (!image_check_dcrc (hdr)) {
+ printf ("Bad Data CRC\n");
+ show_boot_progress (-3);
+ return NULL;
+ }
+ puts ("OK\n");
+ }
+ show_boot_progress (4);
+
+ if (!image_check_target_arch (hdr)) {
+ printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
+ show_boot_progress (-4);
+ return NULL;
+ }
+ return hdr;
+}
+
+/**
+ * fit_check_kernel - verify FIT format kernel subimage
+ * @fit_hdr: pointer to the FIT image header
+ * os_noffset: kernel subimage node offset within FIT image
+ * @verify: data CRC verification flag
+ *
+ * fit_check_kernel() verifies integrity of the kernel subimage and from
+ * specified FIT image.
+ *
+ * returns:
+ * 1, on success
+ * 0, on failure
+ */
+#if defined (CONFIG_FIT)
+static int fit_check_kernel (const void *fit, int os_noffset, int verify)
+{
+ fit_image_print (fit, os_noffset, " ");
+
+ if (verify) {
+ puts (" Verifying Hash Integrity ... ");
+ if (!fit_image_check_hashes (fit, os_noffset)) {
+ puts ("Bad Data Hash\n");
+ show_boot_progress (-104);
+ return 0;
+ }
+ puts ("OK\n");
+ }
+ show_boot_progress (105);
+
+ if (!fit_image_check_target_arch (fit, os_noffset)) {
+ puts ("Unsupported Architecture\n");
+ show_boot_progress (-105);
+ return 0;
+ }
+
+ show_boot_progress (106);
+ if (!fit_image_check_type (fit, os_noffset, IH_TYPE_KERNEL)) {
+ puts ("Not a kernel image\n");
+ show_boot_progress (-106);
+ return 0;
+ }
+
+ show_boot_progress (107);
+ return 1;
+}
+#endif /* CONFIG_FIT */
+
+/**
+ * boot_get_kernel - find kernel image
+ * @os_data: pointer to a ulong variable, will hold os data start address
+ * @os_len: pointer to a ulong variable, will hold os data length
+ *
+ * boot_get_kernel() tries to find a kernel image, verifies its integrity
+ * and locates kernel data.
+ *
+ * returns:
+ * pointer to image header if valid image was found, plus kernel start
+ * address and length, otherwise NULL
+ */
+static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ bootm_headers_t *images, ulong *os_data, ulong *os_len)
+{
+ image_header_t *hdr;
+ ulong img_addr;
+#if defined(CONFIG_FIT)
+ void *fit_hdr;
+ const char *fit_uname_config = NULL;
+ const char *fit_uname_kernel = NULL;
+ const void *data;
+ size_t len;
+ int cfg_noffset;
+ int os_noffset;
+#endif
+
+ /* find out kernel image address */
+ if (argc < 2) {
+ img_addr = load_addr;
+ debug ("* kernel: default image load address = 0x%08lx\n",
+ load_addr);
+#if defined(CONFIG_FIT)
+ } else if (fit_parse_conf (argv[1], load_addr, &img_addr,
+ &fit_uname_config)) {
+ debug ("* kernel: config '%s' from image at 0x%08lx\n",
+ fit_uname_config, img_addr);
+ } else if (fit_parse_subimage (argv[1], load_addr, &img_addr,
+ &fit_uname_kernel)) {
+ debug ("* kernel: subimage '%s' from image at 0x%08lx\n",
+ fit_uname_kernel, img_addr);
+#endif
+ } else {
+ img_addr = simple_strtoul(argv[1], NULL, 16);
+ debug ("* kernel: cmdline image address = 0x%08lx\n", img_addr);
+ }
+
+ show_boot_progress (1);
+
+ /* copy from dataflash if needed */
+ img_addr = genimg_get_image (img_addr);
+
+ /* check image type, for FIT images get FIT kernel node */
+ *os_data = *os_len = 0;
+ switch (genimg_get_format ((void *)img_addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ printf ("## Booting kernel from Legacy Image at %08lx ...\n",
+ img_addr);
+ hdr = image_get_kernel (img_addr, images->verify);
+ if (!hdr)
+ return NULL;
+ show_boot_progress (5);
+
+ /* get os_data and os_len */
+ switch (image_get_type (hdr)) {
+ case IH_TYPE_KERNEL:
+ *os_data = image_get_data (hdr);
+ *os_len = image_get_data_size (hdr);
+ break;
+ case IH_TYPE_MULTI:
+ image_multi_getimg (hdr, 0, os_data, os_len);
+ break;
+ case IH_TYPE_STANDALONE:
+ *os_data = image_get_data (hdr);
+ *os_len = image_get_data_size (hdr);
+ break;
+ default:
+ printf ("Wrong Image Type for %s command\n", cmdtp->name);
+ show_boot_progress (-5);
+ return NULL;
+ }
+
+ /*
+ * copy image header to allow for image overwrites during kernel
+ * decompression.
+ */
+ memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));
+
+ /* save pointer to image header */
+ images->legacy_hdr_os = hdr;
+
+ images->legacy_hdr_valid = 1;
+ show_boot_progress (6);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (void *)img_addr;
+ printf ("## Booting kernel from FIT Image at %08lx ...\n",
+ img_addr);
+
+ if (!fit_check_format (fit_hdr)) {
+ puts ("Bad FIT kernel image format!\n");
+ show_boot_progress (-100);
+ return NULL;
+ }
+ show_boot_progress (100);
+
+ if (!fit_uname_kernel) {
+ /*
+ * no kernel image node unit name, try to get config
+ * node first. If config unit node name is NULL
+ * fit_conf_get_node() will try to find default config node
+ */
+ show_boot_progress (101);
+ cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);
+ if (cfg_noffset < 0) {
+ show_boot_progress (-101);
+ return NULL;
+ }
+ /* save configuration uname provided in the first
+ * bootm argument
+ */
+ images->fit_uname_cfg = fdt_get_name (fit_hdr, cfg_noffset, NULL);
+ printf (" Using '%s' configuration\n", images->fit_uname_cfg);
+ show_boot_progress (103);
+
+ os_noffset = fit_conf_get_kernel_node (fit_hdr, cfg_noffset);
+ fit_uname_kernel = fit_get_name (fit_hdr, os_noffset, NULL);
+ } else {
+ /* get kernel component image node offset */
+ show_boot_progress (102);
+ os_noffset = fit_image_get_node (fit_hdr, fit_uname_kernel);
+ }
+ if (os_noffset < 0) {
+ show_boot_progress (-103);
+ return NULL;
+ }
+
+ printf (" Trying '%s' kernel subimage\n", fit_uname_kernel);
+
+ show_boot_progress (104);
+ if (!fit_check_kernel (fit_hdr, os_noffset, images->verify))
+ return NULL;
+
+ /* get kernel image data address and length */
+ if (fit_image_get_data (fit_hdr, os_noffset, &data, &len)) {
+ puts ("Could not find kernel subimage data!\n");
+ show_boot_progress (-107);
+ return NULL;
+ }
+ show_boot_progress (108);
+
+ *os_len = len;
+ *os_data = (ulong)data;
+ images->fit_hdr_os = fit_hdr;
+ images->fit_uname_os = fit_uname_kernel;
+ images->fit_noffset_os = os_noffset;
+ break;
+#endif
+ default:
+ printf ("Wrong Image Format for %s command\n", cmdtp->name);
+ show_boot_progress (-108);
+ return NULL;
+ }
+
+ debug (" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
+ *os_data, *os_len, *os_len);
+
+ return (void *)img_addr;
+}
+
+U_BOOT_CMD(
+ bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
+ "boot application image from memory",
+ "[addr [arg ...]]\n - boot application image stored in memory\n"
+ "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
+ "\t'arg' can be the address of an initrd image\n"
+#if defined(CONFIG_OF_LIBFDT)
+ "\tWhen booting a Linux kernel which requires a flat device-tree\n"
+ "\ta third argument is required which is the address of the\n"
+ "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
+ "\tuse a '-' for the second argument. If you do not pass a third\n"
+ "\ta bd_info struct will be passed instead\n"
+#endif
+#if defined(CONFIG_FIT)
+ "\t\nFor the new multi component uImage format (FIT) addresses\n"
+ "\tmust be extened to include component or configuration unit name:\n"
+ "\taddr:<subimg_uname> - direct component image specification\n"
+ "\taddr#<conf_uname> - configuration specification\n"
+ "\tUse iminfo command to get the list of existing component\n"
+ "\timages and configurations.\n"
+#endif
+ "\nSub-commands to do part of the bootm sequence. The sub-commands "
+ "must be\n"
+ "issued in the order below (it's ok to not issue all sub-commands):\n"
+ "\tstart [addr [arg ...]]\n"
+ "\tloados - load OS image\n"
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
+ "\tramdisk - relocate initrd, set env initrd_start/initrd_end\n"
+#endif
+#if defined(CONFIG_OF_LIBFDT)
+ "\tfdt - relocate flat device tree\n"
+#endif
+ "\tcmdline - OS specific command line processing/setup\n"
+ "\tbdt - OS specific bd_t processing\n"
+ "\tprep - OS specific prep before relocation or go\n"
+ "\tgo - start OS"
+);
+
+/*******************************************************************/
+/* bootd - boot default image */
+/*******************************************************************/
+#if defined(CONFIG_CMD_BOOTD)
+int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int rcode = 0;
+
+#ifndef CONFIG_SYS_HUSH_PARSER
+ if (run_command (getenv ("bootcmd"), flag) < 0)
+ rcode = 1;
+#else
+ if (parse_string_outer (getenv ("bootcmd"),
+ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+ rcode = 1;
+#endif
+ return rcode;
+}
+
+U_BOOT_CMD(
+ boot, 1, 1, do_bootd,
+ "boot default, i.e., run 'bootcmd'",
+ ""
+);
+
+/* keep old command name "bootd" for backward compatibility */
+U_BOOT_CMD(
+ bootd, 1, 1, do_bootd,
+ "boot default, i.e., run 'bootcmd'",
+ ""
+);
+
+#endif
+
+
+/*******************************************************************/
+/* iminfo - print header info for a requested image */
+/*******************************************************************/
+#if defined(CONFIG_CMD_IMI)
+int do_iminfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int arg;
+ ulong addr;
+ int rcode = 0;
+
+ if (argc < 2) {
+ return image_info (load_addr);
+ }
+
+ for (arg = 1; arg < argc; ++arg) {
+ addr = simple_strtoul (argv[arg], NULL, 16);
+ if (image_info (addr) != 0)
+ rcode = 1;
+ }
+ return rcode;
+}
+
+static int image_info (ulong addr)
+{
+ void *hdr = (void *)addr;
+
+ printf ("\n## Checking Image at %08lx ...\n", addr);
+
+ switch (genimg_get_format (hdr)) {
+ case IMAGE_FORMAT_LEGACY:
+ puts (" Legacy image found\n");
+ if (!image_check_magic (hdr)) {
+ puts (" Bad Magic Number\n");
+ return 1;
+ }
+
+ if (!image_check_hcrc (hdr)) {
+ puts (" Bad Header Checksum\n");
+ return 1;
+ }
+
+ image_print_contents (hdr);
+
+ puts (" Verifying Checksum ... ");
+ if (!image_check_dcrc (hdr)) {
+ puts (" Bad Data CRC\n");
+ return 1;
+ }
+ puts ("OK\n");
+ return 0;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ puts (" FIT image found\n");
+
+ if (!fit_check_format (hdr)) {
+ puts ("Bad FIT image format!\n");
+ return 1;
+ }
+
+ fit_print_contents (hdr);
+
+ if (!fit_all_image_check_hashes (hdr)) {
+ puts ("Bad hash in FIT image!\n");
+ return 1;
+ }
+
+ return 0;
+#endif
+ default:
+ puts ("Unknown image format!\n");
+ break;
+ }
+
+ return 1;
+}
+
+U_BOOT_CMD(
+ iminfo, CONFIG_SYS_MAXARGS, 1, do_iminfo,
+ "print header information for application image",
+ "addr [addr ...]\n"
+ " - print header information for application image starting at\n"
+ " address 'addr' in memory; this includes verification of the\n"
+ " image contents (magic number, header and payload checksums)"
+);
+#endif
+
+
+/*******************************************************************/
+/* imls - list all images found in flash */
+/*******************************************************************/
+#if defined(CONFIG_CMD_IMLS)
+int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ flash_info_t *info;
+ int i, j;
+ void *hdr;
+
+ for (i = 0, info = &flash_info[0];
+ i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ goto next_bank;
+ for (j = 0; j < info->sector_count; ++j) {
+
+ hdr = (void *)info->start[j];
+ if (!hdr)
+ goto next_sector;
+
+ switch (genimg_get_format (hdr)) {
+ case IMAGE_FORMAT_LEGACY:
+ if (!image_check_hcrc (hdr))
+ goto next_sector;
+
+ printf ("Legacy Image at %08lX:\n", (ulong)hdr);
+ image_print_contents (hdr);
+
+ puts (" Verifying Checksum ... ");
+ if (!image_check_dcrc (hdr)) {
+ puts ("Bad Data CRC\n");
+ } else {
+ puts ("OK\n");
+ }
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ if (!fit_check_format (hdr))
+ goto next_sector;
+
+ printf ("FIT Image at %08lX:\n", (ulong)hdr);
+ fit_print_contents (hdr);
+ break;
+#endif
+ default:
+ goto next_sector;
+ }
+
+next_sector: ;
+ }
+next_bank: ;
+ }
+
+ return (0);
+}
+
+U_BOOT_CMD(
+ imls, 1, 1, do_imls,
+ "list all images found in flash",
+ "\n"
+ " - Prints information about all images found at sector\n"
+ " boundaries in flash."
+);
+#endif
+
+/*******************************************************************/
+/* helper routines */
+/*******************************************************************/
+#ifdef CONFIG_SILENT_CONSOLE
+static void fixup_silent_linux ()
+{
+ char buf[256], *start, *end;
+ char *cmdline = getenv ("bootargs");
+
+ /* Only fix cmdline when requested */
+ if (!(gd->flags & GD_FLG_SILENT))
+ return;
+
+ debug ("before silent fix-up: %s\n", cmdline);
+ if (cmdline) {
+ if ((start = strstr (cmdline, "console=")) != NULL) {
+ end = strchr (start, ' ');
+ strncpy (buf, cmdline, (start - cmdline + 8));
+ if (end)
+ strcpy (buf + (start - cmdline + 8), end);
+ else
+ buf[start - cmdline + 8] = '\0';
+ } else {
+ strcpy (buf, cmdline);
+ strcat (buf, " console=");
+ }
+ } else {
+ strcpy (buf, "console=");
+ }
+
+ setenv ("bootargs", buf);
+ debug ("after silent fix-up: %s\n", buf);
+}
+#endif /* CONFIG_SILENT_CONSOLE */
+
+
+/*******************************************************************/
+/* OS booting routines */
+/*******************************************************************/
+
+#ifdef CONFIG_BOOTM_NETBSD
+static int do_bootm_netbsd (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ void (*loader)(bd_t *, image_header_t *, char *, char *);
+ image_header_t *os_hdr, *hdr;
+ ulong kernel_data, kernel_len;
+ char *consdev;
+ char *cmdline;
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("NetBSD");
+ return 1;
+ }
+#endif
+ hdr = images->legacy_hdr_os;
+
+ /*
+ * Booting a (NetBSD) kernel image
+ *
+ * This process is pretty similar to a standalone application:
+ * The (first part of an multi-) image must be a stage-2 loader,
+ * which in turn is responsible for loading & invoking the actual
+ * kernel. The only differences are the parameters being passed:
+ * besides the board info strucure, the loader expects a command
+ * line, the name of the console device, and (optionally) the
+ * address of the original image header.
+ */
+ os_hdr = NULL;
+ if (image_check_type (&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
+ image_multi_getimg (hdr, 1, &kernel_data, &kernel_len);
+ if (kernel_len)
+ os_hdr = hdr;
+ }
+
+ consdev = "";
+#if defined (CONFIG_8xx_CONS_SMC1)
+ consdev = "smc1";
+#elif defined (CONFIG_8xx_CONS_SMC2)
+ consdev = "smc2";
+#elif defined (CONFIG_8xx_CONS_SCC2)
+ consdev = "scc2";
+#elif defined (CONFIG_8xx_CONS_SCC3)
+ consdev = "scc3";
+#endif
+
+ if (argc > 2) {
+ ulong len;
+ int i;
+
+ for (i = 2, len = 0; i < argc; i += 1)
+ len += strlen (argv[i]) + 1;
+ cmdline = malloc (len);
+
+ for (i = 2, len = 0; i < argc; i += 1) {
+ if (i > 2)
+ cmdline[len++] = ' ';
+ strcpy (&cmdline[len], argv[i]);
+ len += strlen (argv[i]);
+ }
+ } else if ((cmdline = getenv ("bootargs")) == NULL) {
+ cmdline = "";
+ }
+
+ loader = (void (*)(bd_t *, image_header_t *, char *, char *))images->ep;
+
+ printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
+ (ulong)loader);
+
+ show_boot_progress (15);
+
+ /*
+ * NetBSD Stage-2 Loader Parameters:
+ * r3: ptr to board info data
+ * r4: image address
+ * r5: console device
+ * r6: boot args string
+ */
+ (*loader) (gd->bd, os_hdr, consdev, cmdline);
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_NETBSD*/
+
+#ifdef CONFIG_LYNXKDI
+static int do_bootm_lynxkdi (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ image_header_t *hdr = &images->legacy_hdr_os_copy;
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("Lynx");
+ return 1;
+ }
+#endif
+
+ lynxkdi_boot ((image_header_t *)hdr);
+
+ return 1;
+}
+#endif /* CONFIG_LYNXKDI */
+
+#ifdef CONFIG_BOOTM_RTEMS
+static int do_bootm_rtems (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(bd_t *);
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("RTEMS");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(bd_t *))images->ep;
+
+ printf ("## Transferring control to RTEMS (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ show_boot_progress (15);
+
+ /*
+ * RTEMS Parameters:
+ * r3: ptr to board info data
+ */
+ (*entry_point)(gd->bd);
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_RTEMS */
+
+#if defined(CONFIG_BOOTM_OSE)
+static int do_bootm_ose (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("OSE");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf ("## Transferring control to OSE (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ show_boot_progress (15);
+
+ /*
+ * OSE Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif /* CONFIG_BOOTM_OSE */
+
+#if defined(CONFIG_CMD_ELF)
+static int do_bootm_vxworks (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ char str[80];
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("VxWorks");
+ return 1;
+ }
+#endif
+
+ sprintf(str, "%lx", images->ep); /* write entry-point into string */
+ setenv("loadaddr", str);
+ do_bootvx(NULL, 0, 0, NULL);
+
+ return 1;
+}
+
+static int do_bootm_qnxelf(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ char *local_args[2];
+ char str[16];
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("QNX");
+ return 1;
+ }
+#endif
+
+ sprintf(str, "%lx", images->ep); /* write entry-point into string */
+ local_args[0] = argv[0];
+ local_args[1] = str; /* and provide it via the arguments */
+ do_bootelf(NULL, 0, 2, local_args);
+
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_INTEGRITY
+static int do_bootm_integrity (int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ void (*entry_point)(void);
+
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+#if defined(CONFIG_FIT)
+ if (!images->legacy_hdr_valid) {
+ fit_unsupported_reset ("INTEGRITY");
+ return 1;
+ }
+#endif
+
+ entry_point = (void (*)(void))images->ep;
+
+ printf ("## Transferring control to INTEGRITY (at address %08lx) ...\n",
+ (ulong)entry_point);
+
+ show_boot_progress (15);
+
+ /*
+ * INTEGRITY Parameters:
+ * None
+ */
+ (*entry_point)();
+
+ return 1;
+}
+#endif
diff --git a/u-boot/common/cmd_cache.c b/u-boot/common/cmd_cache.c
new file mode 100644
index 0000000..5cdd834
--- /dev/null
+++ b/u-boot/common/cmd_cache.c
@@ -0,0 +1,98 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Cache support: switch on or off, get status
+ */
+#include <common.h>
+#include <command.h>
+
+static int on_off (const char *);
+
+int do_icache ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ switch (argc) {
+ case 2: /* on / off */
+ switch (on_off(argv[1])) {
+ case 0: icache_disable();
+ break;
+ case 1: icache_enable ();
+ break;
+ }
+ /* FALL TROUGH */
+ case 1: /* get status */
+ printf ("Instruction Cache is %s\n",
+ icache_status() ? "ON" : "OFF");
+ return 0;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ return 0;
+}
+
+int do_dcache ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ switch (argc) {
+ case 2: /* on / off */
+ switch (on_off(argv[1])) {
+ case 0: dcache_disable();
+ break;
+ case 1: dcache_enable ();
+ break;
+ }
+ /* FALL TROUGH */
+ case 1: /* get status */
+ printf ("Data (writethrough) Cache is %s\n",
+ dcache_status() ? "ON" : "OFF");
+ return 0;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ return 0;
+
+}
+
+static int on_off (const char *s)
+{
+ if (strcmp(s, "on") == 0) {
+ return (1);
+ } else if (strcmp(s, "off") == 0) {
+ return (0);
+ }
+ return (-1);
+}
+
+
+U_BOOT_CMD(
+ icache, 2, 1, do_icache,
+ "enable or disable instruction cache",
+ "[on, off]\n"
+ " - enable or disable instruction cache"
+);
+
+U_BOOT_CMD(
+ dcache, 2, 1, do_dcache,
+ "enable or disable data cache",
+ "[on, off]\n"
+ " - enable or disable data (writethrough) cache"
+);
diff --git a/u-boot/common/cmd_console.c b/u-boot/common/cmd_console.c
new file mode 100644
index 0000000..d8cad6b
--- /dev/null
+++ b/u-boot/common/cmd_console.c
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <stdio_dev.h>
+
+extern void _do_coninfo (void);
+int do_coninfo (cmd_tbl_t * cmd, int flag, int argc, char * const argv[])
+{
+ int l;
+ struct list_head *list = stdio_get_list();
+ struct list_head *pos;
+ struct stdio_dev *dev;
+
+ /* Scan for valid output and input devices */
+
+ puts ("List of available devices:\n");
+
+ list_for_each(pos, list) {
+ dev = list_entry(pos, struct stdio_dev, list);
+
+ printf ("%-8s %08x %c%c%c ",
+ dev->name,
+ dev->flags,
+ (dev->flags & DEV_FLAGS_SYSTEM) ? 'S' : '.',
+ (dev->flags & DEV_FLAGS_INPUT) ? 'I' : '.',
+ (dev->flags & DEV_FLAGS_OUTPUT) ? 'O' : '.');
+
+ for (l = 0; l < MAX_FILES; l++) {
+ if (stdio_devices[l] == dev) {
+ printf ("%s ", stdio_names[l]);
+ }
+ }
+ putc ('\n');
+ }
+ return 0;
+}
+
+
+/***************************************************/
+
+U_BOOT_CMD(
+ coninfo, 3, 1, do_coninfo,
+ "print console devices and information",
+ ""
+);
diff --git a/u-boot/common/cmd_cplbinfo.c b/u-boot/common/cmd_cplbinfo.c
new file mode 100644
index 0000000..ab5b3b5
--- /dev/null
+++ b/u-boot/common/cmd_cplbinfo.c
@@ -0,0 +1,60 @@
+/*
+ * cmd_cplbinfo.c - dump the instruction/data cplb tables
+ *
+ * Copyright (c) 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+#include <asm/mach-common/bits/mpu.h>
+
+/*
+ * Translate the PAGE_SIZE bits into a human string
+ */
+static const char *cplb_page_size(uint32_t data)
+{
+ static const char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+ return page_size_string_table[(data & PAGE_SIZE_MASK) >> PAGE_SIZE_SHIFT];
+}
+
+/*
+ * show a hardware cplb table
+ */
+static void show_cplb_table(uint32_t *addr, uint32_t *data)
+{
+ int i;
+ printf(" Address Data Size Valid Locked\n");
+ for (i = 1; i <= 16; ++i) {
+ printf(" %2i 0x%p 0x%05X %s %c %c\n",
+ i, (void *)*addr, *data,
+ cplb_page_size(*data),
+ (*data & CPLB_VALID ? 'Y' : 'N'),
+ (*data & CPLB_LOCK ? 'Y' : 'N'));
+ ++addr;
+ ++data;
+ }
+}
+
+/*
+ * display current instruction and data cplb tables
+ */
+int do_cplbinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("%s CPLB table [%08x]:\n", "Instruction", *(uint32_t *)DMEM_CONTROL);
+ show_cplb_table((uint32_t *)ICPLB_ADDR0, (uint32_t *)ICPLB_DATA0);
+
+ printf("%s CPLB table [%08x]:\n", "Data", *(uint32_t *)IMEM_CONTROL);
+ show_cplb_table((uint32_t *)DCPLB_ADDR0, (uint32_t *)DCPLB_DATA0);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ cplbinfo, 1, 0, do_cplbinfo,
+ "display current CPLB tables",
+ ""
+);
diff --git a/u-boot/common/cmd_cramfs.c b/u-boot/common/cmd_cramfs.c
new file mode 100644
index 0000000..8c86dc5
--- /dev/null
+++ b/u-boot/common/cmd_cramfs.c
@@ -0,0 +1,216 @@
+/*
+ * 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
+ *
+ * based on: cmd_jffs2.c
+ *
+ * Add support for a CRAMFS located in RAM
+ */
+
+
+/*
+ * CRAMFS support
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <jffs2/jffs2.h>
+#include <jffs2/load_kernel.h>
+#include <cramfs/cramfs_fs.h>
+
+/* enable/disable debugging messages */
+#define DEBUG_CRAMFS
+#undef DEBUG_CRAMFS
+
+#ifdef DEBUG_CRAMFS
+# define DEBUGF(fmt, args...) printf(fmt ,##args)
+#else
+# define DEBUGF(fmt, args...)
+#endif
+
+#ifdef CONFIG_CRAMFS_CMDLINE
+flash_info_t flash_info[1];
+
+#ifndef CONFIG_CMD_JFFS2
+#include <linux/stat.h>
+char *mkmodestr(unsigned long mode, char *str)
+{
+ static const char *l = "xwr";
+ int mask = 1, i;
+ char c;
+
+ switch (mode & S_IFMT) {
+ case S_IFDIR: str[0] = 'd'; break;
+ case S_IFBLK: str[0] = 'b'; break;
+ case S_IFCHR: str[0] = 'c'; break;
+ case S_IFIFO: str[0] = 'f'; break;
+ case S_IFLNK: str[0] = 'l'; break;
+ case S_IFSOCK: str[0] = 's'; break;
+ case S_IFREG: str[0] = '-'; break;
+ default: str[0] = '?';
+ }
+
+ for(i = 0; i < 9; i++) {
+ c = l[i%3];
+ str[9-i] = (mode & mask)?c:'-';
+ mask = mask<<1;
+ }
+
+ if(mode & S_ISUID) str[3] = (mode & S_IXUSR)?'s':'S';
+ if(mode & S_ISGID) str[6] = (mode & S_IXGRP)?'s':'S';
+ if(mode & S_ISVTX) str[9] = (mode & S_IXOTH)?'t':'T';
+ str[10] = '\0';
+ return str;
+}
+#endif /* CONFIG_CMD_JFFS2 */
+
+extern int cramfs_check (struct part_info *info);
+extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
+extern int cramfs_ls (struct part_info *info, char *filename);
+extern int cramfs_info (struct part_info *info);
+
+/***************************************************/
+/* U-boot commands */
+/***************************************************/
+
+/**
+ * Routine implementing fsload u-boot command. This routine tries to load
+ * a requested file from cramfs filesystem at location 'cramfsaddr'.
+ * cramfsaddr is an evironment variable.
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename;
+ int size;
+ ulong offset = load_addr;
+
+ struct part_info part;
+ struct mtd_device dev;
+ struct mtdids id;
+
+ ulong addr;
+ addr = simple_strtoul(getenv("cramfsaddr"), NULL, 16);
+
+ /* hack! */
+ /* cramfs_* only supports NOR flash chips */
+ /* fake the device type */
+ id.type = MTD_DEV_TYPE_NOR;
+ id.num = 0;
+ dev.id = &id;
+ part.dev = &dev;
+ /* fake the address offset */
+ part.offset = addr - flash_info[id.num].start[0];
+
+ /* pre-set Boot file name */
+ if ((filename = getenv("bootfile")) == NULL) {
+ filename = "uImage";
+ }
+
+ if (argc == 2) {
+ filename = argv[1];
+ }
+ if (argc == 3) {
+ offset = simple_strtoul(argv[1], NULL, 0);
+ load_addr = offset;
+ filename = argv[2];
+ }
+
+ size = 0;
+ if (cramfs_check(&part))
+ size = cramfs_load ((char *) offset, &part, filename);
+
+ if (size > 0) {
+ char buf[10];
+ printf("### CRAMFS load complete: %d bytes loaded to 0x%lx\n",
+ size, offset);
+ sprintf(buf, "%x", size);
+ setenv("filesize", buf);
+ } else {
+ printf("### CRAMFS LOAD ERROR<%x> for %s!\n", size, filename);
+ }
+
+ return !(size > 0);
+}
+
+/**
+ * Routine implementing u-boot ls command which lists content of a given
+ * directory at location 'cramfsaddr'.
+ * cramfsaddr is an evironment variable.
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_cramfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int ret;
+ struct part_info part;
+ struct mtd_device dev;
+ struct mtdids id;
+
+ ulong addr;
+ addr = simple_strtoul(getenv("cramfsaddr"), NULL, 16);
+
+ /* hack! */
+ /* cramfs_* only supports NOR flash chips */
+ /* fake the device type */
+ id.type = MTD_DEV_TYPE_NOR;
+ id.num = 0;
+ dev.id = &id;
+ part.dev = &dev;
+ /* fake the address offset */
+ part.offset = addr - flash_info[id.num].start[0];
+
+ if (argc == 2)
+ filename = argv[1];
+
+ ret = 0;
+ if (cramfs_check(&part))
+ ret = cramfs_ls (&part, filename);
+
+ return ret ? 0 : 1;
+}
+
+/* command line only */
+
+/***************************************************/
+U_BOOT_CMD(
+ cramfsload, 3, 0, do_cramfs_load,
+ "load binary file from a filesystem image",
+ "[ off ] [ filename ]\n"
+ " - load binary file from address 'cramfsaddr'\n"
+ " with offset 'off'\n"
+);
+U_BOOT_CMD(
+ cramfsls, 2, 1, do_cramfs_ls,
+ "list files in a directory (default /)",
+ "[ directory ]\n"
+ " - list files in a directory.\n"
+);
+
+#endif /* #ifdef CONFIG_CRAMFS_CMDLINE */
+
+/***************************************************/
diff --git a/u-boot/common/cmd_dataflash_mmc_mux.c b/u-boot/common/cmd_dataflash_mmc_mux.c
new file mode 100644
index 0000000..1678d6e
--- /dev/null
+++ b/u-boot/common/cmd_dataflash_mmc_mux.c
@@ -0,0 +1,64 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+static int mmc_nspi (const char *);
+
+int do_dataflash_mmc_mux (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ switch (argc) {
+ case 2: /* on / off */
+ switch (mmc_nspi (argv[1])) {
+ case 0: AT91F_SelectSPI ();
+ break;
+ case 1: AT91F_SelectMMC ();
+ break;
+ }
+ case 1: /* get status */
+ printf ("Mux is configured to be %s\n",
+ AT91F_GetMuxStatus () ? "MMC" : "SPI");
+ return 0;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ return 0;
+}
+
+static int mmc_nspi (const char *s)
+{
+ if (strcmp (s, "mmc") == 0) {
+ return 1;
+ } else if (strcmp (s, "spi") == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+U_BOOT_CMD(
+ dataflash_mmc_mux, 2, 1, do_dataflash_mmc_mux,
+ "enable or disable MMC or SPI\n",
+ "[mmc, spi]\n"
+ " - enable or disable MMC or SPI"
+);
diff --git a/u-boot/common/cmd_date.c b/u-boot/common/cmd_date.c
new file mode 100644
index 0000000..f0fa02a
--- /dev/null
+++ b/u-boot/common/cmd_date.c
@@ -0,0 +1,226 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * RTC, Date & Time support: get and set date & time
+ */
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char * const weekdays[] = {
+ "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur",
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+#define RELOC(a) ((typeof(a))((unsigned long)(a) + gd->reloc_off))
+#else
+#define RELOC(a) a
+#endif
+
+int mk_date (const char *, struct rtc_time *);
+
+int do_date (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct rtc_time tm;
+ int rcode = 0;
+ int old_bus;
+
+ /* switch to correct I2C bus */
+ old_bus = I2C_GET_BUS();
+ I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
+
+ switch (argc) {
+ case 2: /* set date & time */
+ if (strcmp(argv[1],"reset") == 0) {
+ puts ("Reset RTC...\n");
+ rtc_reset ();
+ } else {
+ /* initialize tm with current time */
+ rcode = rtc_get (&tm);
+
+ if(!rcode) {
+ /* insert new date & time */
+ if (mk_date (argv[1], &tm) != 0) {
+ puts ("## Bad date format\n");
+ break;
+ }
+ /* and write to RTC */
+ rcode = rtc_set (&tm);
+ if(rcode)
+ puts("## Set date failed\n");
+ } else {
+ puts("## Get date failed\n");
+ }
+ }
+ /* FALL TROUGH */
+ case 1: /* get date & time */
+ rcode = rtc_get (&tm);
+
+ if (rcode) {
+ puts("## Get date failed\n");
+ break;
+ }
+
+ printf ("Date: %4d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n",
+ tm.tm_year, tm.tm_mon, tm.tm_mday,
+ (tm.tm_wday<0 || tm.tm_wday>6) ?
+ "unknown " : RELOC(weekdays[tm.tm_wday]),
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ break;
+ default:
+ cmd_usage(cmdtp);
+ rcode = 1;
+ }
+
+ /* switch back to original I2C bus */
+ I2C_SET_BUS(old_bus);
+
+ return rcode;
+}
+
+/*
+ * simple conversion of two-digit string with error checking
+ */
+static int cnvrt2 (const char *str, int *valp)
+{
+ int val;
+
+ if ((*str < '0') || (*str > '9'))
+ return (-1);
+
+ val = *str - '0';
+
+ ++str;
+
+ if ((*str < '0') || (*str > '9'))
+ return (-1);
+
+ *valp = 10 * val + (*str - '0');
+
+ return (0);
+}
+
+/*
+ * Convert date string: MMDDhhmm[[CC]YY][.ss]
+ *
+ * Some basic checking for valid values is done, but this will not catch
+ * all possible error conditions.
+ */
+int mk_date (const char *datestr, struct rtc_time *tmp)
+{
+ int len, val;
+ char *ptr;
+
+ ptr = strchr (datestr,'.');
+ len = strlen (datestr);
+
+ /* Set seconds */
+ if (ptr) {
+ int sec;
+
+ *ptr++ = '\0';
+ if ((len - (ptr - datestr)) != 2)
+ return (-1);
+
+ len = strlen (datestr);
+
+ if (cnvrt2 (ptr, &sec))
+ return (-1);
+
+ tmp->tm_sec = sec;
+ } else {
+ tmp->tm_sec = 0;
+ }
+
+ if (len == 12) { /* MMDDhhmmCCYY */
+ int year, century;
+
+ if (cnvrt2 (datestr+ 8, &century) ||
+ cnvrt2 (datestr+10, &year) ) {
+ return (-1);
+ }
+ tmp->tm_year = 100 * century + year;
+ } else if (len == 10) { /* MMDDhhmmYY */
+ int year, century;
+
+ century = tmp->tm_year / 100;
+ if (cnvrt2 (datestr+ 8, &year))
+ return (-1);
+ tmp->tm_year = 100 * century + year;
+ }
+
+ switch (len) {
+ case 8: /* MMDDhhmm */
+ /* fall thru */
+ case 10: /* MMDDhhmmYY */
+ /* fall thru */
+ case 12: /* MMDDhhmmCCYY */
+ if (cnvrt2 (datestr+0, &val) ||
+ val > 12) {
+ break;
+ }
+ tmp->tm_mon = val;
+ if (cnvrt2 (datestr+2, &val) ||
+ val > ((tmp->tm_mon==2) ? 29 : 31)) {
+ break;
+ }
+ tmp->tm_mday = val;
+
+ if (cnvrt2 (datestr+4, &val) ||
+ val > 23) {
+ break;
+ }
+ tmp->tm_hour = val;
+
+ if (cnvrt2 (datestr+6, &val) ||
+ val > 59) {
+ break;
+ }
+ tmp->tm_min = val;
+
+ /* calculate day of week */
+ GregorianDay (tmp);
+
+ return (0);
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ date, 2, 1, do_date,
+ "get/set/reset date & time",
+ "[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n"
+ " - without arguments: print date & time\n"
+ " - with numeric argument: set the system date & time\n"
+ " - with 'reset' argument: reset the RTC"
+);
diff --git a/u-boot/common/cmd_dcr.c b/u-boot/common/cmd_dcr.c
new file mode 100644
index 0000000..45fe66a
--- /dev/null
+++ b/u-boot/common/cmd_dcr.c
@@ -0,0 +1,237 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * AMCC 4XX DCR Functions
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+unsigned long get_dcr (unsigned short);
+unsigned long set_dcr (unsigned short, unsigned long);
+
+/* =======================================================================
+ * Interpreter command to retrieve an AMCC PPC 4xx Device Control Register
+ * =======================================================================
+ */
+int do_getdcr ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] )
+{
+ unsigned short dcrn; /* Device Control Register Num */
+ unsigned long value; /* DCR's value */
+
+ unsigned long get_dcr (unsigned short);
+
+ /* Validate arguments */
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /* Get a DCR */
+ dcrn = (unsigned short) simple_strtoul (argv[1], NULL, 16);
+ value = get_dcr (dcrn);
+
+ printf ("%04x: %08lx\n", dcrn, value);
+
+ return 0;
+}
+
+
+/* ======================================================================
+ * Interpreter command to set an AMCC PPC 4xx Device Control Register
+ * ======================================================================
+*/
+int do_setdcr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned short dcrn; /* Device Control Register Num */
+ unsigned long value;
+
+ /* DCR's value */
+ int nbytes;
+ extern char console_buffer[];
+
+ /* Validate arguments */
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /* Set a DCR */
+ dcrn = (unsigned short) simple_strtoul (argv[1], NULL, 16);
+ do {
+ value = get_dcr (dcrn);
+ printf ("%04x: %08lx", dcrn, value);
+ nbytes = readline (" ? ");
+ if (nbytes == 0) {
+ /*
+ * <CR> pressed as only input, don't modify current
+ * location and exit command.
+ */
+ nbytes = 1;
+ return 0;
+ } else {
+ unsigned long i;
+ char *endp;
+
+ i = simple_strtoul (console_buffer, &endp, 16);
+ nbytes = endp - console_buffer;
+ if (nbytes)
+ set_dcr (dcrn, i);
+ }
+ } while (nbytes);
+
+ return 0;
+}
+
+/* =======================================================================
+ * Interpreter command to retrieve an register value through AMCC PPC 4xx
+ * Device Control Register inderect addressing.
+ * =======================================================================
+ */
+int do_getidcr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned short adr_dcrn; /* Device Control Register Num for Address */
+ unsigned short dat_dcrn; /* Device Control Register Num for Data */
+ unsigned short offset; /* Register's offset */
+ unsigned long value; /* Register's value */
+ char *ptr = NULL;
+ char buf[80];
+
+ /* Validate arguments */
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ /* Find out whether ther is '.' (dot) symbol in the first parameter. */
+ strncpy (buf, argv[1], sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0; /* will guarantee zero-end string */
+ ptr = strchr (buf, '.');
+
+ if (ptr != NULL) {
+ /* First parameter has format adr_dcrn.dat_dcrn */
+ *ptr++ = 0; /* erase '.', create zero-end string */
+ adr_dcrn = (unsigned short) simple_strtoul (buf, NULL, 16);
+ dat_dcrn = (unsigned short) simple_strtoul (ptr, NULL, 16);
+ } else {
+ /*
+ * First parameter has format adr_dcrn; dat_dcrn will be
+ * calculated as adr_dcrn+1.
+ */
+ adr_dcrn = (unsigned short) simple_strtoul (buf, NULL, 16);
+ dat_dcrn = adr_dcrn+1;
+ }
+
+ /* Register's offset */
+ offset = (unsigned short) simple_strtoul (argv[2], NULL, 16);
+
+ /* Disable interrupts */
+ disable_interrupts ();
+ /* Set offset */
+ set_dcr (adr_dcrn, offset);
+ /* get data */
+ value = get_dcr (dat_dcrn);
+ /* Enable interrupts */
+ enable_interrupts ();
+
+ printf ("%04x.%04x-%04x Read %08lx\n", adr_dcrn, dat_dcrn, offset, value);
+
+ return 0;
+}
+
+/* =======================================================================
+ * Interpreter command to update an register value through AMCC PPC 4xx
+ * Device Control Register inderect addressing.
+ * =======================================================================
+ */
+int do_setidcr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned short adr_dcrn; /* Device Control Register Num for Address */
+ unsigned short dat_dcrn; /* Device Control Register Num for Data */
+ unsigned short offset; /* Register's offset */
+ unsigned long value; /* Register's value */
+ char *ptr = NULL;
+ char buf[80];
+
+ /* Validate arguments */
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ /* Find out whether ther is '.' (dot) symbol in the first parameter. */
+ strncpy (buf, argv[1], sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0; /* will guarantee zero-end string */
+ ptr = strchr (buf, '.');
+
+ if (ptr != NULL) {
+ /* First parameter has format adr_dcrn.dat_dcrn */
+ *ptr++ = 0; /* erase '.', create zero-end string */
+ adr_dcrn = (unsigned short) simple_strtoul (buf, NULL, 16);
+ dat_dcrn = (unsigned short) simple_strtoul (ptr, NULL, 16);
+ } else {
+ /*
+ * First parameter has format adr_dcrn; dat_dcrn will be
+ * calculated as adr_dcrn+1.
+ */
+ adr_dcrn = (unsigned short) simple_strtoul (buf, NULL, 16);
+ dat_dcrn = adr_dcrn+1;
+ }
+
+ /* Register's offset */
+ offset = (unsigned short) simple_strtoul (argv[2], NULL, 16);
+ /* New value */
+ value = (unsigned long) simple_strtoul (argv[3], NULL, 16);
+
+ /* Disable interrupts */
+ disable_interrupts ();
+ /* Set offset */
+ set_dcr (adr_dcrn, offset);
+ /* set data */
+ set_dcr (dat_dcrn, value);
+ /* Enable interrupts */
+ enable_interrupts ();
+
+ printf ("%04x.%04x-%04x Write %08lx\n", adr_dcrn, dat_dcrn, offset, value);
+
+ return 0;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ getdcr, 2, 1, do_getdcr,
+ "Get an AMCC PPC 4xx DCR's value",
+ "dcrn - return a DCR's value."
+);
+U_BOOT_CMD(
+ setdcr, 2, 1, do_setdcr,
+ "Set an AMCC PPC 4xx DCR's value",
+ "dcrn - set a DCR's value."
+);
+
+U_BOOT_CMD(
+ getidcr, 3, 1, do_getidcr,
+ "Get a register value via indirect DCR addressing",
+ "adr_dcrn[.dat_dcrn] offset - write offset to adr_dcrn, read value from dat_dcrn."
+);
+
+U_BOOT_CMD(
+ setidcr, 4, 1, do_setidcr,
+ "Set a register value via indirect DCR addressing",
+ "adr_dcrn[.dat_dcrn] offset value - write offset to adr_dcrn, write value to dat_dcrn."
+);
diff --git a/u-boot/common/cmd_df.c b/u-boot/common/cmd_df.c
new file mode 100644
index 0000000..9a3c84c
--- /dev/null
+++ b/u-boot/common/cmd_df.c
@@ -0,0 +1,36 @@
+/*
+ * Command for accessing DataFlash.
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ */
+#include <common.h>
+#include <df.h>
+
+static int do_df(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const char *cmd;
+
+ /* need at least two arguments */
+ if (argc < 2)
+ goto usage;
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "init") == 0) {
+ df_init(0, 0, 1000000);
+ return 0;
+ }
+
+ if (strcmp(cmd, "info") == 0) {
+ df_show_info();
+ return 0;
+ }
+
+usage:
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ sf, 2, 1, do_serial_flash,
+ "Serial flash sub-system",
+ "probe [bus:]cs - init flash device on given SPI bus and CS")
diff --git a/u-boot/common/cmd_diag.c b/u-boot/common/cmd_diag.c
new file mode 100644
index 0000000..317ea66
--- /dev/null
+++ b/u-boot/common/cmd_diag.c
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Diagnostics support
+ */
+#include <common.h>
+#include <command.h>
+#include <post.h>
+
+int do_diag (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned int i;
+
+ if (argc == 1 || strcmp (argv[1], "run") != 0) {
+ /* List test info */
+ if (argc == 1) {
+ puts ("Available hardware tests:\n");
+ post_info (NULL);
+ puts ("Use 'diag [<test1> [<test2> ...]]'"
+ " to get more info.\n");
+ puts ("Use 'diag run [<test1> [<test2> ...]]'"
+ " to run tests.\n");
+ } else {
+ for (i = 1; i < argc; i++) {
+ if (post_info (argv[i]) != 0)
+ printf ("%s - no such test\n", argv[i]);
+ }
+ }
+ } else {
+ /* Run tests */
+ if (argc == 2) {
+ post_run (NULL, POST_RAM | POST_MANUAL);
+ } else {
+ for (i = 2; i < argc; i++) {
+ if (post_run (argv[i], POST_RAM | POST_MANUAL) != 0)
+ printf ("%s - unable to execute the test\n",
+ argv[i]);
+ }
+ }
+ }
+
+ return 0;
+}
+/***************************************************/
+
+U_BOOT_CMD(
+ diag, CONFIG_SYS_MAXARGS, 0, do_diag,
+ "perform board diagnostics",
+ " - print list of available tests\n"
+ "diag [test1 [test2]]\n"
+ " - print information about specified tests\n"
+ "diag run - run all available tests\n"
+ "diag run [test1 [test2]]\n"
+ " - run specified tests"
+);
diff --git a/u-boot/common/cmd_display.c b/u-boot/common/cmd_display.c
new file mode 100644
index 0000000..d5d5d8c
--- /dev/null
+++ b/u-boot/common/cmd_display.c
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <led-display.h>
+
+#undef DEBUG_DISP
+
+int do_display (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+
+ /* Clear display */
+ display_set(DISPLAY_CLEAR | DISPLAY_HOME);
+
+ if (argc < 2)
+ return (0);
+
+ for (i = 1; i < argc; i++) {
+ char *p = argv[i];
+
+ if (i > 1) { /* Insert a space between strings */
+ display_putc(' ');
+ }
+
+ while ((*p)) {
+#ifdef DEBUG_DISP
+ putc(*p);
+#endif
+ display_putc(*p++);
+ }
+ }
+
+#ifdef DEBUG_DISP
+ putc('\n');
+#endif
+
+ return (0);
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ display, CONFIG_SYS_MAXARGS, 1, do_display,
+ "display string on dot matrix display",
+ "[<string>]\n"
+ " - with <string> argument: display <string> on dot matrix display\n"
+ " - without arguments: clear dot matrix display"
+);
diff --git a/u-boot/common/cmd_dtt.c b/u-boot/common/cmd_dtt.c
new file mode 100644
index 0000000..3388e43
--- /dev/null
+++ b/u-boot/common/cmd_dtt.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+#include <dtt.h>
+#include <i2c.h>
+
+int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ unsigned char sensors[] = CONFIG_DTT_SENSORS;
+ int old_bus;
+
+ /* switch to correct I2C bus */
+ old_bus = I2C_GET_BUS();
+ I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
+
+ /*
+ * Loop through sensors, read
+ * temperature, and output it.
+ */
+ for (i = 0; i < sizeof (sensors); i++)
+ printf ("DTT%d: %i C\n", i + 1, dtt_get_temp (sensors[i]));
+
+ /* switch back to original I2C bus */
+ I2C_SET_BUS(old_bus);
+
+ return 0;
+} /* do_dtt() */
+
+/***************************************************/
+
+U_BOOT_CMD(
+ dtt, 1, 1, do_dtt,
+ "Read temperature from Digital Thermometer and Thermostat",
+ ""
+);
diff --git a/u-boot/common/cmd_echo.c b/u-boot/common/cmd_echo.c
new file mode 100644
index 0000000..43a6da5
--- /dev/null
+++ b/u-boot/common/cmd_echo.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+int do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ int putnl = 1;
+
+ for (i = 1; i < argc; i++) {
+ char *p = argv[i], c;
+
+ if (i > 1)
+ putc(' ');
+ while ((c = *p++) != '\0') {
+ if (c == '\\' && *p == 'c') {
+ putnl = 0;
+ p++;
+ } else {
+ putc(c);
+ }
+ }
+ }
+
+ if (putnl)
+ putc('\n');
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ echo, CONFIG_SYS_MAXARGS, 1, do_echo,
+ "echo args to console",
+ "[args..]\n"
+ " - echo args to console; \\c suppresses newline"
+);
diff --git a/u-boot/common/cmd_eeprom.c b/u-boot/common/cmd_eeprom.c
new file mode 100644
index 0000000..9f4b22c
--- /dev/null
+++ b/u-boot/common/cmd_eeprom.c
@@ -0,0 +1,440 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ *
+ */
+
+/*
+ * Support for read and write access to EEPROM like memory devices. This
+ * includes regular EEPROM as well as FRAM (ferroelectic nonvolaile RAM).
+ * FRAM devices read and write data at bus speed. In particular, there is no
+ * write delay. Also, there is no limit imposed on the numer of bytes that can
+ * be transferred with a single read or write.
+ *
+ * Use the following configuration options to ensure no unneeded performance
+ * degradation (typical for EEPROM) is incured for FRAM memory:
+ *
+ * #define CONFIG_SYS_I2C_FRAM
+ * #undef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+ *
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <i2c.h>
+
+extern void eeprom_init (void);
+extern int eeprom_read (unsigned dev_addr, unsigned offset,
+ uchar *buffer, unsigned cnt);
+extern int eeprom_write (unsigned dev_addr, unsigned offset,
+ uchar *buffer, unsigned cnt);
+#if defined(CONFIG_SYS_EEPROM_WREN)
+extern int eeprom_write_enable (unsigned dev_addr, int state);
+#endif
+
+
+#if defined(CONFIG_SYS_EEPROM_X40430)
+ /* Maximum number of times to poll for acknowledge after write */
+#define MAX_ACKNOWLEDGE_POLLS 10
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_CMD_EEPROM)
+int do_eeprom ( cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ const char *const fmt =
+ "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... ";
+
+#if defined(CONFIG_SYS_I2C_MULTI_EEPROMS)
+ if (argc == 6) {
+ ulong dev_addr = simple_strtoul (argv[2], NULL, 16);
+ ulong addr = simple_strtoul (argv[3], NULL, 16);
+ ulong off = simple_strtoul (argv[4], NULL, 16);
+ ulong cnt = simple_strtoul (argv[5], NULL, 16);
+#else
+ if (argc == 5) {
+ ulong dev_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
+ ulong addr = simple_strtoul (argv[2], NULL, 16);
+ ulong off = simple_strtoul (argv[3], NULL, 16);
+ ulong cnt = simple_strtoul (argv[4], NULL, 16);
+#endif /* CONFIG_SYS_I2C_MULTI_EEPROMS */
+
+# if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+ eeprom_init ();
+# endif /* !CONFIG_SPI */
+
+ if (strcmp (argv[1], "read") == 0) {
+ int rcode;
+
+ printf (fmt, dev_addr, argv[1], addr, off, cnt);
+
+ rcode = eeprom_read (dev_addr, off, (uchar *) addr, cnt);
+
+ puts ("done\n");
+ return rcode;
+ } else if (strcmp (argv[1], "write") == 0) {
+ int rcode;
+
+ printf (fmt, dev_addr, argv[1], addr, off, cnt);
+
+ rcode = eeprom_write (dev_addr, off, (uchar *) addr, cnt);
+
+ puts ("done\n");
+ return rcode;
+ }
+ }
+
+ return cmd_usage(cmdtp);
+}
+#endif
+
+/*-----------------------------------------------------------------------
+ *
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
+ * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
+ *
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
+ * 0x00000nxx for EEPROM address selectors and page number at n.
+ */
+
+#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+#if !defined(CONFIG_SYS_I2C_EEPROM_ADDR_LEN) || CONFIG_SYS_I2C_EEPROM_ADDR_LEN < 1 || CONFIG_SYS_I2C_EEPROM_ADDR_LEN > 2
+#error CONFIG_SYS_I2C_EEPROM_ADDR_LEN must be 1 or 2
+#endif
+#endif
+
+int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
+{
+ unsigned end = offset + cnt;
+ unsigned blk_off;
+ int rcode = 0;
+
+ /* Read data until done or would cross a page boundary.
+ * We must write the address again when changing pages
+ * because the next page may be in a different device.
+ */
+ while (offset < end) {
+ unsigned alen, len;
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ unsigned maxlen;
+#endif
+
+#if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
+ uchar addr[2];
+
+ blk_off = offset & 0xFF; /* block offset */
+
+ addr[0] = offset >> 8; /* block number */
+ addr[1] = blk_off; /* block offset */
+ alen = 2;
+#else
+ uchar addr[3];
+
+ blk_off = offset & 0xFF; /* block offset */
+
+ addr[0] = offset >> 16; /* block number */
+ addr[1] = offset >> 8; /* upper address octet */
+ addr[2] = blk_off; /* lower address octet */
+ alen = 3;
+#endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
+
+ addr[0] |= dev_addr; /* insert device address */
+
+ len = end - offset;
+
+ /*
+ * For a FRAM device there is no limit on the number of the
+ * bytes that can be ccessed with the single read or write
+ * operation.
+ */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ maxlen = 0x100 - blk_off;
+ if (maxlen > I2C_RXTX_LEN)
+ maxlen = I2C_RXTX_LEN;
+ if (len > maxlen)
+ len = maxlen;
+#endif
+
+#if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+ spi_read (addr, alen, buffer, len);
+#else
+ if (i2c_read (addr[0], offset, alen-1, buffer, len) != 0)
+ rcode = 1;
+#endif
+ buffer += len;
+ offset += len;
+ }
+
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ *
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is
+ * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM.
+ *
+ * for CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is
+ * 0x00000nxx for EEPROM address selectors and page number at n.
+ */
+
+int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt)
+{
+ unsigned end = offset + cnt;
+ unsigned blk_off;
+ int rcode = 0;
+
+#if defined(CONFIG_SYS_EEPROM_X40430)
+ uchar contr_r_addr[2];
+ uchar addr_void[2];
+ uchar contr_reg[2];
+ uchar ctrl_reg_v;
+ int i;
+#endif
+
+#if defined(CONFIG_SYS_EEPROM_WREN)
+ eeprom_write_enable (dev_addr,1);
+#endif
+ /* Write data until done or would cross a write page boundary.
+ * We must write the address again when changing pages
+ * because the address counter only increments within a page.
+ */
+
+ while (offset < end) {
+ unsigned alen, len;
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ unsigned maxlen;
+#endif
+
+#if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
+ uchar addr[2];
+
+ blk_off = offset & 0xFF; /* block offset */
+
+ addr[0] = offset >> 8; /* block number */
+ addr[1] = blk_off; /* block offset */
+ alen = 2;
+#else
+ uchar addr[3];
+
+ blk_off = offset & 0xFF; /* block offset */
+
+ addr[0] = offset >> 16; /* block number */
+ addr[1] = offset >> 8; /* upper address octet */
+ addr[2] = blk_off; /* lower address octet */
+ alen = 3;
+#endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
+
+ addr[0] |= dev_addr; /* insert device address */
+
+ len = end - offset;
+
+ /*
+ * For a FRAM device there is no limit on the number of the
+ * bytes that can be ccessed with the single read or write
+ * operation.
+ */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+
+#if defined(CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
+
+#define EEPROM_PAGE_SIZE (1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)
+#define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1))
+
+ maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off);
+#else
+ maxlen = 0x100 - blk_off;
+#endif
+ if (maxlen > I2C_RXTX_LEN)
+ maxlen = I2C_RXTX_LEN;
+
+ if (len > maxlen)
+ len = maxlen;
+#endif
+
+#if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+ spi_write (addr, alen, buffer, len);
+#else
+#if defined(CONFIG_SYS_EEPROM_X40430)
+ /* Get the value of the control register.
+ * Set current address (internal pointer in the x40430)
+ * to 0x1ff.
+ */
+ contr_r_addr[0] = 9;
+ contr_r_addr[1] = 0xff;
+ addr_void[0] = 0;
+ addr_void[1] = addr[1];
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR
+ contr_r_addr[0] |= CONFIG_SYS_I2C_EEPROM_ADDR;
+ addr_void[0] |= CONFIG_SYS_I2C_EEPROM_ADDR;
+#endif
+ contr_reg[0] = 0xff;
+ if (i2c_read (contr_r_addr[0], contr_r_addr[1], 1, contr_reg, 1) != 0) {
+ rcode = 1;
+ }
+ ctrl_reg_v = contr_reg[0];
+
+ /* Are any of the eeprom blocks write protected?
+ */
+ if (ctrl_reg_v & 0x18) {
+ ctrl_reg_v &= ~0x18; /* reset block protect bits */
+ ctrl_reg_v |= 0x02; /* set write enable latch */
+ ctrl_reg_v &= ~0x04; /* clear RWEL */
+
+ /* Set write enable latch.
+ */
+ contr_reg[0] = 0x02;
+ if (i2c_write (contr_r_addr[0], 0xff, 1, contr_reg, 1) != 0) {
+ rcode = 1;
+ }
+
+ /* Set register write enable latch.
+ */
+ contr_reg[0] = 0x06;
+ if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
+ rcode = 1;
+ }
+
+ /* Modify ctrl register.
+ */
+ contr_reg[0] = ctrl_reg_v;
+ if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
+ rcode = 1;
+ }
+
+ /* The write (above) is an operation on NV memory.
+ * These can take some time (~5ms), and the device
+ * will not respond to further I2C messages till
+ * it's completed the write.
+ * So poll device for an I2C acknowledge.
+ * When we get one we know we can continue with other
+ * operations.
+ */
+ contr_reg[0] = 0;
+ for (i = 0; i < MAX_ACKNOWLEDGE_POLLS; i++) {
+ if (i2c_read (addr_void[0], addr_void[1], 1, contr_reg, 1) == 0)
+ break; /* got ack */
+#if defined(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS)
+ udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+#endif
+ }
+ if (i == MAX_ACKNOWLEDGE_POLLS) {
+ puts ("EEPROM poll acknowledge failed\n");
+ rcode = 1;
+ }
+ }
+
+ /* Is the write enable latch on?.
+ */
+ else if (!(ctrl_reg_v & 0x02)) {
+ /* Set write enable latch.
+ */
+ contr_reg[0] = 0x02;
+ if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) {
+ rcode = 1;
+ }
+ }
+ /* Write is enabled ... now write eeprom value.
+ */
+#endif
+ if (i2c_write (addr[0], offset, alen-1, buffer, len) != 0)
+ rcode = 1;
+
+#endif
+ buffer += len;
+ offset += len;
+
+#if defined(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS)
+ udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+#endif
+ }
+#if defined(CONFIG_SYS_EEPROM_WREN)
+ eeprom_write_enable (dev_addr,0);
+#endif
+ return rcode;
+}
+
+#if !defined(CONFIG_SPI) || defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+int
+eeprom_probe (unsigned dev_addr, unsigned offset)
+{
+ unsigned char chip;
+
+ /* Probe the chip address
+ */
+#if CONFIG_SYS_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X)
+ chip = offset >> 8; /* block number */
+#else
+ chip = offset >> 16; /* block number */
+#endif /* CONFIG_SYS_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */
+
+ chip |= dev_addr; /* insert device address */
+
+ return (i2c_probe (chip));
+}
+#endif
+
+/*-----------------------------------------------------------------------
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED 50000
+#endif
+
+void eeprom_init (void)
+{
+
+#if defined(CONFIG_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
+ spi_init_f ();
+#endif
+#if defined(CONFIG_HARD_I2C) || \
+ defined(CONFIG_SOFT_I2C)
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/***************************************************/
+
+#if defined(CONFIG_CMD_EEPROM)
+
+#ifdef CONFIG_SYS_I2C_MULTI_EEPROMS
+U_BOOT_CMD(
+ eeprom, 6, 1, do_eeprom,
+ "EEPROM sub-system",
+ "read devaddr addr off cnt\n"
+ "eeprom write devaddr addr off cnt\n"
+ " - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
+);
+#else /* One EEPROM */
+U_BOOT_CMD(
+ eeprom, 5, 1, do_eeprom,
+ "EEPROM sub-system",
+ "read addr off cnt\n"
+ "eeprom write addr off cnt\n"
+ " - read/write `cnt' bytes at EEPROM offset `off'"
+);
+#endif /* CONFIG_SYS_I2C_MULTI_EEPROMS */
+
+#endif
diff --git a/u-boot/common/cmd_elf.c b/u-boot/common/cmd_elf.c
new file mode 100644
index 0000000..bf32612
--- /dev/null
+++ b/u-boot/common/cmd_elf.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2001 William L. Pitts
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <net.h>
+#include <elf.h>
+#include <vxworks.h>
+
+#if defined(CONFIG_WALNUT) || defined(CONFIG_SYS_VXWORKS_MAC_PTR)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+int valid_elf_image (unsigned long addr);
+static unsigned long load_elf_image_phdr(unsigned long addr);
+static unsigned long load_elf_image_shdr(unsigned long addr);
+
+/* Allow ports to override the default behavior */
+__attribute__((weak))
+unsigned long do_bootelf_exec (ulong (*entry)(int, char * const[]),
+ int argc, char * const argv[])
+{
+ unsigned long ret;
+
+ /*
+ * QNX images require the data cache is disabled.
+ * Data cache is already flushed, so just turn it off.
+ */
+ int dcache = dcache_status ();
+ if (dcache)
+ dcache_disable ();
+
+ /*
+ * pass address parameter as argv[0] (aka command name),
+ * and all remaining args
+ */
+ ret = entry (argc, argv);
+
+ if (dcache)
+ dcache_enable ();
+
+ return ret;
+}
+
+/* ======================================================================
+ * Interpreter command to boot an arbitrary ELF image from memory.
+ * ====================================================================== */
+int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr; /* Address of the ELF image */
+ unsigned long rc; /* Return value from user code */
+ char *sload, *saddr;
+
+ /* -------------------------------------------------- */
+ int rcode = 0;
+
+ sload = saddr = NULL;
+ if (argc == 3) {
+ sload = argv[1];
+ saddr = argv[2];
+ } else if (argc == 2) {
+ if (argv[1][0] == '-')
+ sload = argv[1];
+ else
+ saddr = argv[1];
+ }
+
+ if (saddr)
+ addr = simple_strtoul(saddr, NULL, 16);
+ else
+ addr = load_addr;
+
+ if (!valid_elf_image (addr))
+ return 1;
+
+ if (sload && sload[1] == 'p')
+ addr = load_elf_image_phdr(addr);
+ else
+ addr = load_elf_image_shdr(addr);
+
+ printf ("## Starting application at 0x%08lx ...\n", addr);
+
+ /*
+ * pass address parameter as argv[0] (aka command name),
+ * and all remaining args
+ */
+ rc = do_bootelf_exec ((void *)addr, argc - 1, argv + 1);
+ if (rc != 0)
+ rcode = 1;
+
+ printf ("## Application terminated, rc = 0x%lx\n", rc);
+ return rcode;
+}
+
+/* ======================================================================
+ * Interpreter command to boot VxWorks from a memory image. The image can
+ * be either an ELF image or a raw binary. Will attempt to setup the
+ * bootline and other parameters correctly.
+ * ====================================================================== */
+int do_bootvx (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr; /* Address of image */
+ unsigned long bootaddr; /* Address to put the bootline */
+ char *bootline; /* Text of the bootline */
+ char *tmp; /* Temporary char pointer */
+ char build_buf[128]; /* Buffer for building the bootline */
+
+ /* ---------------------------------------------------
+ *
+ * Check the loadaddr variable.
+ * If we don't know where the image is then we're done.
+ */
+
+ if (argc < 2)
+ addr = load_addr;
+ else
+ addr = simple_strtoul (argv[1], NULL, 16);
+
+#if defined(CONFIG_CMD_NET)
+ /* Check to see if we need to tftp the image ourselves before starting */
+
+ if ((argc == 2) && (strcmp (argv[1], "tftp") == 0)) {
+ if (NetLoop (TFTP) <= 0)
+ return 1;
+ printf ("Automatic boot of VxWorks image at address 0x%08lx ... \n",
+ addr);
+ }
+#endif
+
+ /* This should equate
+ * to NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
+ * from the VxWorks BSP header files.
+ * This will vary from board to board
+ */
+
+#if defined(CONFIG_WALNUT)
+ tmp = (char *) CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
+ eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
+ memcpy(tmp, &build_buf[3], 3);
+#elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
+ tmp = (char *) CONFIG_SYS_VXWORKS_MAC_PTR;
+ eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
+ memcpy(tmp, build_buf, 6);
+#else
+ puts ("## Ethernet MAC address not copied to NV RAM\n");
+#endif
+
+ /*
+ * Use bootaddr to find the location in memory that VxWorks
+ * will look for the bootline string. The default value for
+ * PowerPC is LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET which
+ * defaults to 0x4200
+ */
+
+ if ((tmp = getenv ("bootaddr")) == NULL)
+ bootaddr = CONFIG_SYS_VXWORKS_BOOT_ADDR;
+ else
+ bootaddr = simple_strtoul (tmp, NULL, 16);
+
+ /*
+ * Check to see if the bootline is defined in the 'bootargs'
+ * parameter. If it is not defined, we may be able to
+ * construct the info
+ */
+
+ if ((bootline = getenv ("bootargs")) != NULL) {
+ memcpy ((void *) bootaddr, bootline,
+ max (strlen (bootline), 255));
+ flush_cache (bootaddr, max (strlen (bootline), 255));
+ } else {
+
+
+ sprintf (build_buf, CONFIG_SYS_VXWORKS_BOOT_DEVICE);
+ if ((tmp = getenv ("bootfile")) != NULL) {
+ sprintf (&build_buf[strlen (build_buf)],
+ "%s:%s ", CONFIG_SYS_VXWORKS_SERVERNAME, tmp);
+ } else {
+ sprintf (&build_buf[strlen (build_buf)],
+ "%s:file ", CONFIG_SYS_VXWORKS_SERVERNAME);
+ }
+
+ if ((tmp = getenv ("ipaddr")) != NULL) {
+ sprintf (&build_buf[strlen (build_buf)], "e=%s ", tmp);
+ }
+
+ if ((tmp = getenv ("serverip")) != NULL) {
+ sprintf (&build_buf[strlen (build_buf)], "h=%s ", tmp);
+ }
+
+ if ((tmp = getenv ("hostname")) != NULL) {
+ sprintf (&build_buf[strlen (build_buf)], "tn=%s ", tmp);
+ }
+#ifdef CONFIG_SYS_VXWORKS_ADD_PARAMS
+ sprintf (&build_buf[strlen (build_buf)],
+ CONFIG_SYS_VXWORKS_ADD_PARAMS);
+#endif
+
+ memcpy ((void *) bootaddr, build_buf,
+ max (strlen (build_buf), 255));
+ flush_cache (bootaddr, max (strlen (build_buf), 255));
+ }
+
+ /*
+ * If the data at the load address is an elf image, then
+ * treat it like an elf image. Otherwise, assume that it is a
+ * binary image
+ */
+
+ if (valid_elf_image (addr)) {
+ addr = load_elf_image_shdr (addr);
+ } else {
+ puts ("## Not an ELF image, assuming binary\n");
+ /* leave addr as load_addr */
+ }
+
+ printf ("## Using bootline (@ 0x%lx): %s\n", bootaddr,
+ (char *) bootaddr);
+ printf ("## Starting vxWorks at 0x%08lx ...\n", addr);
+
+ ((void (*)(void)) addr) ();
+
+ puts ("## vxWorks terminated\n");
+ return 1;
+}
+
+/* ======================================================================
+ * Determine if a valid ELF image exists at the given memory location.
+ * First looks at the ELF header magic field, the makes sure that it is
+ * executable and makes sure that it is for a PowerPC.
+ * ====================================================================== */
+int valid_elf_image (unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+
+ /* -------------------------------------------------- */
+
+ ehdr = (Elf32_Ehdr *) addr;
+
+ if (!IS_ELF (*ehdr)) {
+ printf ("## No elf image at address 0x%08lx\n", addr);
+ return 0;
+ }
+
+ if (ehdr->e_type != ET_EXEC) {
+ printf ("## Not a 32-bit elf image at address 0x%08lx\n", addr);
+ return 0;
+ }
+
+#if 0
+ if (ehdr->e_machine != EM_PPC) {
+ printf ("## Not a PowerPC elf image at address 0x%08lx\n",
+ addr);
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+/* ======================================================================
+ * A very simple elf loader, assumes the image is valid, returns the
+ * entry point address.
+ * ====================================================================== */
+static unsigned long load_elf_image_phdr(unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ int i;
+
+ ehdr = (Elf32_Ehdr *) addr;
+ phdr = (Elf32_Phdr *) (addr + ehdr->e_phoff);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ void *dst = (void *) phdr->p_paddr;
+ void *src = (void *) addr + phdr->p_offset;
+ debug("Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ if (phdr->p_filesz != phdr->p_memsz)
+ memset(dst + phdr->p_filesz, 0x00, phdr->p_memsz - phdr->p_filesz);
+ flush_cache((unsigned long)dst, phdr->p_filesz);
+ ++phdr;
+ }
+
+ return ehdr->e_entry;
+}
+
+static unsigned long load_elf_image_shdr(unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Shdr *shdr; /* Section header structure pointer */
+ unsigned char *strtab = 0; /* String table pointer */
+ unsigned char *image; /* Binary image pointer */
+ int i; /* Loop counter */
+
+ /* -------------------------------------------------- */
+
+ ehdr = (Elf32_Ehdr *) addr;
+
+ /* Find the section header string table for output info */
+ shdr = (Elf32_Shdr *) (addr + ehdr->e_shoff +
+ (ehdr->e_shstrndx * sizeof (Elf32_Shdr)));
+
+ if (shdr->sh_type == SHT_STRTAB)
+ strtab = (unsigned char *) (addr + shdr->sh_offset);
+
+ /* Load each appropriate section */
+ for (i = 0; i < ehdr->e_shnum; ++i) {
+ shdr = (Elf32_Shdr *) (addr + ehdr->e_shoff +
+ (i * sizeof (Elf32_Shdr)));
+
+ if (!(shdr->sh_flags & SHF_ALLOC)
+ || shdr->sh_addr == 0 || shdr->sh_size == 0) {
+ continue;
+ }
+
+ if (strtab) {
+ debug("%sing %s @ 0x%08lx (%ld bytes)\n",
+ (shdr->sh_type == SHT_NOBITS) ?
+ "Clear" : "Load",
+ &strtab[shdr->sh_name],
+ (unsigned long) shdr->sh_addr,
+ (long) shdr->sh_size);
+ }
+
+ if (shdr->sh_type == SHT_NOBITS) {
+ memset ((void *)shdr->sh_addr, 0, shdr->sh_size);
+ } else {
+ image = (unsigned char *) addr + shdr->sh_offset;
+ memcpy ((void *) shdr->sh_addr,
+ (const void *) image,
+ shdr->sh_size);
+ }
+ flush_cache (shdr->sh_addr, shdr->sh_size);
+ }
+
+ return ehdr->e_entry;
+}
+
+/* ====================================================================== */
+U_BOOT_CMD(
+ bootelf, 3, 0, do_bootelf,
+ "Boot from an ELF image in memory",
+ "[-p|-s] [address]\n"
+ "\t- load ELF image at [address] via program headers (-p)\n"
+ "\t or via section headers (-s)"
+);
+
+U_BOOT_CMD(
+ bootvx, 2, 0, do_bootvx,
+ "Boot vxWorks from an ELF image",
+ " [address] - load address of vxWorks ELF image."
+);
diff --git a/u-boot/common/cmd_exit.c b/u-boot/common/cmd_exit.c
new file mode 100644
index 0000000..f3fc8f5
--- /dev/null
+++ b/u-boot/common/cmd_exit.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+int do_exit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int r;
+
+ r = 0;
+ if (argc > 1)
+ r = simple_strtoul(argv[1], NULL, 10);
+
+ return -r - 2;
+}
+
+U_BOOT_CMD(
+ exit, 2, 1, do_exit,
+ "exit script",
+ ""
+);
diff --git a/u-boot/common/cmd_ext2.c b/u-boot/common/cmd_ext2.c
new file mode 100644
index 0000000..35fb361
--- /dev/null
+++ b/u-boot/common/cmd_ext2.c
@@ -0,0 +1,260 @@
+/*
+ * (C) Copyright 2004
+ * esd gmbh <www.esd-electronics.com>
+ * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
+ *
+ * made from cmd_reiserfs by
+ *
+ * (C) Copyright 2003 - 2004
+ * Sysgo Real-Time Solutions, AG <www.elinos.com>
+ * Pavel Bartusek <pba@sysgo.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Ext2fs support
+ */
+#include <common.h>
+#include <part.h>
+#include <config.h>
+#include <command.h>
+#include <image.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <ext2fs.h>
+#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
+#include <usb.h>
+#endif
+
+#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
+#error DOS or EFI partition support must be selected
+#endif
+
+/* #define EXT2_DEBUG */
+
+#ifdef EXT2_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+int do_ext2ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int dev=0;
+ int part=1;
+ char *ep;
+ block_dev_desc_t *dev_desc=NULL;
+ int part_length;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ dev = (int)simple_strtoul (argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+
+ if (dev_desc == NULL) {
+ printf ("\n** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+
+ if (argc == 4)
+ filename = argv[3];
+
+ PRINTF("Using device %s %d:%d, directory: %s\n", argv[1], dev, part, filename);
+
+ if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) {
+ printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part);
+ ext2fs_close();
+ return 1;
+ }
+
+ if (!ext2fs_mount(part_length)) {
+ printf ("** Bad ext2 partition or disk - %s %d:%d **\n", argv[1], dev, part);
+ ext2fs_close();
+ return 1;
+ }
+
+ if (ext2fs_ls (filename)) {
+ printf ("** Error ext2fs_ls() **\n");
+ ext2fs_close();
+ return 1;
+ };
+
+ ext2fs_close();
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ ext2ls, 4, 1, do_ext2ls,
+ "list files in a directory (default /)",
+ "<interface> <dev[:part]> [directory]\n"
+ " - list files from 'dev' on 'interface' in a 'directory'"
+);
+
+/******************************************************************************
+ * Ext2fs boot command intepreter. Derived from diskboot
+ */
+int do_ext2load (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = NULL;
+ char *ep;
+ int dev, part = 1;
+ ulong addr = 0, part_length;
+ int filelen;
+ disk_partition_t info;
+ block_dev_desc_t *dev_desc = NULL;
+ char buf [12];
+ unsigned long count;
+ char *addr_str;
+
+ switch (argc) {
+ case 3:
+ addr_str = getenv("loadaddr");
+ if (addr_str != NULL)
+ addr = simple_strtoul (addr_str, NULL, 16);
+ else
+ addr = CONFIG_SYS_LOAD_ADDR;
+
+ filename = getenv ("bootfile");
+ count = 0;
+ break;
+ case 4:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = getenv ("bootfile");
+ count = 0;
+ break;
+ case 5:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = argv[4];
+ count = 0;
+ break;
+ case 6:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = argv[4];
+ count = simple_strtoul (argv[5], NULL, 16);
+ break;
+
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (!filename) {
+ puts ("** No boot file defined **\n");
+ return 1;
+ }
+
+ dev = (int)simple_strtoul (argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+ if (dev_desc==NULL) {
+ printf ("** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+
+ PRINTF("Using device %s%d, partition %d\n", argv[1], dev, part);
+
+ if (part != 0) {
+ if (get_partition_info (dev_desc, part, &info)) {
+ printf ("** Bad partition %d **\n", part);
+ return 1;
+ }
+
+ if (strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
+ printf ("** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ return 1;
+ }
+ printf ("Loading file \"%s\" "
+ "from %s device %d:%d (%.32s)\n",
+ filename,
+ argv[1], dev, part, info.name);
+ } else {
+ printf ("Loading file \"%s\" from %s device %d\n",
+ filename, argv[1], dev);
+ }
+
+
+ if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) {
+ printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part);
+ ext2fs_close();
+ return 1;
+ }
+
+ if (!ext2fs_mount(part_length)) {
+ printf ("** Bad ext2 partition or disk - %s %d:%d **\n",
+ argv[1], dev, part);
+ ext2fs_close();
+ return 1;
+ }
+
+ filelen = ext2fs_open(filename);
+ if (filelen < 0) {
+ printf("** File not found %s\n", filename);
+ ext2fs_close();
+ return 1;
+ }
+ if ((count < filelen) && (count != 0)) {
+ filelen = count;
+ }
+
+ if (ext2fs_read((char *)addr, filelen) != filelen) {
+ printf("** Unable to read \"%s\" from %s %d:%d **\n",
+ filename, argv[1], dev, part);
+ ext2fs_close();
+ return 1;
+ }
+
+ ext2fs_close();
+
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ printf ("%d bytes read\n", filelen);
+ sprintf(buf, "%X", filelen);
+ setenv("filesize", buf);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ ext2load, 6, 0, do_ext2load,
+ "load binary file from a Ext2 filesystem",
+ "<interface> <dev[:part]> [addr] [filename] [bytes]\n"
+ " - load binary file 'filename' from 'dev' on 'interface'\n"
+ " to address 'addr' from ext2 filesystem"
+);
diff --git a/u-boot/common/cmd_fat.c b/u-boot/common/cmd_fat.c
new file mode 100644
index 0000000..0220494
--- /dev/null
+++ b/u-boot/common/cmd_fat.c
@@ -0,0 +1,186 @@
+/*
+ * (C) Copyright 2002
+ * Richard Jones, rjones@nexus-tech.net
+ *
+ * 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <s_record.h>
+#include <net.h>
+#include <ata.h>
+#include <part.h>
+#include <fat.h>
+
+
+int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ long size;
+ unsigned long offset;
+ unsigned long count;
+ char buf [12];
+ block_dev_desc_t *dev_desc=NULL;
+ int dev=0;
+ int part=1;
+ char *ep;
+
+ if (argc < 5) {
+ printf( "usage: fatload <interface> <dev[:part]> "
+ "<addr> <filename> [bytes]\n");
+ return 1;
+ }
+
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+ if (dev_desc == NULL) {
+ puts("\n** Invalid boot device **\n");
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+ if (fat_register_device(dev_desc,part)!=0) {
+ printf("\n** Unable to use %s %d:%d for fatload **\n",
+ argv[1], dev, part);
+ return 1;
+ }
+ offset = simple_strtoul(argv[3], NULL, 16);
+ if (argc == 6)
+ count = simple_strtoul(argv[5], NULL, 16);
+ else
+ count = 0;
+ size = file_fat_read(argv[4], (unsigned char *)offset, count);
+
+ if(size==-1) {
+ printf("\n** Unable to read \"%s\" from %s %d:%d **\n",
+ argv[4], argv[1], dev, part);
+ return 1;
+ }
+
+ printf("\n%ld bytes read\n", size);
+
+ sprintf(buf, "%lX", size);
+ setenv("filesize", buf);
+
+ return 0;
+}
+
+
+U_BOOT_CMD(
+ fatload, 6, 0, do_fat_fsload,
+ "load binary file from a dos filesystem",
+ "<interface> <dev[:part]> <addr> <filename> [bytes]\n"
+ " - load binary file 'filename' from 'dev' on 'interface'\n"
+ " to address 'addr' from dos filesystem"
+);
+
+int do_fat_ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int ret;
+ int dev=0;
+ int part=1;
+ char *ep;
+ block_dev_desc_t *dev_desc=NULL;
+
+ if (argc < 3) {
+ printf("usage: fatls <interface> <dev[:part]> [directory]\n");
+ return 0;
+ }
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+ if (dev_desc == NULL) {
+ puts("\n** Invalid boot device **\n");
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+ if (fat_register_device(dev_desc,part)!=0) {
+ printf("\n** Unable to use %s %d:%d for fatls **\n",
+ argv[1], dev, part);
+ return 1;
+ }
+ if (argc == 4)
+ ret = file_fat_ls(argv[3]);
+ else
+ ret = file_fat_ls(filename);
+
+ if(ret!=0)
+ printf("No Fat FS detected\n");
+ return ret;
+}
+
+U_BOOT_CMD(
+ fatls, 4, 1, do_fat_ls,
+ "list files in a directory (default /)",
+ "<interface> <dev[:part]> [directory]\n"
+ " - list files from 'dev' on 'interface' in a 'directory'"
+);
+
+int do_fat_fsinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int dev=0;
+ int part=1;
+ char *ep;
+ block_dev_desc_t *dev_desc=NULL;
+
+ if (argc < 2) {
+ printf("usage: fatinfo <interface> <dev[:part]>\n");
+ return 0;
+ }
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+ if (dev_desc == NULL) {
+ puts("\n** Invalid boot device **\n");
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+ if (fat_register_device(dev_desc,part)!=0) {
+ printf("\n** Unable to use %s %d:%d for fatinfo **\n",
+ argv[1], dev, part);
+ return 1;
+ }
+ return file_fat_detectfs();
+}
+
+U_BOOT_CMD(
+ fatinfo, 3, 1, do_fat_fsinfo,
+ "print information about filesystem",
+ "<interface> <dev[:part]>\n"
+ " - print information about filesystem from 'dev' on 'interface'"
+);
diff --git a/u-boot/common/cmd_fdc.c b/u-boot/common/cmd_fdc.c
new file mode 100644
index 0000000..cdb050c
--- /dev/null
+++ b/u-boot/common/cmd_fdc.c
@@ -0,0 +1,846 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG, d.peter@mpl.ch.
+ *
+ * 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
+ *
+ */
+/*
+ * Floppy Disk support
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <image.h>
+
+
+#undef FDC_DEBUG
+
+#ifdef FDC_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*#if defined(CONFIG_CMD_DATE) */
+/*#include <rtc.h> */
+/*#endif */
+
+typedef struct {
+ int flags; /* connected drives ect */
+ unsigned long blnr; /* Logical block nr */
+ uchar drive; /* drive no */
+ uchar cmdlen; /* cmd length */
+ uchar cmd[16]; /* cmd desc */
+ uchar dma; /* if > 0 dma enabled */
+ uchar result[11]; /* status information */
+ uchar resultlen; /* lenght of result */
+} FDC_COMMAND_STRUCT;
+
+/* flags: only the lower 8bit used:
+ * bit 0 if set drive 0 is present
+ * bit 1 if set drive 1 is present
+ * bit 2 if set drive 2 is present
+ * bit 3 if set drive 3 is present
+ * bit 4 if set disk in drive 0 is inserted
+ * bit 5 if set disk in drive 1 is inserted
+ * bit 6 if set disk in drive 2 is inserted
+ * bit 7 if set disk in drive 4 is inserted
+ */
+
+/* cmd indexes */
+#define COMMAND 0
+#define DRIVE 1
+#define CONFIG0 1
+#define SPEC_HUTSRT 1
+#define TRACK 2
+#define CONFIG1 2
+#define SPEC_HLT 2
+#define HEAD 3
+#define CONFIG2 3
+#define SECTOR 4
+#define SECTOR_SIZE 5
+#define LAST_TRACK 6
+#define GAP 7
+#define DTL 8
+/* result indexes */
+#define STATUS_0 0
+#define STATUS_PCN 1
+#define STATUS_1 1
+#define STATUS_2 2
+#define STATUS_TRACK 3
+#define STATUS_HEAD 4
+#define STATUS_SECT 5
+#define STATUS_SECT_SIZE 6
+
+
+/* Register addresses */
+#define FDC_BASE 0x3F0
+#define FDC_SRA FDC_BASE + 0 /* Status Register A */
+#define FDC_SRB FDC_BASE + 1 /* Status Register B */
+#define FDC_DOR FDC_BASE + 2 /* Digital Output Register */
+#define FDC_TDR FDC_BASE + 3 /* Tape Drive Register */
+#define FDC_DSR FDC_BASE + 4 /* Data rate Register */
+#define FDC_MSR FDC_BASE + 4 /* Main Status Register */
+#define FDC_FIFO FDC_BASE + 5 /* FIFO */
+#define FDC_DIR FDC_BASE + 6 /* Digital Input Register */
+#define FDC_CCR FDC_BASE + 7 /* Configuration Control */
+/* Commands */
+#define FDC_CMD_SENSE_INT 0x08
+#define FDC_CMD_CONFIGURE 0x13
+#define FDC_CMD_SPECIFY 0x03
+#define FDC_CMD_RECALIBRATE 0x07
+#define FDC_CMD_READ 0x06
+#define FDC_CMD_READ_TRACK 0x02
+#define FDC_CMD_READ_ID 0x0A
+#define FDC_CMD_DUMP_REG 0x0E
+#define FDC_CMD_SEEK 0x0F
+
+#define FDC_CMD_SENSE_INT_LEN 0x01
+#define FDC_CMD_CONFIGURE_LEN 0x04
+#define FDC_CMD_SPECIFY_LEN 0x03
+#define FDC_CMD_RECALIBRATE_LEN 0x02
+#define FDC_CMD_READ_LEN 0x09
+#define FDC_CMD_READ_TRACK_LEN 0x09
+#define FDC_CMD_READ_ID_LEN 0x02
+#define FDC_CMD_DUMP_REG_LEN 0x01
+#define FDC_CMD_SEEK_LEN 0x03
+
+#define FDC_FIFO_THR 0x0C
+#define FDC_FIFO_DIS 0x00
+#define FDC_IMPLIED_SEEK 0x01
+#define FDC_POLL_DIS 0x00
+#define FDC_PRE_TRK 0x00
+#define FDC_CONFIGURE FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)
+#define FDC_MFM_MODE 0x01 /* MFM enable */
+#define FDC_SKIP_MODE 0x00 /* skip enable */
+
+#define FDC_TIME_OUT 100000 /* time out */
+#define FDC_RW_RETRIES 3 /* read write retries */
+#define FDC_CAL_RETRIES 3 /* calibration and seek retries */
+
+
+/* Disk structure */
+typedef struct {
+ unsigned int size; /* nr of sectors total */
+ unsigned int sect; /* sectors per track */
+ unsigned int head; /* nr of heads */
+ unsigned int track; /* nr of tracks */
+ unsigned int stretch; /* !=0 means double track steps */
+ unsigned char gap; /* gap1 size */
+ unsigned char rate; /* data rate. |= 0x40 for perpendicular */
+ unsigned char spec1; /* stepping rate, head unload time */
+ unsigned char fmt_gap;/* gap2 size */
+ unsigned char hlt; /* head load time */
+ unsigned char sect_code;/* Sector Size code */
+ const char * name; /* used only for predefined formats */
+} FD_GEO_STRUCT;
+
+
+/* supported Floppy types (currently only one) */
+const static FD_GEO_STRUCT floppy_type[2] = {
+ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" }, /* 7 1.44MB 3.5" */
+ { 0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL }, /* end of table */
+};
+
+static FDC_COMMAND_STRUCT cmd; /* global command struct */
+
+/* If the boot drive number is undefined, we assume it's drive 0 */
+#ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
+#define CONFIG_SYS_FDC_DRIVE_NUMBER 0
+#endif
+
+/* Hardware access */
+#ifndef CONFIG_SYS_ISA_IO_STRIDE
+#define CONFIG_SYS_ISA_IO_STRIDE 1
+#endif
+
+#ifndef CONFIG_SYS_ISA_IO_OFFSET
+#define CONFIG_SYS_ISA_IO_OFFSET 0
+#endif
+
+/* Supporting Functions */
+/* reads a Register of the FDC */
+unsigned char read_fdc_reg(unsigned int addr)
+{
+ volatile unsigned char *val =
+ (volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
+ (addr * CONFIG_SYS_ISA_IO_STRIDE) +
+ CONFIG_SYS_ISA_IO_OFFSET);
+
+ return val [0];
+}
+
+/* writes a Register of the FDC */
+void write_fdc_reg(unsigned int addr, unsigned char val)
+{
+ volatile unsigned char *tmp =
+ (volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
+ (addr * CONFIG_SYS_ISA_IO_STRIDE) +
+ CONFIG_SYS_ISA_IO_OFFSET);
+ tmp[0]=val;
+}
+
+/* waits for an interrupt (polling) */
+int wait_for_fdc_int(void)
+{
+ unsigned long timeout;
+ timeout = FDC_TIME_OUT;
+ while((read_fdc_reg(FDC_SRA)&0x80)==0) {
+ timeout--;
+ udelay(10);
+ if(timeout==0) /* timeout occured */
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* reads a byte from the FIFO of the FDC and checks direction and RQM bit
+ of the MSR. returns -1 if timeout, or byte if ok */
+int read_fdc_byte(void)
+{
+ unsigned long timeout;
+ timeout = FDC_TIME_OUT;
+ while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
+ /* direction out and ready */
+ udelay(10);
+ timeout--;
+ if(timeout==0) /* timeout occured */
+ return -1;
+ }
+ return read_fdc_reg(FDC_FIFO);
+}
+
+/* if the direction of the FIFO is wrong, this routine is used to
+ empty the FIFO. Should _not_ be used */
+int fdc_need_more_output(void)
+{
+ unsigned char c;
+ while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0) {
+ c=(unsigned char)read_fdc_byte();
+ printf("Error: more output: %x\n",c);
+ }
+ return TRUE;
+}
+
+
+/* writes a byte to the FIFO of the FDC and checks direction and RQM bit
+ of the MSR */
+int write_fdc_byte(unsigned char val)
+{
+ unsigned long timeout;
+ timeout = FDC_TIME_OUT;
+ while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) {
+ /* direction in and ready for byte */
+ timeout--;
+ udelay(10);
+ fdc_need_more_output();
+ if(timeout==0) /* timeout occured */
+ return FALSE;
+ }
+ write_fdc_reg(FDC_FIFO,val);
+ return TRUE;
+}
+
+/* sets up all FDC commands and issues it to the FDC. If
+ the command causes direct results (no Execution Phase)
+ the result is be read as well. */
+
+int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
+{
+ int i;
+ unsigned long head,track,sect,timeout;
+ track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */
+ sect = pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */
+ head = sect / pFG->sect; /* head nr */
+ sect = sect % pFG->sect; /* remaining blocks */
+ sect++; /* sectors are 1 based */
+ PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",
+ pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr);
+
+ if(head|=0) { /* max heads = 2 */
+ pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */
+ pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
+ }
+ else {
+ pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */
+ pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
+ }
+ pCMD->cmd[TRACK]=(unsigned char) track; /* track */
+ switch (pCMD->cmd[COMMAND]) {
+ case FDC_CMD_READ:
+ pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */
+ pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */
+ pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */
+ pCMD->cmd[GAP]=pFG->gap; /* gap */
+ pCMD->cmd[DTL]=0xFF; /* DTL */
+ pCMD->cmdlen=FDC_CMD_READ_LEN;
+ pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
+ pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */
+ pCMD->resultlen=0; /* result only after execution */
+ break;
+ case FDC_CMD_SEEK:
+ pCMD->cmdlen=FDC_CMD_SEEK_LEN;
+ pCMD->resultlen=0; /* no result */
+ break;
+ case FDC_CMD_CONFIGURE:
+ pCMD->cmd[CONFIG0]=0;
+ pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */
+ pCMD->cmd[CONFIG2]=FDC_PRE_TRK; /* Precompensation Track */
+ pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN;
+ pCMD->resultlen=0; /* no result */
+ break;
+ case FDC_CMD_SPECIFY:
+ pCMD->cmd[SPEC_HUTSRT]=pFG->spec1;
+ pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */
+ if(pCMD->dma==0)
+ pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */
+ pCMD->cmdlen=FDC_CMD_SPECIFY_LEN;
+ pCMD->resultlen=0; /* no result */
+ break;
+ case FDC_CMD_DUMP_REG:
+ pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN;
+ pCMD->resultlen=10; /* 10 byte result */
+ break;
+ case FDC_CMD_READ_ID:
+ pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
+ pCMD->cmdlen=FDC_CMD_READ_ID_LEN;
+ pCMD->resultlen=7; /* 7 byte result */
+ break;
+ case FDC_CMD_RECALIBRATE:
+ pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */
+ pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN;
+ pCMD->resultlen=0; /* no result */
+ break;
+ break;
+ case FDC_CMD_SENSE_INT:
+ pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN;
+ pCMD->resultlen=2;
+ break;
+ }
+ for(i=0;i<pCMD->cmdlen;i++) {
+ /* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */
+ if(write_fdc_byte(pCMD->cmd[i])==FALSE) {
+ PRINTF("Error: timeout while issue cmd%d\n",i);
+ return FALSE;
+ }
+ }
+ timeout=FDC_TIME_OUT;
+ for(i=0;i<pCMD->resultlen;i++) {
+ while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
+ timeout--;
+ if(timeout==0) {
+ PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR));
+ return FALSE;
+ }
+ }
+ pCMD->result[i]=(unsigned char)read_fdc_byte();
+ }
+ return TRUE;
+}
+
+/* selects the drive assigned in the cmd structur and
+ switches on the Motor */
+void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
+{
+ unsigned char val;
+
+ val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */
+ if((read_fdc_reg(FDC_DOR)&val)!=val) {
+ write_fdc_reg(FDC_DOR,val);
+ for(val=0;val<255;val++)
+ udelay(500); /* wait some time to start motor */
+ }
+}
+
+/* switches off the Motor of the specified drive */
+void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
+{
+ unsigned char val;
+
+ val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */
+ write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));
+}
+
+/* issues a recalibrate command, waits for interrupt and
+ * issues a sense_interrupt */
+int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
+{
+ pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE)
+ return FALSE;
+ while(wait_for_fdc_int()!=TRUE);
+ pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
+ return(fdc_issue_cmd(pCMD,pFG));
+}
+
+/* issues a recalibrate command, waits for interrupt and
+ * issues a sense_interrupt */
+int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
+{
+ pCMD->cmd[COMMAND]=FDC_CMD_SEEK;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE)
+ return FALSE;
+ while(wait_for_fdc_int()!=TRUE);
+ pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
+ return(fdc_issue_cmd(pCMD,pFG));
+}
+
+/* terminates current command, by not servicing the FIFO
+ * waits for interrupt and fills in the result bytes */
+int fdc_terminate(FDC_COMMAND_STRUCT *pCMD)
+{
+ int i;
+ for(i=0;i<100;i++)
+ udelay(500); /* wait 500usec for fifo overrun */
+ while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occured */
+ for(i=0;i<7;i++) {
+ pCMD->result[i]=(unsigned char)read_fdc_byte();
+ }
+ return TRUE;
+}
+
+/* reads data from FDC, seek commands are issued automatic */
+int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
+{
+ /* first seek to start address */
+ unsigned long len,lastblk,readblk,i,timeout,ii,offset;
+ unsigned char pcn,c,retriesrw,retriescal;
+ unsigned char *bufferw; /* working buffer */
+ int sect_size;
+ int flags;
+
+ flags=disable_interrupts(); /* switch off all Interrupts */
+ select_fdc_drive(pCMD); /* switch on drive */
+ sect_size=0x080<<pFG->sect_code;
+ retriesrw=0;
+ retriescal=0;
+ offset=0;
+ if(fdc_seek(pCMD,pFG)==FALSE) {
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ if((pCMD->result[STATUS_0]&0x20)!=0x20) {
+ printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ pcn=pCMD->result[STATUS_PCN]; /* current track */
+ /* now determine the next seek point */
+ lastblk=pCMD->blnr + blocks;
+ /* readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
+ readblk=pFG->sect-(pCMD->blnr%pFG->sect);
+ PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr);
+ if(readblk>blocks) /* is end within 1st track */
+ readblk=blocks; /* yes, correct it */
+ PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr);
+ bufferw = &buffer[0]; /* setup working buffer */
+ do {
+retryrw:
+ len=sect_size * readblk;
+ pCMD->cmd[COMMAND]=FDC_CMD_READ;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE) {
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ for (i=0;i<len;i++) {
+ timeout=FDC_TIME_OUT;
+ do {
+ c=read_fdc_reg(FDC_MSR);
+ if((c&0xC0)==0xC0) {
+ bufferw[i]=read_fdc_reg(FDC_FIFO);
+ break;
+ }
+ if((c&0xC0)==0x80) { /* output */
+ PRINTF("Transfer error transfered: at %ld, MSR=%02X\n",i,c);
+ if(i>6) {
+ for(ii=0;ii<7;ii++) {
+ pCMD->result[ii]=bufferw[(i-7+ii)];
+ } /* for */
+ }
+ if(retriesrw++>FDC_RW_RETRIES) {
+ if (retriescal++>FDC_CAL_RETRIES) {
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ else {
+ PRINTF(" trying to recalibrate Try %d\n",retriescal);
+ if(fdc_recalibrate(pCMD,pFG)==FALSE) {
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ retriesrw=0;
+ goto retrycal;
+ } /* else >FDC_CAL_RETRIES */
+ }
+ else {
+ PRINTF("Read retry %d\n",retriesrw);
+ goto retryrw;
+ } /* else >FDC_RW_RETRIES */
+ }/* if output */
+ timeout--;
+ }while(TRUE);
+ } /* for len */
+ /* the last sector of a track or all data has been read,
+ * we need to get the results */
+ fdc_terminate(pCMD);
+ offset+=(sect_size*readblk); /* set up buffer pointer */
+ bufferw = &buffer[offset];
+ pCMD->blnr+=readblk; /* update current block nr */
+ blocks-=readblk; /* update blocks */
+ if(blocks==0)
+ break; /* we are finish */
+ /* setup new read blocks */
+ /* readblk=pFG->head*pFG->sect; */
+ readblk=pFG->sect;
+ if(readblk>blocks)
+ readblk=blocks;
+retrycal:
+ /* a seek is necessary */
+ if(fdc_seek(pCMD,pFG)==FALSE) {
+ stop_fdc_drive(pCMD);
+ enable_interrupts();
+ return FALSE;
+ }
+ if((pCMD->result[STATUS_0]&0x20)!=0x20) {
+ PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
+ stop_fdc_drive(pCMD);
+ return FALSE;
+ }
+ pcn=pCMD->result[STATUS_PCN]; /* current track */
+ }while(TRUE); /* start over */
+ stop_fdc_drive(pCMD); /* switch off drive */
+ enable_interrupts();
+ return TRUE;
+}
+
+/* Scan all drives and check if drive is present and disk is inserted */
+int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
+{
+ int i,drives,state;
+ /* OK procedure of data book is satisfied.
+ * trying to get some information over the drives */
+ state=0; /* no drives, no disks */
+ for(drives=0;drives<4;drives++) {
+ pCMD->drive=drives;
+ select_fdc_drive(pCMD);
+ pCMD->blnr=0; /* set to the 1st block */
+ if(fdc_recalibrate(pCMD,pFG)==FALSE)
+ continue;
+ if((pCMD->result[STATUS_0]&0x10)==0x10)
+ continue;
+ /* ok drive connected check for disk */
+ state|=(1<<drives);
+ pCMD->blnr=pFG->size; /* set to the last block */
+ if(fdc_seek(pCMD,pFG)==FALSE)
+ continue;
+ pCMD->blnr=0; /* set to the 1st block */
+ if(fdc_recalibrate(pCMD,pFG)==FALSE)
+ continue;
+ pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE)
+ continue;
+ state|=(0x10<<drives);
+ }
+ stop_fdc_drive(pCMD);
+ for(i=0;i<4;i++) {
+ PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
+ ((state&(1<<i))==(1<<i)) ? "":"not ",
+ ((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
+ ((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
+ }
+ pCMD->flags=state;
+ return TRUE;
+}
+
+
+/**************************************************************************
+* int fdc_setup
+* setup the fdc according the datasheet
+* assuming in PS2 Mode
+*/
+int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
+{
+ int i;
+
+#ifdef CONFIG_SYS_FDC_HW_INIT
+ fdc_hw_init ();
+#endif
+ /* first, we reset the FDC via the DOR */
+ write_fdc_reg(FDC_DOR,0x00);
+ for(i=0; i<255; i++) /* then we wait some time */
+ udelay(500);
+ /* then, we clear the reset in the DOR */
+ pCMD->drive=drive;
+ select_fdc_drive(pCMD);
+ /* initialize the CCR */
+ write_fdc_reg(FDC_CCR,pFG->rate);
+ /* then initialize the DSR */
+ write_fdc_reg(FDC_DSR,pFG->rate);
+ if(wait_for_fdc_int()==FALSE) {
+ PRINTF("Time Out after writing CCR\n");
+ return FALSE;
+ }
+ /* now issue sense Interrupt and status command
+ * assuming only one drive present (drive 0) */
+ pCMD->dma=0; /* we don't use any dma at all */
+ for(i=0;i<4;i++) {
+ /* issue sense interrupt for all 4 possible drives */
+ pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE) {
+ PRINTF("Sense Interrupt for drive %d failed\n",i);
+ }
+ }
+ /* issue the configure command */
+ pCMD->drive=drive;
+ select_fdc_drive(pCMD);
+ pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE) {
+ PRINTF(" configure timeout\n");
+ stop_fdc_drive(pCMD);
+ return FALSE;
+ }
+ /* issue specify command */
+ pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
+ if(fdc_issue_cmd(pCMD,pFG)==FALSE) {
+ PRINTF(" specify timeout\n");
+ stop_fdc_drive(pCMD);
+ return FALSE;
+
+ }
+ /* then, we clear the reset in the DOR */
+ /* fdc_check_drive(pCMD,pFG); */
+ /* write_fdc_reg(FDC_DOR,0x04); */
+
+ return TRUE;
+}
+
+#if defined(CONFIG_CMD_FDOS)
+
+/* Low level functions for the Floppy-DOS layer */
+
+/**************************************************************************
+* int fdc_fdos_init
+* initialize the FDC layer
+*
+*/
+int fdc_fdos_init (int drive)
+{
+ FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
+ FDC_COMMAND_STRUCT *pCMD = &cmd;
+
+ /* setup FDC and scan for drives */
+ if(fdc_setup(drive,pCMD,pFG)==FALSE) {
+ printf("\n** Error in setup FDC **\n");
+ return FALSE;
+ }
+ if(fdc_check_drive(pCMD,pFG)==FALSE) {
+ printf("\n** Error in check_drives **\n");
+ return FALSE;
+ }
+ if((pCMD->flags&(1<<drive))==0) {
+ /* drive not available */
+ printf("\n** Drive %d not available **\n",drive);
+ return FALSE;
+ }
+ if((pCMD->flags&(0x10<<drive))==0) {
+ /* no disk inserted */
+ printf("\n** No disk inserted in drive %d **\n",drive);
+ return FALSE;
+ }
+ /* ok, we have a valid source */
+ pCMD->drive=drive;
+
+ /* read first block */
+ pCMD->blnr=0;
+ return TRUE;
+}
+/**************************************************************************
+* int fdc_fdos_seek
+* parameter is a block number
+*/
+int fdc_fdos_seek (int where)
+{
+ FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
+ FDC_COMMAND_STRUCT *pCMD = &cmd;
+
+ pCMD -> blnr = where ;
+ return (fdc_seek (pCMD, pFG));
+}
+/**************************************************************************
+* int fdc_fdos_read
+* the length is in block number
+*/
+int fdc_fdos_read (void *buffer, int len)
+{
+ FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
+ FDC_COMMAND_STRUCT *pCMD = &cmd;
+
+ return (fdc_read_data (buffer, len, pCMD, pFG));
+}
+#endif
+
+#if defined(CONFIG_CMD_FDC)
+/****************************************************************************
+ * main routine do_fdcboot
+ */
+int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
+ FDC_COMMAND_STRUCT *pCMD = &cmd;
+ unsigned long addr,imsize;
+ image_header_t *hdr; /* used for fdc boot */
+ unsigned char boot_drive;
+ int i,nrofblk;
+ char *ep;
+ int rcode = 0;
+#if defined(CONFIG_FIT)
+ const void *fit_hdr = NULL;
+#endif
+
+ switch (argc) {
+ case 1:
+ addr = CONFIG_SYS_LOAD_ADDR;
+ boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_drive=simple_strtoul(argv[2], NULL, 10);
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ /* setup FDC and scan for drives */
+ if(fdc_setup(boot_drive,pCMD,pFG)==FALSE) {
+ printf("\n** Error in setup FDC **\n");
+ return 1;
+ }
+ if(fdc_check_drive(pCMD,pFG)==FALSE) {
+ printf("\n** Error in check_drives **\n");
+ return 1;
+ }
+ if((pCMD->flags&(1<<boot_drive))==0) {
+ /* drive not available */
+ printf("\n** Drive %d not availabe **\n",boot_drive);
+ return 1;
+ }
+ if((pCMD->flags&(0x10<<boot_drive))==0) {
+ /* no disk inserted */
+ printf("\n** No disk inserted in drive %d **\n",boot_drive);
+ return 1;
+ }
+ /* ok, we have a valid source */
+ pCMD->drive=boot_drive;
+ /* read first block */
+ pCMD->blnr=0;
+ if(fdc_read_data((unsigned char *)addr,1,pCMD,pFG)==FALSE) {
+ printf("\nRead error:");
+ for(i=0;i<7;i++)
+ printf("result%d: 0x%02X\n",i,pCMD->result[i]);
+ return 1;
+ }
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+ image_print_contents (hdr);
+
+ imsize = image_get_image_size (hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (const void *)addr;
+ puts ("Fit image detected...\n");
+
+ imsize = fit_get_size (fit_hdr);
+ break;
+#endif
+ default:
+ puts ("** Unknown image type\n");
+ return 1;
+ }
+
+ nrofblk=imsize/512;
+ if((imsize%512)>0)
+ nrofblk++;
+ printf("Loading %ld Bytes (%d blocks) at 0x%08lx..\n",imsize,nrofblk,addr);
+ pCMD->blnr=0;
+ if(fdc_read_data((unsigned char *)addr,nrofblk,pCMD,pFG)==FALSE) {
+ /* read image block */
+ printf("\nRead error:");
+ for(i=0;i<7;i++)
+ printf("result%d: 0x%02X\n",i,pCMD->result[i]);
+ return 1;
+ }
+ printf("OK %ld Bytes loaded.\n",imsize);
+
+ flush_cache (addr, imsize);
+
+#if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+ if (!fit_check_format (fit_hdr)) {
+ puts ("** Bad FIT image format\n");
+ return 1;
+ }
+ fit_print_contents (fit_hdr);
+ }
+#endif
+
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+ char *local_args[2];
+
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+
+ printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+ do_bootm (cmdtp, 0, 1, local_args);
+ rcode ++;
+ }
+ return rcode;
+}
+
+U_BOOT_CMD(
+ fdcboot, 3, 1, do_fdcboot,
+ "boot from floppy device",
+ "loadAddr drive"
+);
+#endif
diff --git a/u-boot/common/cmd_fdos.c b/u-boot/common/cmd_fdos.c
new file mode 100644
index 0000000..2af4ca0
--- /dev/null
+++ b/u-boot/common/cmd_fdos.c
@@ -0,0 +1,151 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Dos floppy support
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <fdc.h>
+
+/*-----------------------------------------------------------------------------
+ * do_fdosboot --
+ *-----------------------------------------------------------------------------
+ */
+int do_fdosboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *name;
+ char *ep;
+ int size;
+ int rcode = 0;
+ char buf [12];
+ int drive = CONFIG_SYS_FDC_DRIVE_NUMBER;
+
+ /* pre-set load_addr */
+ if ((ep = getenv("loadaddr")) != NULL) {
+ load_addr = simple_strtoul(ep, NULL, 16);
+ }
+
+ /* pre-set Boot file name */
+ if ((name = getenv("bootfile")) == NULL) {
+ name = "uImage";
+ }
+
+ switch (argc) {
+ case 1:
+ break;
+ case 2:
+ /* only one arg - accept two forms:
+ * just load address, or just boot file name.
+ * The latter form must be written "filename" here.
+ */
+ if (argv[1][0] == '"') { /* just boot filename */
+ name = argv [1];
+ } else { /* load address */
+ load_addr = simple_strtoul(argv[1], NULL, 16);
+ }
+ break;
+ case 3:
+ load_addr = simple_strtoul(argv[1], NULL, 16);
+ name = argv [2];
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ /* Init physical layer */
+ if (!fdc_fdos_init (drive)) {
+ return (-1);
+ }
+
+ /* Open file */
+ if (dos_open (name) < 0) {
+ printf ("Unable to open %s\n", name);
+ return 1;
+ }
+ if ((size = dos_read (load_addr)) < 0) {
+ printf ("boot error\n");
+ return 1;
+ }
+ flush_cache (load_addr, size);
+
+ sprintf(buf, "%x", size);
+ setenv("filesize", buf);
+
+ printf("Floppy DOS load complete: %d bytes loaded to 0x%lx\n",
+ size, load_addr);
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+ char *local_args[2];
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+ printf ("Automatic boot of image at addr 0x%08lX ...\n", load_addr);
+ rcode = do_bootm (cmdtp, 0, 1, local_args);
+ }
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------------
+ * do_fdosls --
+ *-----------------------------------------------------------------------------
+ */
+int do_fdosls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *path = "";
+ int drive = CONFIG_SYS_FDC_DRIVE_NUMBER;
+
+ switch (argc) {
+ case 1:
+ break;
+ case 2:
+ path = argv [1];
+ break;
+ }
+
+ /* Init physical layer */
+ if (!fdc_fdos_init (drive)) {
+ return (-1);
+ }
+ /* Open directory */
+ if (dos_open (path) < 0) {
+ printf ("Unable to open %s\n", path);
+ return 1;
+ }
+ return (dos_dir ());
+}
+
+U_BOOT_CMD(
+ fdosboot, 3, 0, do_fdosboot,
+ "boot from a dos floppy file",
+ "[loadAddr] [filename]"
+);
+
+U_BOOT_CMD(
+ fdosls, 2, 0, do_fdosls,
+ "list files in a directory",
+ "[directory]"
+);
diff --git a/u-boot/common/cmd_fdt.c b/u-boot/common/cmd_fdt.c
new file mode 100644
index 0000000..3d0c2b7
--- /dev/null
+++ b/u-boot/common/cmd_fdt.c
@@ -0,0 +1,829 @@
+/*
+ * (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ * Based on code written by:
+ * Pantelis Antoniou <pantelis.antoniou@gmail.com> and
+ * Matthew McClintock <msm@freescale.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <asm/global_data.h>
+#include <fdt.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+#define MAX_LEVEL 32 /* how deeply nested we will go */
+#define SCRATCHPAD 1024 /* bytes of scratchpad memory */
+
+/*
+ * Global data (for the gd->bd)
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+static int fdt_valid(void);
+static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);
+static int fdt_print(const char *pathp, char *prop, int depth);
+
+/*
+ * The working_fdt points to our working flattened device tree.
+ */
+struct fdt_header *working_fdt;
+
+void set_working_fdt_addr(void *addr)
+{
+ char buf[17];
+
+ working_fdt = addr;
+
+ sprintf(buf, "%lx", (unsigned long)addr);
+ setenv("fdtaddr", buf);
+}
+
+/*
+ * Flattened Device Tree command, see the help for parameter definitions.
+ */
+int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Set the address of the fdt
+ */
+ if (argv[1][0] == 'a') {
+ unsigned long addr;
+ /*
+ * Set the address [and length] of the fdt.
+ */
+ if (argc == 2) {
+ if (!fdt_valid()) {
+ return 1;
+ }
+ printf("The address of the fdt is %p\n", working_fdt);
+ return 0;
+ }
+
+ addr = simple_strtoul(argv[2], NULL, 16);
+ set_working_fdt_addr((void *)addr);
+
+ if (!fdt_valid()) {
+ return 1;
+ }
+
+ if (argc >= 4) {
+ int len;
+ int err;
+ /*
+ * Optional new length
+ */
+ len = simple_strtoul(argv[3], NULL, 16);
+ if (len < fdt_totalsize(working_fdt)) {
+ printf ("New length %d < existing length %d, "
+ "ignoring.\n",
+ len, fdt_totalsize(working_fdt));
+ } else {
+ /*
+ * Open in place with a new length.
+ */
+ err = fdt_open_into(working_fdt, working_fdt, len);
+ if (err != 0) {
+ printf ("libfdt fdt_open_into(): %s\n",
+ fdt_strerror(err));
+ }
+ }
+ }
+
+ /*
+ * Move the working_fdt
+ */
+ } else if (strncmp(argv[1], "mo", 2) == 0) {
+ struct fdt_header *newaddr;
+ int len;
+ int err;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Set the address and length of the fdt.
+ */
+ working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
+ if (!fdt_valid()) {
+ return 1;
+ }
+
+ newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);
+
+ /*
+ * If the user specifies a length, use that. Otherwise use the
+ * current length.
+ */
+ if (argc <= 4) {
+ len = fdt_totalsize(working_fdt);
+ } else {
+ len = simple_strtoul(argv[4], NULL, 16);
+ if (len < fdt_totalsize(working_fdt)) {
+ printf ("New length 0x%X < existing length "
+ "0x%X, aborting.\n",
+ len, fdt_totalsize(working_fdt));
+ return 1;
+ }
+ }
+
+ /*
+ * Copy to the new location.
+ */
+ err = fdt_open_into(working_fdt, newaddr, len);
+ if (err != 0) {
+ printf ("libfdt fdt_open_into(): %s\n",
+ fdt_strerror(err));
+ return 1;
+ }
+ working_fdt = newaddr;
+
+ /*
+ * Make a new node
+ */
+ } else if (strncmp(argv[1], "mk", 2) == 0) {
+ char *pathp; /* path */
+ char *nodep; /* new node to add */
+ int nodeoffset; /* node offset from libfdt */
+ int err;
+
+ /*
+ * Parameters: Node path, new node to be appended to the path.
+ */
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ pathp = argv[2];
+ nodep = argv[3];
+
+ nodeoffset = fdt_path_offset (working_fdt, pathp);
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return 1;
+ }
+ err = fdt_add_subnode(working_fdt, nodeoffset, nodep);
+ if (err < 0) {
+ printf ("libfdt fdt_add_subnode(): %s\n",
+ fdt_strerror(err));
+ return 1;
+ }
+
+ /*
+ * Set the value of a property in the working_fdt.
+ */
+ } else if (argv[1][0] == 's') {
+ char *pathp; /* path */
+ char *prop; /* property */
+ int nodeoffset; /* node offset from libfdt */
+ static char data[SCRATCHPAD]; /* storage for the property */
+ int len; /* new length of the property */
+ int ret; /* return value */
+
+ /*
+ * Parameters: Node path, property, optional value.
+ */
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ pathp = argv[2];
+ prop = argv[3];
+ if (argc == 4) {
+ len = 0;
+ } else {
+ ret = fdt_parse_prop(&argv[4], argc - 4, data, &len);
+ if (ret != 0)
+ return ret;
+ }
+
+ nodeoffset = fdt_path_offset (working_fdt, pathp);
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return 1;
+ }
+
+ ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len);
+ if (ret < 0) {
+ printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
+ return 1;
+ }
+
+ /*
+ * Print (recursive) / List (single level)
+ */
+ } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
+ int depth = MAX_LEVEL; /* how deep to print */
+ char *pathp; /* path */
+ char *prop; /* property */
+ int ret; /* return value */
+ static char root[2] = "/";
+
+ /*
+ * list is an alias for print, but limited to 1 level
+ */
+ if (argv[1][0] == 'l') {
+ depth = 1;
+ }
+
+ /*
+ * Get the starting path. The root node is an oddball,
+ * the offset is zero and has no name.
+ */
+ if (argc == 2)
+ pathp = root;
+ else
+ pathp = argv[2];
+ if (argc > 3)
+ prop = argv[3];
+ else
+ prop = NULL;
+
+ ret = fdt_print(pathp, prop, depth);
+ if (ret != 0)
+ return ret;
+
+ /*
+ * Remove a property/node
+ */
+ } else if (strncmp(argv[1], "rm", 2) == 0) {
+ int nodeoffset; /* node offset from libfdt */
+ int err;
+
+ /*
+ * Get the path. The root node is an oddball, the offset
+ * is zero and has no name.
+ */
+ nodeoffset = fdt_path_offset (working_fdt, argv[2]);
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return 1;
+ }
+ /*
+ * Do the delete. A fourth parameter means delete a property,
+ * otherwise delete the node.
+ */
+ if (argc > 3) {
+ err = fdt_delprop(working_fdt, nodeoffset, argv[3]);
+ if (err < 0) {
+ printf("libfdt fdt_delprop(): %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ } else {
+ err = fdt_del_node(working_fdt, nodeoffset);
+ if (err < 0) {
+ printf("libfdt fdt_del_node(): %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ }
+
+ /*
+ * Display header info
+ */
+ } else if (argv[1][0] == 'h') {
+ u32 version = fdt_version(working_fdt);
+ printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt));
+ printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt),
+ fdt_totalsize(working_fdt));
+ printf("off_dt_struct:\t\t0x%x\n",
+ fdt_off_dt_struct(working_fdt));
+ printf("off_dt_strings:\t\t0x%x\n",
+ fdt_off_dt_strings(working_fdt));
+ printf("off_mem_rsvmap:\t\t0x%x\n",
+ fdt_off_mem_rsvmap(working_fdt));
+ printf("version:\t\t%d\n", version);
+ printf("last_comp_version:\t%d\n",
+ fdt_last_comp_version(working_fdt));
+ if (version >= 2)
+ printf("boot_cpuid_phys:\t0x%x\n",
+ fdt_boot_cpuid_phys(working_fdt));
+ if (version >= 3)
+ printf("size_dt_strings:\t0x%x\n",
+ fdt_size_dt_strings(working_fdt));
+ if (version >= 17)
+ printf("size_dt_struct:\t\t0x%x\n",
+ fdt_size_dt_struct(working_fdt));
+ printf("number mem_rsv:\t\t0x%x\n",
+ fdt_num_mem_rsv(working_fdt));
+ printf("\n");
+
+ /*
+ * Set boot cpu id
+ */
+ } else if (strncmp(argv[1], "boo", 3) == 0) {
+ unsigned long tmp = simple_strtoul(argv[2], NULL, 16);
+ fdt_set_boot_cpuid_phys(working_fdt, tmp);
+
+ /*
+ * memory command
+ */
+ } else if (strncmp(argv[1], "me", 2) == 0) {
+ uint64_t addr, size;
+ int err;
+ addr = simple_strtoull(argv[2], NULL, 16);
+ size = simple_strtoull(argv[3], NULL, 16);
+ err = fdt_fixup_memory(working_fdt, addr, size);
+ if (err < 0)
+ return err;
+
+ /*
+ * mem reserve commands
+ */
+ } else if (strncmp(argv[1], "rs", 2) == 0) {
+ if (argv[2][0] == 'p') {
+ uint64_t addr, size;
+ int total = fdt_num_mem_rsv(working_fdt);
+ int j, err;
+ printf("index\t\t start\t\t size\n");
+ printf("-------------------------------"
+ "-----------------\n");
+ for (j = 0; j < total; j++) {
+ err = fdt_get_mem_rsv(working_fdt, j, &addr, &size);
+ if (err < 0) {
+ printf("libfdt fdt_get_mem_rsv(): %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ printf(" %x\t%08x%08x\t%08x%08x\n", j,
+ (u32)(addr >> 32),
+ (u32)(addr & 0xffffffff),
+ (u32)(size >> 32),
+ (u32)(size & 0xffffffff));
+ }
+ } else if (argv[2][0] == 'a') {
+ uint64_t addr, size;
+ int err;
+ addr = simple_strtoull(argv[3], NULL, 16);
+ size = simple_strtoull(argv[4], NULL, 16);
+ err = fdt_add_mem_rsv(working_fdt, addr, size);
+
+ if (err < 0) {
+ printf("libfdt fdt_add_mem_rsv(): %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ } else if (argv[2][0] == 'd') {
+ unsigned long idx = simple_strtoul(argv[3], NULL, 16);
+ int err = fdt_del_mem_rsv(working_fdt, idx);
+
+ if (err < 0) {
+ printf("libfdt fdt_del_mem_rsv(): %s\n",
+ fdt_strerror(err));
+ return err;
+ }
+ } else {
+ /* Unrecognized command */
+ return cmd_usage(cmdtp);
+ }
+ }
+#ifdef CONFIG_OF_BOARD_SETUP
+ /* Call the board-specific fixup routine */
+ else if (strncmp(argv[1], "boa", 3) == 0)
+ ft_board_setup(working_fdt, gd->bd);
+#endif
+ /* Create a chosen node */
+ else if (argv[1][0] == 'c') {
+ unsigned long initrd_start = 0, initrd_end = 0;
+
+ if ((argc != 2) && (argc != 4))
+ return cmd_usage(cmdtp);
+
+ if (argc == 4) {
+ initrd_start = simple_strtoul(argv[2], NULL, 16);
+ initrd_end = simple_strtoul(argv[3], NULL, 16);
+ }
+
+ fdt_chosen(working_fdt, 1);
+ fdt_initrd(working_fdt, initrd_start, initrd_end, 1);
+ }
+ /* resize the fdt */
+ else if (strncmp(argv[1], "re", 2) == 0) {
+ fdt_resize(working_fdt);
+ }
+ else {
+ /* Unrecognized command */
+ return cmd_usage(cmdtp);
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+static int fdt_valid(void)
+{
+ int err;
+
+ if (working_fdt == NULL) {
+ printf ("The address of the fdt is invalid (NULL).\n");
+ return 0;
+ }
+
+ err = fdt_check_header(working_fdt);
+ if (err == 0)
+ return 1; /* valid */
+
+ if (err < 0) {
+ printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
+ /*
+ * Be more informative on bad version.
+ */
+ if (err == -FDT_ERR_BADVERSION) {
+ if (fdt_version(working_fdt) <
+ FDT_FIRST_SUPPORTED_VERSION) {
+ printf (" - too old, fdt %d < %d",
+ fdt_version(working_fdt),
+ FDT_FIRST_SUPPORTED_VERSION);
+ working_fdt = NULL;
+ }
+ if (fdt_last_comp_version(working_fdt) >
+ FDT_LAST_SUPPORTED_VERSION) {
+ printf (" - too new, fdt %d > %d",
+ fdt_version(working_fdt),
+ FDT_LAST_SUPPORTED_VERSION);
+ working_fdt = NULL;
+ }
+ return 0;
+ }
+ printf("\n");
+ return 0;
+ }
+ return 1;
+}
+
+/****************************************************************************/
+
+/*
+ * Parse the user's input, partially heuristic. Valid formats:
+ * <0x00112233 4 05> - an array of cells. Numbers follow standard
+ * C conventions.
+ * [00 11 22 .. nn] - byte stream
+ * "string" - If the the value doesn't start with "<" or "[", it is
+ * treated as a string. Note that the quotes are
+ * stripped by the parser before we get the string.
+ * newval: An array of strings containing the new property as specified
+ * on the command line
+ * count: The number of strings in the array
+ * data: A bytestream to be placed in the property
+ * len: The length of the resulting bytestream
+ */
+static int fdt_parse_prop(char * const *newval, int count, char *data, int *len)
+{
+ char *cp; /* temporary char pointer */
+ char *newp; /* temporary newval char pointer */
+ unsigned long tmp; /* holds converted values */
+ int stridx = 0;
+
+ *len = 0;
+ newp = newval[0];
+
+ /* An array of cells */
+ if (*newp == '<') {
+ newp++;
+ while ((*newp != '>') && (stridx < count)) {
+ /*
+ * Keep searching until we find that last ">"
+ * That way users don't have to escape the spaces
+ */
+ if (*newp == '\0') {
+ newp = newval[++stridx];
+ continue;
+ }
+
+ cp = newp;
+ tmp = simple_strtoul(cp, &newp, 0);
+ *(uint32_t *)data = __cpu_to_be32(tmp);
+ data += 4;
+ *len += 4;
+
+ /* If the ptr didn't advance, something went wrong */
+ if ((newp - cp) <= 0) {
+ printf("Sorry, I could not convert \"%s\"\n",
+ cp);
+ return 1;
+ }
+
+ while (*newp == ' ')
+ newp++;
+ }
+
+ if (*newp != '>') {
+ printf("Unexpected character '%c'\n", *newp);
+ return 1;
+ }
+ } else if (*newp == '[') {
+ /*
+ * Byte stream. Convert the values.
+ */
+ newp++;
+ while ((stridx < count) && (*newp != ']')) {
+ while (*newp == ' ')
+ newp++;
+ if (*newp == '\0') {
+ newp = newval[++stridx];
+ continue;
+ }
+ if (!isxdigit(*newp))
+ break;
+ tmp = simple_strtoul(newp, &newp, 16);
+ *data++ = tmp & 0xFF;
+ *len = *len + 1;
+ }
+ if (*newp != ']') {
+ printf("Unexpected character '%c'\n", *newp);
+ return 1;
+ }
+ } else {
+ /*
+ * Assume it is one or more strings. Copy it into our
+ * data area for convenience (including the
+ * terminating '\0's).
+ */
+ while (stridx < count) {
+ size_t length = strlen(newp) + 1;
+ strcpy(data, newp);
+ data += length;
+ *len += length;
+ newp = newval[++stridx];
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************/
+
+/*
+ * Heuristic to guess if this is a string or concatenated strings.
+ */
+
+static int is_printable_string(const void *data, int len)
+{
+ const char *s = data;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ /* printable or a null byte (concatenated strings) */
+ while (((*s == '\0') || isprint(*s)) && (len > 0)) {
+ /*
+ * If we see a null, there are three possibilities:
+ * 1) If len == 1, it is the end of the string, printable
+ * 2) Next character also a null, not printable.
+ * 3) Next character not a null, continue to check.
+ */
+ if (s[0] == '\0') {
+ if (len == 1)
+ return 1;
+ if (s[1] == '\0')
+ return 0;
+ }
+ s++;
+ len--;
+ }
+
+ /* Not the null termination, or not done yet: not printable */
+ if (*s != '\0' || (len != 0))
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * Print the property in the best format, a heuristic guess. Print as
+ * a string, concatenated strings, a byte, word, double word, or (if all
+ * else fails) it is printed as a stream of bytes.
+ */
+static void print_data(const void *data, int len)
+{
+ int j;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ /*
+ * It is a string, but it may have multiple strings (embedded '\0's).
+ */
+ if (is_printable_string(data, len)) {
+ puts("\"");
+ j = 0;
+ while (j < len) {
+ if (j > 0)
+ puts("\", \"");
+ puts(data);
+ j += strlen(data) + 1;
+ data += strlen(data) + 1;
+ }
+ puts("\"");
+ return;
+ }
+
+ if ((len %4) == 0) {
+ const u32 *p;
+
+ printf("<");
+ for (j = 0, p = data; j < len/4; j ++)
+ printf("0x%x%s", p[j], j < (len/4 - 1) ? " " : "");
+ printf(">");
+ } else { /* anything else... hexdump */
+ const u8 *s;
+
+ printf("[");
+ for (j = 0, s = data; j < len; j++)
+ printf("%02x%s", s[j], j < len - 1 ? " " : "");
+ printf("]");
+ }
+}
+
+/****************************************************************************/
+
+/*
+ * Recursively print (a portion of) the working_fdt. The depth parameter
+ * determines how deeply nested the fdt is printed.
+ */
+static int fdt_print(const char *pathp, char *prop, int depth)
+{
+ static char tabs[MAX_LEVEL+1] =
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ const void *nodep; /* property node pointer */
+ int nodeoffset; /* node offset from libfdt */
+ int nextoffset; /* next node offset from libfdt */
+ uint32_t tag; /* tag */
+ int len; /* length of the property */
+ int level = 0; /* keep track of nesting level */
+ const struct fdt_property *fdt_prop;
+
+ nodeoffset = fdt_path_offset (working_fdt, pathp);
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return 1;
+ }
+ /*
+ * The user passed in a property as well as node path.
+ * Print only the given property and then return.
+ */
+ if (prop) {
+ nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len);
+ if (len == 0) {
+ /* no property value */
+ printf("%s %s\n", pathp, prop);
+ return 0;
+ } else if (len > 0) {
+ printf("%s = ", prop);
+ print_data (nodep, len);
+ printf("\n");
+ return 0;
+ } else {
+ printf ("libfdt fdt_getprop(): %s\n",
+ fdt_strerror(len));
+ return 1;
+ }
+ }
+
+ /*
+ * The user passed in a node path and no property,
+ * print the node and all subnodes.
+ */
+ while(level >= 0) {
+ tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
+ switch(tag) {
+ case FDT_BEGIN_NODE:
+ pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
+ if (level <= depth) {
+ if (pathp == NULL)
+ pathp = "/* NULL pointer error */";
+ if (*pathp == '\0')
+ pathp = "/"; /* root is nameless */
+ printf("%s%s {\n",
+ &tabs[MAX_LEVEL - level], pathp);
+ }
+ level++;
+ if (level >= MAX_LEVEL) {
+ printf("Nested too deep, aborting.\n");
+ return 1;
+ }
+ break;
+ case FDT_END_NODE:
+ level--;
+ if (level <= depth)
+ printf("%s};\n", &tabs[MAX_LEVEL - level]);
+ if (level == 0) {
+ level = -1; /* exit the loop */
+ }
+ break;
+ case FDT_PROP:
+ fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
+ sizeof(*fdt_prop));
+ pathp = fdt_string(working_fdt,
+ fdt32_to_cpu(fdt_prop->nameoff));
+ len = fdt32_to_cpu(fdt_prop->len);
+ nodep = fdt_prop->data;
+ if (len < 0) {
+ printf ("libfdt fdt_getprop(): %s\n",
+ fdt_strerror(len));
+ return 1;
+ } else if (len == 0) {
+ /* the property has no value */
+ if (level <= depth)
+ printf("%s%s;\n",
+ &tabs[MAX_LEVEL - level],
+ pathp);
+ } else {
+ if (level <= depth) {
+ printf("%s%s = ",
+ &tabs[MAX_LEVEL - level],
+ pathp);
+ print_data (nodep, len);
+ printf(";\n");
+ }
+ }
+ break;
+ case FDT_NOP:
+ printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
+ break;
+ case FDT_END:
+ return 1;
+ default:
+ if (level <= depth)
+ printf("Unknown tag 0x%08X\n", tag);
+ return 1;
+ }
+ nodeoffset = nextoffset;
+ }
+ return 0;
+}
+
+/********************************************************************/
+
+U_BOOT_CMD(
+ fdt, 255, 0, do_fdt,
+ "flattened device tree utility commands",
+ "addr <addr> [<length>] - Set the fdt location to <addr>\n"
+#ifdef CONFIG_OF_BOARD_SETUP
+ "fdt boardsetup - Do board-specific set up\n"
+#endif
+ "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n"
+ "fdt resize - Resize fdt to size + padding to 4k addr\n"
+ "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
+ "fdt list <path> [<prop>] - Print one level starting at <path>\n"
+ "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
+ "fdt mknode <path> <node> - Create a new node after <path>\n"
+ "fdt rm <path> [<prop>] - Delete the node or <property>\n"
+ "fdt header - Display header info\n"
+ "fdt bootcpu <id> - Set boot cpuid\n"
+ "fdt memory <addr> <size> - Add/Update memory node\n"
+ "fdt rsvmem print - Show current mem reserves\n"
+ "fdt rsvmem add <addr> <size> - Add a mem reserve\n"
+ "fdt rsvmem delete <index> - Delete a mem reserves\n"
+ "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n"
+ " <start>/<end> - initrd start/end addr\n"
+ "NOTE: Dereference aliases by omiting the leading '/', "
+ "e.g. fdt print ethernet0."
+);
diff --git a/u-boot/common/cmd_flash.c b/u-boot/common/cmd_flash.c
new file mode 100644
index 0000000..bd49b79
--- /dev/null
+++ b/u-boot/common/cmd_flash.c
@@ -0,0 +1,742 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * FLASH support
+ */
+#include <common.h>
+#include <command.h>
+
+#ifdef CONFIG_HAS_DATAFLASH
+#include <dataflash.h>
+#endif
+
+#if defined(CONFIG_CMD_MTDPARTS)
+#include <jffs2/jffs2.h>
+
+/* partition handling routines */
+int mtdparts_init(void);
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+ u8 *part_num, struct part_info **part);
+#endif
+
+#ifndef CONFIG_SYS_NO_FLASH
+#include <flash.h>
+#include <mtd/cfi_flash.h>
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*
+ * The user interface starts numbering for Flash banks with 1
+ * for historical reasons.
+ */
+
+/*
+ * this routine looks for an abbreviated flash range specification.
+ * the syntax is B:SF[-SL], where B is the bank number, SF is the first
+ * sector to erase, and SL is the last sector to erase (defaults to SF).
+ * bank numbers start at 1 to be consistent with other specs, sector numbers
+ * start at zero.
+ *
+ * returns: 1 - correct spec; *pinfo, *psf and *psl are
+ * set appropriately
+ * 0 - doesn't look like an abbreviated spec
+ * -1 - looks like an abbreviated spec, but got
+ * a parsing error, a number out of range,
+ * or an invalid flash bank.
+ */
+static int
+abbrev_spec (char *str, flash_info_t ** pinfo, int *psf, int *psl)
+{
+ flash_info_t *fp;
+ int bank, first, last;
+ char *p, *ep;
+
+ if ((p = strchr (str, ':')) == NULL)
+ return 0;
+ *p++ = '\0';
+
+ bank = simple_strtoul (str, &ep, 10);
+ if (ep == str || *ep != '\0' ||
+ bank < 1 || bank > CONFIG_SYS_MAX_FLASH_BANKS ||
+ (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
+ return -1;
+
+ str = p;
+ if ((p = strchr (str, '-')) != NULL)
+ *p++ = '\0';
+
+ first = simple_strtoul (str, &ep, 10);
+ if (ep == str || *ep != '\0' || first >= fp->sector_count)
+ return -1;
+
+ if (p != NULL) {
+ last = simple_strtoul (p, &ep, 10);
+ if (ep == p || *ep != '\0' ||
+ last < first || last >= fp->sector_count)
+ return -1;
+ } else {
+ last = first;
+ }
+
+ *pinfo = fp;
+ *psf = first;
+ *psl = last;
+
+ return 1;
+}
+
+/*
+ * Take *addr in Flash and adjust it to fall on the end of its sector
+ */
+int flash_sect_roundb (ulong *addr)
+{
+ flash_info_t *info;
+ ulong bank, sector_end_addr;
+ char found;
+ int i;
+
+ /* find the end addr of the sector where the *addr is */
+ found = 0;
+ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS && !found; ++bank) {
+ info = &flash_info[bank];
+ for (i = 0; i < info->sector_count && !found; ++i) {
+ /* get the end address of the sector */
+ if (i == info->sector_count - 1) {
+ sector_end_addr = info->start[0] +
+ info->size - 1;
+ } else {
+ sector_end_addr = info->start[i+1] - 1;
+ }
+
+ if (*addr <= sector_end_addr &&
+ *addr >= info->start[i]) {
+ found = 1;
+ /* adjust *addr if necessary */
+ if (*addr < sector_end_addr)
+ *addr = sector_end_addr;
+ } /* sector */
+ } /* bank */
+ }
+ if (!found) {
+ /* error, addres not in flash */
+ printf("Error: end address (0x%08lx) not in flash!\n", *addr);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function computes the start and end addresses for both
+ * erase and protect commands. The range of the addresses on which
+ * either of the commands is to operate can be given in two forms:
+ * 1. <cmd> start end - operate on <'start', 'end')
+ * 2. <cmd> start +length - operate on <'start', start + length)
+ * If the second form is used and the end address doesn't fall on the
+ * sector boundary, than it will be adjusted to the next sector boundary.
+ * If it isn't in the flash, the function will fail (return -1).
+ * Input:
+ * arg1, arg2: address specification (i.e. both command arguments)
+ * Output:
+ * addr_first, addr_last: computed address range
+ * Return:
+ * 1: success
+ * -1: failure (bad format, bad address).
+*/
+static int
+addr_spec(char *arg1, char *arg2, ulong *addr_first, ulong *addr_last)
+{
+ char *ep;
+ char len_used; /* indicates if the "start +length" form used */
+
+ *addr_first = simple_strtoul(arg1, &ep, 16);
+ if (ep == arg1 || *ep != '\0')
+ return -1;
+
+ len_used = 0;
+ if (arg2 && *arg2 == '+'){
+ len_used = 1;
+ ++arg2;
+ }
+
+ *addr_last = simple_strtoul(arg2, &ep, 16);
+ if (ep == arg2 || *ep != '\0')
+ return -1;
+
+ if (len_used){
+ /*
+ * *addr_last has the length, compute correct *addr_last
+ * XXX watch out for the integer overflow! Right now it is
+ * checked for in both the callers.
+ */
+ *addr_last = *addr_first + *addr_last - 1;
+
+ /*
+ * It may happen that *addr_last doesn't fall on the sector
+ * boundary. We want to round such an address to the next
+ * sector boundary, so that the commands don't fail later on.
+ */
+
+ if (flash_sect_roundb(addr_last) > 0)
+ return -1;
+ } /* "start +length" from used */
+
+ return 1;
+}
+
+static int
+flash_fill_sect_ranges (ulong addr_first, ulong addr_last,
+ int *s_first, int *s_last,
+ int *s_count )
+{
+ flash_info_t *info;
+ ulong bank;
+ int rcode = 0;
+
+ *s_count = 0;
+
+ for (bank=0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ s_first[bank] = -1; /* first sector to erase */
+ s_last [bank] = -1; /* last sector to erase */
+ }
+
+ for (bank=0,info = &flash_info[0];
+ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last);
+ ++bank, ++info) {
+ ulong b_end;
+ int sect;
+ short s_end;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+
+ b_end = info->start[0] + info->size - 1; /* bank end addr */
+ s_end = info->sector_count - 1; /* last sector */
+
+
+ for (sect=0; sect < info->sector_count; ++sect) {
+ ulong end; /* last address in current sect */
+
+ end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+ if (addr_first > end)
+ continue;
+ if (addr_last < info->start[sect])
+ continue;
+
+ if (addr_first == info->start[sect]) {
+ s_first[bank] = sect;
+ }
+ if (addr_last == end) {
+ s_last[bank] = sect;
+ }
+ }
+ if (s_first[bank] >= 0) {
+ if (s_last[bank] < 0) {
+ if (addr_last > b_end) {
+ s_last[bank] = s_end;
+ } else {
+ puts ("Error: end address"
+ " not on sector boundary\n");
+ rcode = 1;
+ break;
+ }
+ }
+ if (s_last[bank] < s_first[bank]) {
+ puts ("Error: end sector"
+ " precedes start sector\n");
+ rcode = 1;
+ break;
+ }
+ sect = s_last[bank];
+ addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1];
+ (*s_count) += s_last[bank] - s_first[bank] + 1;
+ } else if (addr_first >= info->start[0] && addr_first < b_end) {
+ puts ("Error: start address not on sector boundary\n");
+ rcode = 1;
+ break;
+ } else if (s_last[bank] >= 0) {
+ puts ("Error: cannot span across banks when they are"
+ " mapped in reverse order\n");
+ rcode = 1;
+ break;
+ }
+ }
+
+ return rcode;
+}
+#endif /* CONFIG_SYS_NO_FLASH */
+
+int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#ifndef CONFIG_SYS_NO_FLASH
+ ulong bank;
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+ dataflash_print_info();
+#endif
+
+#ifndef CONFIG_SYS_NO_FLASH
+ if (argc == 1) { /* print info for all FLASH banks */
+ for (bank=0; bank <CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ printf ("\nBank # %ld: ", bank+1);
+
+ flash_print_info (&flash_info[bank]);
+ }
+ return 0;
+ }
+
+ bank = simple_strtoul(argv[1], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("\nBank # %ld: ", bank);
+ flash_print_info (&flash_info[bank-1]);
+#endif /* CONFIG_SYS_NO_FLASH */
+ return 0;
+}
+
+int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#ifndef CONFIG_SYS_NO_FLASH
+ flash_info_t *info;
+ ulong bank, addr_first, addr_last;
+ int n, sect_first, sect_last;
+#if defined(CONFIG_CMD_MTDPARTS)
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 dev_type, dev_num, pnum;
+#endif
+ int rcode = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "all") == 0) {
+ for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ printf ("Erase Flash Bank # %ld ", bank);
+ info = &flash_info[bank-1];
+ rcode = flash_erase (info, 0, info->sector_count-1);
+ }
+ return rcode;
+ }
+
+ if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
+ if (n < 0) {
+ puts ("Bad sector specification\n");
+ return 1;
+ }
+ printf ("Erase Flash Sectors %d-%d in Bank # %zu ",
+ sect_first, sect_last, (info-flash_info)+1);
+ rcode = flash_erase(info, sect_first, sect_last);
+ return rcode;
+ }
+
+#if defined(CONFIG_CMD_MTDPARTS)
+ /* erase <part-id> - erase partition */
+ if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
+ mtdparts_init();
+ if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
+ if (dev->id->type == MTD_DEV_TYPE_NOR) {
+ bank = dev->id->num;
+ info = &flash_info[bank];
+ addr_first = part->offset + info->start[0];
+ addr_last = addr_first + part->size - 1;
+
+ printf ("Erase Flash Partition %s, "
+ "bank %ld, 0x%08lx - 0x%08lx ",
+ argv[1], bank, addr_first,
+ addr_last);
+
+ rcode = flash_sect_erase(addr_first, addr_last);
+ return rcode;
+ }
+
+ printf("cannot erase, not a NOR device\n");
+ return 1;
+ }
+ }
+#endif
+
+ if (argc != 3)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "bank") == 0) {
+ bank = simple_strtoul(argv[2], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("Erase Flash Bank # %ld ", bank);
+ info = &flash_info[bank-1];
+ rcode = flash_erase (info, 0, info->sector_count-1);
+ return rcode;
+ }
+
+ if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
+ printf ("Bad address format\n");
+ return 1;
+ }
+
+ if (addr_first >= addr_last)
+ return cmd_usage(cmdtp);
+
+ rcode = flash_sect_erase(addr_first, addr_last);
+ return rcode;
+#else
+ return 0;
+#endif /* CONFIG_SYS_NO_FLASH */
+}
+
+#ifndef CONFIG_SYS_NO_FLASH
+int flash_sect_erase (ulong addr_first, ulong addr_last)
+{
+ flash_info_t *info;
+ ulong bank;
+ int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS];
+ int erased = 0;
+ int planned;
+ int rcode = 0;
+
+ rcode = flash_fill_sect_ranges (addr_first, addr_last,
+ s_first, s_last, &planned );
+
+ if (planned && (rcode == 0)) {
+ for (bank=0,info = &flash_info[0];
+ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0);
+ ++bank, ++info) {
+ if (s_first[bank]>=0) {
+ erased += s_last[bank] - s_first[bank] + 1;
+ debug ("Erase Flash from 0x%08lx to 0x%08lx "
+ "in Bank # %ld ",
+ info->start[s_first[bank]],
+ (s_last[bank] == info->sector_count) ?
+ info->start[0] + info->size - 1:
+ info->start[s_last[bank]+1] - 1,
+ bank+1);
+ rcode = flash_erase (info, s_first[bank], s_last[bank]);
+ }
+ }
+ printf ("Erased %d sectors\n", erased);
+ } else if (rcode == 0) {
+ puts ("Error: start and/or end address"
+ " not on sector boundary\n");
+ rcode = 1;
+ }
+ return rcode;
+}
+#endif /* CONFIG_SYS_NO_FLASH */
+
+int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#ifndef CONFIG_SYS_NO_FLASH
+ flash_info_t *info;
+ ulong bank;
+ int i, n, sect_first, sect_last;
+#if defined(CONFIG_CMD_MTDPARTS)
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 dev_type, dev_num, pnum;
+#endif
+#endif /* CONFIG_SYS_NO_FLASH */
+#if !defined(CONFIG_SYS_NO_FLASH) || defined(CONFIG_HAS_DATAFLASH)
+ ulong addr_first, addr_last;
+#endif
+#ifdef CONFIG_HAS_DATAFLASH
+ int status;
+#endif
+ int p;
+ int rcode = 0;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "off") == 0)
+ p = 0;
+ else if (strcmp(argv[1], "on") == 0)
+ p = 1;
+ else
+ return cmd_usage(cmdtp);
+
+#ifdef CONFIG_HAS_DATAFLASH
+ if ((strcmp(argv[2], "all") != 0) && (strcmp(argv[2], "bank") != 0)) {
+ addr_first = simple_strtoul(argv[2], NULL, 16);
+ addr_last = simple_strtoul(argv[3], NULL, 16);
+
+ if (addr_dataflash(addr_first) && addr_dataflash(addr_last)) {
+ status = dataflash_real_protect(p,addr_first,addr_last);
+ if (status < 0){
+ puts ("Bad DataFlash sector specification\n");
+ return 1;
+ }
+ printf("%sProtect %d DataFlash Sectors\n",
+ p ? "" : "Un-", status);
+ return 0;
+ }
+ }
+#endif
+
+#ifndef CONFIG_SYS_NO_FLASH
+ if (strcmp(argv[2], "all") == 0) {
+ for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ info = &flash_info[bank-1];
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+ printf ("%sProtect Flash Bank # %ld\n",
+ p ? "" : "Un-", bank);
+
+ for (i=0; i<info->sector_count; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ return rcode;
+ }
+
+ if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
+ if (n < 0) {
+ puts ("Bad sector specification\n");
+ return 1;
+ }
+ printf("%sProtect Flash Sectors %d-%d in Bank # %zu\n",
+ p ? "" : "Un-", sect_first, sect_last,
+ (info-flash_info)+1);
+ for (i = sect_first; i <= sect_last; i++) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ return rcode;
+ }
+
+#if defined(CONFIG_CMD_MTDPARTS)
+ /* protect on/off <part-id> */
+ if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
+ mtdparts_init();
+ if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
+ if (dev->id->type == MTD_DEV_TYPE_NOR) {
+ bank = dev->id->num;
+ info = &flash_info[bank];
+ addr_first = part->offset + info->start[0];
+ addr_last = addr_first + part->size - 1;
+
+ printf ("%sProtect Flash Partition %s, "
+ "bank %ld, 0x%08lx - 0x%08lx\n",
+ p ? "" : "Un", argv[1],
+ bank, addr_first, addr_last);
+
+ rcode = flash_sect_protect (p, addr_first, addr_last);
+ return rcode;
+ }
+
+ printf("cannot %sprotect, not a NOR device\n",
+ p ? "" : "un");
+ return 1;
+ }
+ }
+#endif
+
+ if (argc != 4)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[2], "bank") == 0) {
+ bank = simple_strtoul(argv[3], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("%sProtect Flash Bank # %ld\n",
+ p ? "" : "Un-", bank);
+ info = &flash_info[bank-1];
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ puts ("missing or unknown FLASH type\n");
+ return 1;
+ }
+ for (i=0; i<info->sector_count; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ return rcode;
+ }
+
+ if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){
+ printf("Bad address format\n");
+ return 1;
+ }
+
+ if (addr_first >= addr_last)
+ return cmd_usage(cmdtp);
+
+ rcode = flash_sect_protect (p, addr_first, addr_last);
+#endif /* CONFIG_SYS_NO_FLASH */
+ return rcode;
+}
+
+#ifndef CONFIG_SYS_NO_FLASH
+int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
+{
+ flash_info_t *info;
+ ulong bank;
+ int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS];
+ int protected, i;
+ int planned;
+ int rcode;
+
+ rcode = flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned );
+
+ protected = 0;
+
+ if (planned && (rcode == 0)) {
+ for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+
+ if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) {
+ debug ("%sProtecting sectors %d..%d in bank %ld\n",
+ p ? "" : "Un-",
+ s_first[bank], s_last[bank], bank+1);
+ protected += s_last[bank] - s_first[bank] + 1;
+ for (i=s_first[bank]; i<=s_last[bank]; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ }
+ }
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ printf ("%sProtected %d sectors\n",
+ p ? "" : "Un-", protected);
+ } else if (rcode == 0) {
+ puts ("Error: start and/or end address"
+ " not on sector boundary\n");
+ rcode = 1;
+ }
+ return rcode;
+}
+#endif /* CONFIG_SYS_NO_FLASH */
+
+
+/**************************************************/
+#if defined(CONFIG_CMD_MTDPARTS)
+# define TMP_ERASE "erase <part-id>\n - erase partition\n"
+# define TMP_PROT_ON "protect on <part-id>\n - protect partition\n"
+# define TMP_PROT_OFF "protect off <part-id>\n - make partition writable\n"
+#else
+# define TMP_ERASE /* empty */
+# define TMP_PROT_ON /* empty */
+# define TMP_PROT_OFF /* empty */
+#endif
+
+U_BOOT_CMD(
+ flinfo, 2, 1, do_flinfo,
+ "print FLASH memory information",
+ "\n - print information for all FLASH memory banks\n"
+ "flinfo N\n - print information for FLASH memory bank # N"
+);
+
+U_BOOT_CMD(
+ erase, 3, 0, do_flerase,
+ "erase FLASH memory",
+ "start end\n"
+ " - erase FLASH from addr 'start' to addr 'end'\n"
+ "erase start +len\n"
+ " - erase FLASH from addr 'start' to the end of sect "
+ "w/addr 'start'+'len'-1\n"
+ "erase N:SF[-SL]\n - erase sectors SF-SL in FLASH bank # N\n"
+ "erase bank N\n - erase FLASH bank # N\n"
+ TMP_ERASE
+ "erase all\n - erase all FLASH banks"
+);
+
+U_BOOT_CMD(
+ protect, 4, 0, do_protect,
+ "enable or disable FLASH write protection",
+ "on start end\n"
+ " - protect FLASH from addr 'start' to addr 'end'\n"
+ "protect on start +len\n"
+ " - protect FLASH from addr 'start' to end of sect "
+ "w/addr 'start'+'len'-1\n"
+ "protect on N:SF[-SL]\n"
+ " - protect sectors SF-SL in FLASH bank # N\n"
+ "protect on bank N\n - protect FLASH bank # N\n"
+ TMP_PROT_ON
+ "protect on all\n - protect all FLASH banks\n"
+ "protect off start end\n"
+ " - make FLASH from addr 'start' to addr 'end' writable\n"
+ "protect off start +len\n"
+ " - make FLASH from addr 'start' to end of sect "
+ "w/addr 'start'+'len'-1 wrtable\n"
+ "protect off N:SF[-SL]\n"
+ " - make sectors SF-SL writable in FLASH bank # N\n"
+ "protect off bank N\n - make FLASH bank # N writable\n"
+ TMP_PROT_OFF
+ "protect off all\n - make all FLASH banks writable"
+);
+
+#undef TMP_ERASE
+#undef TMP_PROT_ON
+#undef TMP_PROT_OFF
diff --git a/u-boot/common/cmd_fpga.c b/u-boot/common/cmd_fpga.c
new file mode 100644
index 0000000..0ad310f
--- /dev/null
+++ b/u-boot/common/cmd_fpga.c
@@ -0,0 +1,386 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * FPGA support
+ */
+#include <common.h>
+#include <command.h>
+#if defined(CONFIG_CMD_NET)
+#include <net.h>
+#endif
+#include <fpga.h>
+#include <malloc.h>
+
+#if 0
+#define FPGA_DEBUG
+#endif
+
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Local functions */
+static int fpga_get_op (char *opstr);
+
+/* Local defines */
+#define FPGA_NONE -1
+#define FPGA_INFO 0
+#define FPGA_LOAD 1
+#define FPGA_LOADB 2
+#define FPGA_DUMP 3
+#define FPGA_LOADMK 4
+
+/* Convert bitstream data and load into the fpga */
+int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size)
+{
+#if defined(CONFIG_FPGA_XILINX)
+ unsigned int length;
+ unsigned int swapsize;
+ char buffer[80];
+ unsigned char *dataptr;
+ unsigned int i;
+ int rc;
+
+ dataptr = (unsigned char *)fpgadata;
+
+ /* skip the first bytes of the bitsteam, their meaning is unknown */
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ dataptr+=length;
+
+ /* get design name (identifier, length, string) */
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ if (*dataptr++ != 0x61) {
+ PRINTF ("%s: Design name identifier not recognized in bitstream\n",
+ __FUNCTION__ );
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ for(i=0;i<length;i++)
+ buffer[i] = *dataptr++;
+
+ printf(" design filename = \"%s\"\n", buffer);
+
+ /* get part number (identifier, length, string) */
+ if (*dataptr++ != 0x62) {
+ printf("%s: Part number identifier not recognized in bitstream\n",
+ __FUNCTION__ );
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ for(i=0;i<length;i++)
+ buffer[i] = *dataptr++;
+ printf(" part number = \"%s\"\n", buffer);
+
+ /* get date (identifier, length, string) */
+ if (*dataptr++ != 0x63) {
+ printf("%s: Date identifier not recognized in bitstream\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ for(i=0;i<length;i++)
+ buffer[i] = *dataptr++;
+ printf(" date = \"%s\"\n", buffer);
+
+ /* get time (identifier, length, string) */
+ if (*dataptr++ != 0x64) {
+ printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr+=2;
+ for(i=0;i<length;i++)
+ buffer[i] = *dataptr++;
+ printf(" time = \"%s\"\n", buffer);
+
+ /* get fpga data length (identifier, length) */
+ if (*dataptr++ != 0x65) {
+ printf("%s: Data length identifier not recognized in bitstream\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+ }
+ swapsize = ((unsigned int) *dataptr <<24) +
+ ((unsigned int) *(dataptr+1) <<16) +
+ ((unsigned int) *(dataptr+2) <<8 ) +
+ ((unsigned int) *(dataptr+3) ) ;
+ dataptr+=4;
+ printf(" bytes in bitstream = %d\n", swapsize);
+
+ rc = fpga_load(dev, dataptr, swapsize);
+ return rc;
+#else
+ printf("Bitstream support only for Xilinx devices\n");
+ return FPGA_FAIL;
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+/* command form:
+ * fpga <op> <device number> <data addr> <datasize>
+ * where op is 'load', 'dump', or 'info'
+ * If there is no device number field, the fpga environment variable is used.
+ * If there is no data addr field, the fpgadata environment variable is used.
+ * The info command requires no data address field.
+ */
+int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int op, dev = FPGA_INVALID_DEVICE;
+ size_t data_size = 0;
+ void *fpga_data = NULL;
+ char *devstr = getenv ("fpga");
+ char *datastr = getenv ("fpgadata");
+ int rc = FPGA_FAIL;
+ int wrong_parms = 0;
+#if defined (CONFIG_FIT)
+ const char *fit_uname = NULL;
+ ulong fit_addr;
+#endif
+
+ if (devstr)
+ dev = (int) simple_strtoul (devstr, NULL, 16);
+ if (datastr)
+ fpga_data = (void *) simple_strtoul (datastr, NULL, 16);
+
+ switch (argc) {
+ case 5: /* fpga <op> <dev> <data> <datasize> */
+ data_size = simple_strtoul (argv[4], NULL, 16);
+
+ case 4: /* fpga <op> <dev> <data> */
+#if defined(CONFIG_FIT)
+ if (fit_parse_subimage (argv[3], (ulong)fpga_data,
+ &fit_addr, &fit_uname)) {
+ fpga_data = (void *)fit_addr;
+ debug ("* fpga: subimage '%s' from FIT image at 0x%08lx\n",
+ fit_uname, fit_addr);
+ } else
+#endif
+ {
+ fpga_data = (void *) simple_strtoul (argv[3], NULL, 16);
+ debug ("* fpga: cmdline image address = 0x%08lx\n", (ulong)fpga_data);
+ }
+ PRINTF ("%s: fpga_data = 0x%x\n", __FUNCTION__, (uint) fpga_data);
+
+ case 3: /* fpga <op> <dev | data addr> */
+ dev = (int) simple_strtoul (argv[2], NULL, 16);
+ PRINTF ("%s: device = %d\n", __FUNCTION__, dev);
+ /* FIXME - this is a really weak test */
+ if ((argc == 3) && (dev > fpga_count ())) { /* must be buffer ptr */
+ PRINTF ("%s: Assuming buffer pointer in arg 3\n",
+ __FUNCTION__);
+
+#if defined(CONFIG_FIT)
+ if (fit_parse_subimage (argv[2], (ulong)fpga_data,
+ &fit_addr, &fit_uname)) {
+ fpga_data = (void *)fit_addr;
+ debug ("* fpga: subimage '%s' from FIT image at 0x%08lx\n",
+ fit_uname, fit_addr);
+ } else
+#endif
+ {
+ fpga_data = (void *) dev;
+ debug ("* fpga: cmdline image address = 0x%08lx\n", (ulong)fpga_data);
+ }
+
+ PRINTF ("%s: fpga_data = 0x%x\n",
+ __FUNCTION__, (uint) fpga_data);
+ dev = FPGA_INVALID_DEVICE; /* reset device num */
+ }
+
+ case 2: /* fpga <op> */
+ op = (int) fpga_get_op (argv[1]);
+ break;
+
+ default:
+ PRINTF ("%s: Too many or too few args (%d)\n",
+ __FUNCTION__, argc);
+ op = FPGA_NONE; /* force usage display */
+ break;
+ }
+
+ if (dev == FPGA_INVALID_DEVICE) {
+ puts("FPGA device not specified\n");
+ op = FPGA_NONE;
+ }
+
+ switch (op) {
+ case FPGA_NONE:
+ case FPGA_INFO:
+ break;
+ case FPGA_LOAD:
+ case FPGA_LOADB:
+ case FPGA_DUMP:
+ if (!fpga_data || !data_size)
+ wrong_parms = 1;
+ break;
+ case FPGA_LOADMK:
+ if (!fpga_data)
+ wrong_parms = 1;
+ break;
+ }
+
+ if (wrong_parms) {
+ puts("Wrong parameters for FPGA request\n");
+ op = FPGA_NONE;
+ }
+
+ switch (op) {
+ case FPGA_NONE:
+ return cmd_usage(cmdtp);
+
+ case FPGA_INFO:
+ rc = fpga_info (dev);
+ break;
+
+ case FPGA_LOAD:
+ rc = fpga_load (dev, fpga_data, data_size);
+ break;
+
+ case FPGA_LOADB:
+ rc = fpga_loadbitstream(dev, fpga_data, data_size);
+ break;
+
+ case FPGA_LOADMK:
+ switch (genimg_get_format (fpga_data)) {
+ case IMAGE_FORMAT_LEGACY:
+ {
+ image_header_t *hdr = (image_header_t *)fpga_data;
+ ulong data;
+
+ data = (ulong)image_get_data (hdr);
+ data_size = image_get_data_size (hdr);
+ rc = fpga_load (dev, (void *)data, data_size);
+ }
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ {
+ const void *fit_hdr = (const void *)fpga_data;
+ int noffset;
+ void *fit_data;
+
+ if (fit_uname == NULL) {
+ puts ("No FIT subimage unit name\n");
+ return 1;
+ }
+
+ if (!fit_check_format (fit_hdr)) {
+ puts ("Bad FIT image format\n");
+ return 1;
+ }
+
+ /* get fpga component image node offset */
+ noffset = fit_image_get_node (fit_hdr, fit_uname);
+ if (noffset < 0) {
+ printf ("Can't find '%s' FIT subimage\n", fit_uname);
+ return 1;
+ }
+
+ /* verify integrity */
+ if (!fit_image_check_hashes (fit_hdr, noffset)) {
+ puts ("Bad Data Hash\n");
+ return 1;
+ }
+
+ /* get fpga subimage data address and length */
+ if (fit_image_get_data (fit_hdr, noffset, &fit_data, &data_size)) {
+ puts ("Could not find fpga subimage data\n");
+ return 1;
+ }
+
+ rc = fpga_load (dev, fit_data, data_size);
+ }
+ break;
+#endif
+ default:
+ puts ("** Unknown image type\n");
+ rc = FPGA_FAIL;
+ break;
+ }
+ break;
+
+ case FPGA_DUMP:
+ rc = fpga_dump (dev, fpga_data, data_size);
+ break;
+
+ default:
+ printf ("Unknown operation\n");
+ return cmd_usage(cmdtp);
+ }
+ return (rc);
+}
+
+/*
+ * Map op to supported operations. We don't use a table since we
+ * would just have to relocate it from flash anyway.
+ */
+static int fpga_get_op (char *opstr)
+{
+ int op = FPGA_NONE;
+
+ if (!strcmp ("info", opstr)) {
+ op = FPGA_INFO;
+ } else if (!strcmp ("loadb", opstr)) {
+ op = FPGA_LOADB;
+ } else if (!strcmp ("load", opstr)) {
+ op = FPGA_LOAD;
+ } else if (!strcmp ("loadmk", opstr)) {
+ op = FPGA_LOADMK;
+ } else if (!strcmp ("dump", opstr)) {
+ op = FPGA_DUMP;
+ }
+
+ if (op == FPGA_NONE) {
+ printf ("Unknown fpga operation \"%s\"\n", opstr);
+ }
+ return op;
+}
+
+U_BOOT_CMD (fpga, 6, 1, do_fpga,
+ "loadable FPGA image support",
+ "[operation type] [device number] [image address] [image size]\n"
+ "fpga operations:\n"
+ " dump\t[dev]\t\t\tLoad device to memory buffer\n"
+ " info\t[dev]\t\t\tlist known device information\n"
+ " load\t[dev] [address] [size]\tLoad device from memory buffer\n"
+ " loadb\t[dev] [address] [size]\t"
+ "Load device from bitstream buffer (Xilinx only)\n"
+ " loadmk [dev] [address]\tLoad device generated with mkimage"
+#if defined(CONFIG_FIT)
+ "\n"
+ "\tFor loadmk operating on FIT format uImage address must include\n"
+ "\tsubimage unit name in the form of addr:<subimg_uname>"
+#endif
+);
diff --git a/u-boot/common/cmd_help.c b/u-boot/common/cmd_help.c
new file mode 100644
index 0000000..8c8178e
--- /dev/null
+++ b/u-boot/common/cmd_help.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+int do_help(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ return _do_help(&__u_boot_cmd_start,
+ &__u_boot_cmd_end - &__u_boot_cmd_start,
+ cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+ help, CONFIG_SYS_MAXARGS, 1, do_help,
+ "print command description/usage",
+ "\n"
+ " - print brief description of all commands\n"
+ "help command ...\n"
+ " - print detailed usage of 'command'"
+);
+
+/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
+cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
+ "?", CONFIG_SYS_MAXARGS, 1, do_help,
+ "alias for 'help'",
+#ifdef CONFIG_SYS_LONGHELP
+ ""
+#endif /* CONFIG_SYS_LONGHELP */
+};
diff --git a/u-boot/common/cmd_i2c.c b/u-boot/common/cmd_i2c.c
new file mode 100644
index 0000000..c272b0d
--- /dev/null
+++ b/u-boot/common/cmd_i2c.c
@@ -0,0 +1,1553 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * I2C Functions similar to the standard memory functions.
+ *
+ * There are several parameters in many of the commands that bear further
+ * explanations:
+ *
+ * {i2c_chip} is the I2C chip address (the first byte sent on the bus).
+ * Each I2C chip on the bus has a unique address. On the I2C data bus,
+ * the address is the upper seven bits and the LSB is the "read/write"
+ * bit. Note that the {i2c_chip} address specified on the command
+ * line is not shifted up: e.g. a typical EEPROM memory chip may have
+ * an I2C address of 0x50, but the data put on the bus will be 0xA0
+ * for write and 0xA1 for read. This "non shifted" address notation
+ * matches at least half of the data sheets :-/.
+ *
+ * {addr} is the address (or offset) within the chip. Small memory
+ * chips have 8 bit addresses. Large memory chips have 16 bit
+ * addresses. Other memory chips have 9, 10, or 11 bit addresses.
+ * Many non-memory chips have multiple registers and {addr} is used
+ * as the register index. Some non-memory chips have only one register
+ * and therefore don't need any {addr} parameter.
+ *
+ * The default {addr} parameter is one byte (.1) which works well for
+ * memories and registers with 8 bits of address space.
+ *
+ * You can specify the length of the {addr} field with the optional .0,
+ * .1, or .2 modifier (similar to the .b, .w, .l modifier). If you are
+ * manipulating a single register device which doesn't use an address
+ * field, use "0.0" for the address and the ".0" length field will
+ * suppress the address in the I2C data stream. This also works for
+ * successive reads using the I2C auto-incrementing memory pointer.
+ *
+ * If you are manipulating a large memory with 2-byte addresses, use
+ * the .2 address modifier, e.g. 210.2 addresses location 528 (decimal).
+ *
+ * Then there are the unfortunate memory chips that spill the most
+ * significant 1, 2, or 3 bits of address into the chip address byte.
+ * This effectively makes one chip (logically) look like 2, 4, or
+ * 8 chips. This is handled (awkwardly) by #defining
+ * CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW and using the .1 modifier on the
+ * {addr} field (since .1 is the default, it doesn't actually have to
+ * be specified). Examples: given a memory chip at I2C chip address
+ * 0x50, the following would happen...
+ * i2c md 50 0 10 display 16 bytes starting at 0x000
+ * On the bus: <S> A0 00 <E> <S> A1 <rd> ... <rd>
+ * i2c md 50 100 10 display 16 bytes starting at 0x100
+ * On the bus: <S> A2 00 <E> <S> A3 <rd> ... <rd>
+ * i2c md 50 210 10 display 16 bytes starting at 0x210
+ * On the bus: <S> A4 10 <E> <S> A5 <rd> ... <rd>
+ * This is awfully ugly. It would be nice if someone would think up
+ * a better way of handling this.
+ *
+ * Adapted from cmd_mem.c which is copyright Wolfgang Denk (wd@denx.de).
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+static uchar i2c_dp_last_chip;
+static uint i2c_dp_last_addr;
+static uint i2c_dp_last_alen;
+static uint i2c_dp_last_length = 0x10;
+
+static uchar i2c_mm_last_chip;
+static uint i2c_mm_last_addr;
+static uint i2c_mm_last_alen;
+
+/* If only one I2C bus is present, the list of devices to ignore when
+ * the probe command is issued is represented by a 1D array of addresses.
+ * When multiple buses are present, the list is an array of bus-address
+ * pairs. The following macros take care of this */
+
+#if defined(CONFIG_SYS_I2C_NOPROBES)
+#if defined(CONFIG_I2C_MULTI_BUS)
+static struct
+{
+ uchar bus;
+ uchar addr;
+} i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;
+#define GET_BUS_NUM i2c_get_bus_num()
+#define COMPARE_BUS(b,i) (i2c_no_probes[(i)].bus == (b))
+#define COMPARE_ADDR(a,i) (i2c_no_probes[(i)].addr == (a))
+#define NO_PROBE_ADDR(i) i2c_no_probes[(i)].addr
+#else /* single bus */
+static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;
+#define GET_BUS_NUM 0
+#define COMPARE_BUS(b,i) ((b) == 0) /* Make compiler happy */
+#define COMPARE_ADDR(a,i) (i2c_no_probes[(i)] == (a))
+#define NO_PROBE_ADDR(i) i2c_no_probes[(i)]
+#endif /* CONFIG_MULTI_BUS */
+
+#define NUM_ELEMENTS_NOPROBE (sizeof(i2c_no_probes)/sizeof(i2c_no_probes[0]))
+#endif
+
+#if defined(CONFIG_I2C_MUX)
+static I2C_MUX_DEVICE *i2c_mux_devices = NULL;
+static int i2c_mux_busid = CONFIG_SYS_MAX_I2C_BUS;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif
+
+#define DISP_LINE_LEN 16
+
+/* TODO: Implement architecture-specific get/set functions */
+unsigned int __def_i2c_get_bus_speed(void)
+{
+ return CONFIG_SYS_I2C_SPEED;
+}
+unsigned int i2c_get_bus_speed(void)
+ __attribute__((weak, alias("__def_i2c_get_bus_speed")));
+
+int __def_i2c_set_bus_speed(unsigned int speed)
+{
+ if (speed != CONFIG_SYS_I2C_SPEED)
+ return -1;
+
+ return 0;
+}
+int i2c_set_bus_speed(unsigned int)
+ __attribute__((weak, alias("__def_i2c_set_bus_speed")));
+
+/*
+ * get_alen: small parser helper function to get address length
+ * returns the address length
+ */
+static uint get_alen(char *arg)
+{
+ int j;
+ int alen;
+
+ alen = 1;
+ for (j = 0; j < 8; j++) {
+ if (arg[j] == '.') {
+ alen = arg[j+1] - '0';
+ break;
+ } else if (arg[j] == '\0')
+ break;
+ }
+ return alen;
+}
+
+/*
+ * Syntax:
+ * i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr}
+ */
+
+static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u_char chip;
+ uint devaddr, alen, length;
+ u_char *memaddr;
+
+ if (argc != 5)
+ return cmd_usage(cmdtp);
+
+ /*
+ * I2C chip address
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * I2C data address within the chip. This can be 1 or
+ * 2 bytes long. Some day it might be 3 bytes long :-).
+ */
+ devaddr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Length is the number of objects, not number of bytes.
+ */
+ length = simple_strtoul(argv[3], NULL, 16);
+
+ /*
+ * memaddr is the address where to store things in memory
+ */
+ memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16);
+
+ if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) {
+ puts ("Error reading the chip.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Syntax:
+ * i2c md {i2c_chip} {addr}{.0, .1, .2} {len}
+ */
+static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u_char chip;
+ uint addr, alen, length;
+ int j, nbytes, linebytes;
+
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ chip = i2c_dp_last_chip;
+ addr = i2c_dp_last_addr;
+ alen = i2c_dp_last_alen;
+ length = i2c_dp_last_length;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /*
+ * New command specified.
+ */
+
+ /*
+ * I2C chip address
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * I2C data address within the chip. This can be 1 or
+ * 2 bytes long. Some day it might be 3 bytes long :-).
+ */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * If another parameter, it is the length to display.
+ * Length is the number of objects, not number of bytes.
+ */
+ if (argc > 3)
+ length = simple_strtoul(argv[3], NULL, 16);
+ }
+
+ /*
+ * Print the lines.
+ *
+ * We buffer all read data, so we can make sure data is read only
+ * once.
+ */
+ nbytes = length;
+ do {
+ unsigned char linebuf[DISP_LINE_LEN];
+ unsigned char *cp;
+
+ linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
+
+ if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
+ puts ("Error reading the chip.\n");
+ else {
+ printf("%04x:", addr);
+ cp = linebuf;
+ for (j=0; j<linebytes; j++) {
+ printf(" %02x", *cp++);
+ addr++;
+ }
+ puts (" ");
+ cp = linebuf;
+ for (j=0; j<linebytes; j++) {
+ if ((*cp < 0x20) || (*cp > 0x7e))
+ puts (".");
+ else
+ printf("%c", *cp);
+ cp++;
+ }
+ putc ('\n');
+ }
+ nbytes -= linebytes;
+ } while (nbytes > 0);
+
+ i2c_dp_last_chip = chip;
+ i2c_dp_last_addr = addr;
+ i2c_dp_last_alen = alen;
+ i2c_dp_last_length = length;
+
+ return 0;
+}
+
+
+/* Write (fill) memory
+ *
+ * Syntax:
+ * i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}]
+ */
+static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uchar chip;
+ ulong addr;
+ uint alen;
+ uchar byte;
+ int count;
+
+ if ((argc < 4) || (argc > 5))
+ return cmd_usage(cmdtp);
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * Address is always specified.
+ */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Value to write is always specified.
+ */
+ byte = simple_strtoul(argv[3], NULL, 16);
+
+ /*
+ * Optional count
+ */
+ if (argc == 5)
+ count = simple_strtoul(argv[4], NULL, 16);
+ else
+ count = 1;
+
+ while (count-- > 0) {
+ if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
+ puts ("Error writing the chip.\n");
+ /*
+ * Wait for the write to complete. The write can take
+ * up to 10mSec (we allow a little more time).
+ */
+/*
+ * No write delay with FRAM devices.
+ */
+#if !defined(CONFIG_SYS_I2C_FRAM)
+ udelay(11000);
+#endif
+ }
+
+ return (0);
+}
+
+/* Calculate a CRC on memory
+ *
+ * Syntax:
+ * i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count}
+ */
+static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uchar chip;
+ ulong addr;
+ uint alen;
+ int count;
+ uchar byte;
+ ulong crc;
+ ulong err;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * Address is always specified.
+ */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Count is always specified
+ */
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ printf ("CRC32 for %08lx ... %08lx ==> ", addr, addr + count - 1);
+ /*
+ * CRC a byte at a time. This is going to be slooow, but hey, the
+ * memories are small and slow too so hopefully nobody notices.
+ */
+ crc = 0;
+ err = 0;
+ while (count-- > 0) {
+ if (i2c_read(chip, addr, alen, &byte, 1) != 0)
+ err++;
+ crc = crc32 (crc, &byte, 1);
+ addr++;
+ }
+ if (err > 0)
+ puts ("Error reading the chip,\n");
+ else
+ printf ("%08lx\n", crc);
+
+ return 0;
+}
+
+/* Modify memory.
+ *
+ * Syntax:
+ * i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}
+ * i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}
+ */
+
+static int
+mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+ uchar chip;
+ ulong addr;
+ uint alen;
+ ulong data;
+ int size = 1;
+ int nbytes;
+ extern char console_buffer[];
+
+ if (argc != 3)
+ return cmd_usage(cmdtp);
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+ reset_cmd_timeout(); /* got a good command to get here */
+#endif
+ /*
+ * We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ chip = i2c_mm_last_chip;
+ addr = i2c_mm_last_addr;
+ alen = i2c_mm_last_alen;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /*
+ * New command specified. Check for a size specification.
+ * Defaults to byte if no or incorrect specification.
+ */
+ size = cmd_get_data_size(argv[0], 1);
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * Address is always specified.
+ */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+ }
+
+ /*
+ * Print the address, followed by value. Then accept input for
+ * the next value. A non-converted value exits.
+ */
+ do {
+ printf("%08lx:", addr);
+ if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0)
+ puts ("\nError reading the chip,\n");
+ else {
+ data = cpu_to_be32(data);
+ if (size == 1)
+ printf(" %02lx", (data >> 24) & 0x000000FF);
+ else if (size == 2)
+ printf(" %04lx", (data >> 16) & 0x0000FFFF);
+ else
+ printf(" %08lx", data);
+ }
+
+ nbytes = readline (" ? ");
+ if (nbytes == 0) {
+ /*
+ * <CR> pressed as only input, don't modify current
+ * location and move to next.
+ */
+ if (incrflag)
+ addr += size;
+ nbytes = size;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ reset_cmd_timeout(); /* good enough to not time out */
+#endif
+ }
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (nbytes == -2)
+ break; /* timed out, exit the command */
+#endif
+ else {
+ char *endp;
+
+ data = simple_strtoul(console_buffer, &endp, 16);
+ if (size == 1)
+ data = data << 24;
+ else if (size == 2)
+ data = data << 16;
+ data = be32_to_cpu(data);
+ nbytes = endp - console_buffer;
+ if (nbytes) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ /*
+ * good enough to not time out
+ */
+ reset_cmd_timeout();
+#endif
+ if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0)
+ puts ("Error writing the chip.\n");
+#ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+ udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+#endif
+ if (incrflag)
+ addr += size;
+ }
+ }
+ } while (nbytes);
+
+ i2c_mm_last_chip = chip;
+ i2c_mm_last_addr = addr;
+ i2c_mm_last_alen = alen;
+
+ return 0;
+}
+
+/*
+ * Syntax:
+ * i2c probe {addr}{.0, .1, .2}
+ */
+static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int j;
+#if defined(CONFIG_SYS_I2C_NOPROBES)
+ int k, skip;
+ uchar bus = GET_BUS_NUM;
+#endif /* NOPROBES */
+
+ puts ("Valid chip addresses:");
+ for (j = 0; j < 128; j++) {
+#if defined(CONFIG_SYS_I2C_NOPROBES)
+ skip = 0;
+ for (k=0; k < NUM_ELEMENTS_NOPROBE; k++) {
+ if (COMPARE_BUS(bus, k) && COMPARE_ADDR(j, k)) {
+ skip = 1;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+#endif
+ if (i2c_probe(j) == 0)
+ printf(" %02X", j);
+ }
+ putc ('\n');
+
+#if defined(CONFIG_SYS_I2C_NOPROBES)
+ puts ("Excluded chip addresses:");
+ for (k=0; k < NUM_ELEMENTS_NOPROBE; k++) {
+ if (COMPARE_BUS(bus,k))
+ printf(" %02X", NO_PROBE_ADDR(k));
+ }
+ putc ('\n');
+#endif
+
+ return 0;
+}
+
+/*
+ * Syntax:
+ * i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}]
+ * {length} - Number of bytes to read
+ * {delay} - A DECIMAL number and defaults to 1000 uSec
+ */
+static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u_char chip;
+ ulong alen;
+ uint addr;
+ uint length;
+ u_char bytes[16];
+ int delay;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul(argv[1], NULL, 16);
+
+ /*
+ * Address is always specified.
+ */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ alen = get_alen(argv[2]);
+ if (alen > 3)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Length is the number of objects, not number of bytes.
+ */
+ length = 1;
+ length = simple_strtoul(argv[3], NULL, 16);
+ if (length > sizeof(bytes))
+ length = sizeof(bytes);
+
+ /*
+ * The delay time (uSec) is optional.
+ */
+ delay = 1000;
+ if (argc > 3)
+ delay = simple_strtoul(argv[4], NULL, 10);
+ /*
+ * Run the loop...
+ */
+ while (1) {
+ if (i2c_read(chip, addr, alen, bytes, length) != 0)
+ puts ("Error reading the chip.\n");
+ udelay(delay);
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+/*
+ * The SDRAM command is separately configured because many
+ * (most?) embedded boards don't use SDRAM DIMMs.
+ */
+#if defined(CONFIG_CMD_SDRAM)
+static void print_ddr2_tcyc (u_char const b)
+{
+ printf ("%d.", (b >> 4) & 0x0F);
+ switch (b & 0x0F) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ printf ("%d ns\n", b & 0x0F);
+ break;
+ case 0xA:
+ puts ("25 ns\n");
+ break;
+ case 0xB:
+ puts ("33 ns\n");
+ break;
+ case 0xC:
+ puts ("66 ns\n");
+ break;
+ case 0xD:
+ puts ("75 ns\n");
+ break;
+ default:
+ puts ("?? ns\n");
+ break;
+ }
+}
+
+static void decode_bits (u_char const b, char const *str[], int const do_once)
+{
+ u_char mask;
+
+ for (mask = 0x80; mask != 0x00; mask >>= 1, ++str) {
+ if (b & mask) {
+ puts (*str);
+ if (do_once)
+ return;
+ }
+ }
+}
+
+/*
+ * Syntax:
+ * i2c sdram {i2c_chip}
+ */
+static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ enum { unknown, EDO, SDRAM, DDR2 } type;
+
+ u_char chip;
+ u_char data[128];
+ u_char cksum;
+ int j;
+
+ static const char *decode_CAS_DDR2[] = {
+ " TBD", " 6", " 5", " 4", " 3", " 2", " TBD", " TBD"
+ };
+
+ static const char *decode_CAS_default[] = {
+ " TBD", " 7", " 6", " 5", " 4", " 3", " 2", " 1"
+ };
+
+ static const char *decode_CS_WE_default[] = {
+ " TBD", " 6", " 5", " 4", " 3", " 2", " 1", " 0"
+ };
+
+ static const char *decode_byte21_default[] = {
+ " TBD (bit 7)\n",
+ " Redundant row address\n",
+ " Differential clock input\n",
+ " Registerd DQMB inputs\n",
+ " Buffered DQMB inputs\n",
+ " On-card PLL\n",
+ " Registered address/control lines\n",
+ " Buffered address/control lines\n"
+ };
+
+ static const char *decode_byte22_DDR2[] = {
+ " TBD (bit 7)\n",
+ " TBD (bit 6)\n",
+ " TBD (bit 5)\n",
+ " TBD (bit 4)\n",
+ " TBD (bit 3)\n",
+ " Supports partial array self refresh\n",
+ " Supports 50 ohm ODT\n",
+ " Supports weak driver\n"
+ };
+
+ static const char *decode_row_density_DDR2[] = {
+ "512 MiB", "256 MiB", "128 MiB", "16 GiB",
+ "8 GiB", "4 GiB", "2 GiB", "1 GiB"
+ };
+
+ static const char *decode_row_density_default[] = {
+ "512 MiB", "256 MiB", "128 MiB", "64 MiB",
+ "32 MiB", "16 MiB", "8 MiB", "4 MiB"
+ };
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /*
+ * Chip is always specified.
+ */
+ chip = simple_strtoul (argv[1], NULL, 16);
+
+ if (i2c_read (chip, 0, 1, data, sizeof (data)) != 0) {
+ puts ("No SDRAM Serial Presence Detect found.\n");
+ return 1;
+ }
+
+ cksum = 0;
+ for (j = 0; j < 63; j++) {
+ cksum += data[j];
+ }
+ if (cksum != data[63]) {
+ printf ("WARNING: Configuration data checksum failure:\n"
+ " is 0x%02x, calculated 0x%02x\n", data[63], cksum);
+ }
+ printf ("SPD data revision %d.%d\n",
+ (data[62] >> 4) & 0x0F, data[62] & 0x0F);
+ printf ("Bytes used 0x%02X\n", data[0]);
+ printf ("Serial memory size 0x%02X\n", 1 << data[1]);
+
+ puts ("Memory type ");
+ switch (data[2]) {
+ case 2:
+ type = EDO;
+ puts ("EDO\n");
+ break;
+ case 4:
+ type = SDRAM;
+ puts ("SDRAM\n");
+ break;
+ case 8:
+ type = DDR2;
+ puts ("DDR2\n");
+ break;
+ default:
+ type = unknown;
+ puts ("unknown\n");
+ break;
+ }
+
+ puts ("Row address bits ");
+ if ((data[3] & 0x00F0) == 0)
+ printf ("%d\n", data[3] & 0x0F);
+ else
+ printf ("%d/%d\n", data[3] & 0x0F, (data[3] >> 4) & 0x0F);
+
+ puts ("Column address bits ");
+ if ((data[4] & 0x00F0) == 0)
+ printf ("%d\n", data[4] & 0x0F);
+ else
+ printf ("%d/%d\n", data[4] & 0x0F, (data[4] >> 4) & 0x0F);
+
+ switch (type) {
+ case DDR2:
+ printf ("Number of ranks %d\n",
+ (data[5] & 0x07) + 1);
+ break;
+ default:
+ printf ("Module rows %d\n", data[5]);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("Module data width %d bits\n", data[6]);
+ break;
+ default:
+ printf ("Module data width %d bits\n",
+ (data[7] << 8) | data[6]);
+ break;
+ }
+
+ puts ("Interface signal levels ");
+ switch(data[8]) {
+ case 0: puts ("TTL 5.0 V\n"); break;
+ case 1: puts ("LVTTL\n"); break;
+ case 2: puts ("HSTL 1.5 V\n"); break;
+ case 3: puts ("SSTL 3.3 V\n"); break;
+ case 4: puts ("SSTL 2.5 V\n"); break;
+ case 5: puts ("SSTL 1.8 V\n"); break;
+ default: puts ("unknown\n"); break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM cycle time ");
+ print_ddr2_tcyc (data[9]);
+ break;
+ default:
+ printf ("SDRAM cycle time %d.%d ns\n",
+ (data[9] >> 4) & 0x0F, data[9] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM access time 0.%d%d ns\n",
+ (data[10] >> 4) & 0x0F, data[10] & 0x0F);
+ break;
+ default:
+ printf ("SDRAM access time %d.%d ns\n",
+ (data[10] >> 4) & 0x0F, data[10] & 0x0F);
+ break;
+ }
+
+ puts ("EDC configuration ");
+ switch (data[11]) {
+ case 0: puts ("None\n"); break;
+ case 1: puts ("Parity\n"); break;
+ case 2: puts ("ECC\n"); break;
+ default: puts ("unknown\n"); break;
+ }
+
+ if ((data[12] & 0x80) == 0)
+ puts ("No self refresh, rate ");
+ else
+ puts ("Self refresh, rate ");
+
+ switch(data[12] & 0x7F) {
+ case 0: puts ("15.625 us\n"); break;
+ case 1: puts ("3.9 us\n"); break;
+ case 2: puts ("7.8 us\n"); break;
+ case 3: puts ("31.3 us\n"); break;
+ case 4: puts ("62.5 us\n"); break;
+ case 5: puts ("125 us\n"); break;
+ default: puts ("unknown\n"); break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM width (primary) %d\n", data[13]);
+ break;
+ default:
+ printf ("SDRAM width (primary) %d\n", data[13] & 0x7F);
+ if ((data[13] & 0x80) != 0) {
+ printf (" (second bank) %d\n",
+ 2 * (data[13] & 0x7F));
+ }
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ if (data[14] != 0)
+ printf ("EDC width %d\n", data[14]);
+ break;
+ default:
+ if (data[14] != 0) {
+ printf ("EDC width %d\n",
+ data[14] & 0x7F);
+
+ if ((data[14] & 0x80) != 0) {
+ printf (" (second bank) %d\n",
+ 2 * (data[14] & 0x7F));
+ }
+ }
+ break;
+ }
+
+ if (DDR2 != type) {
+ printf ("Min clock delay, back-to-back random column addresses "
+ "%d\n", data[15]);
+ }
+
+ puts ("Burst length(s) ");
+ if (data[16] & 0x80) puts (" Page");
+ if (data[16] & 0x08) puts (" 8");
+ if (data[16] & 0x04) puts (" 4");
+ if (data[16] & 0x02) puts (" 2");
+ if (data[16] & 0x01) puts (" 1");
+ putc ('\n');
+ printf ("Number of banks %d\n", data[17]);
+
+ switch (type) {
+ case DDR2:
+ puts ("CAS latency(s) ");
+ decode_bits (data[18], decode_CAS_DDR2, 0);
+ putc ('\n');
+ break;
+ default:
+ puts ("CAS latency(s) ");
+ decode_bits (data[18], decode_CAS_default, 0);
+ putc ('\n');
+ break;
+ }
+
+ if (DDR2 != type) {
+ puts ("CS latency(s) ");
+ decode_bits (data[19], decode_CS_WE_default, 0);
+ putc ('\n');
+ }
+
+ if (DDR2 != type) {
+ puts ("WE latency(s) ");
+ decode_bits (data[20], decode_CS_WE_default, 0);
+ putc ('\n');
+ }
+
+ switch (type) {
+ case DDR2:
+ puts ("Module attributes:\n");
+ if (data[21] & 0x80)
+ puts (" TBD (bit 7)\n");
+ if (data[21] & 0x40)
+ puts (" Analysis probe installed\n");
+ if (data[21] & 0x20)
+ puts (" TBD (bit 5)\n");
+ if (data[21] & 0x10)
+ puts (" FET switch external enable\n");
+ printf (" %d PLLs on DIMM\n", (data[21] >> 2) & 0x03);
+ if (data[20] & 0x11) {
+ printf (" %d active registers on DIMM\n",
+ (data[21] & 0x03) + 1);
+ }
+ break;
+ default:
+ puts ("Module attributes:\n");
+ if (!data[21])
+ puts (" (none)\n");
+ else
+ decode_bits (data[21], decode_byte21_default, 0);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ decode_bits (data[22], decode_byte22_DDR2, 0);
+ break;
+ default:
+ puts ("Device attributes:\n");
+ if (data[22] & 0x80) puts (" TBD (bit 7)\n");
+ if (data[22] & 0x40) puts (" TBD (bit 6)\n");
+ if (data[22] & 0x20) puts (" Upper Vcc tolerance 5%\n");
+ else puts (" Upper Vcc tolerance 10%\n");
+ if (data[22] & 0x10) puts (" Lower Vcc tolerance 5%\n");
+ else puts (" Lower Vcc tolerance 10%\n");
+ if (data[22] & 0x08) puts (" Supports write1/read burst\n");
+ if (data[22] & 0x04) puts (" Supports precharge all\n");
+ if (data[22] & 0x02) puts (" Supports auto precharge\n");
+ if (data[22] & 0x01) puts (" Supports early RAS# precharge\n");
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM cycle time (2nd highest CAS latency) ");
+ print_ddr2_tcyc (data[23]);
+ break;
+ default:
+ printf ("SDRAM cycle time (2nd highest CAS latency) %d."
+ "%d ns\n", (data[23] >> 4) & 0x0F, data[23] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM access from clock (2nd highest CAS latency) 0."
+ "%d%d ns\n", (data[24] >> 4) & 0x0F, data[24] & 0x0F);
+ break;
+ default:
+ printf ("SDRAM access from clock (2nd highest CAS latency) %d."
+ "%d ns\n", (data[24] >> 4) & 0x0F, data[24] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM cycle time (3rd highest CAS latency) ");
+ print_ddr2_tcyc (data[25]);
+ break;
+ default:
+ printf ("SDRAM cycle time (3rd highest CAS latency) %d."
+ "%d ns\n", (data[25] >> 4) & 0x0F, data[25] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("SDRAM access from clock (3rd highest CAS latency) 0."
+ "%d%d ns\n", (data[26] >> 4) & 0x0F, data[26] & 0x0F);
+ break;
+ default:
+ printf ("SDRAM access from clock (3rd highest CAS latency) %d."
+ "%d ns\n", (data[26] >> 4) & 0x0F, data[26] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("Minimum row precharge %d.%02d ns\n",
+ (data[27] >> 2) & 0x3F, 25 * (data[27] & 0x03));
+ break;
+ default:
+ printf ("Minimum row precharge %d ns\n", data[27]);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("Row active to row active min %d.%02d ns\n",
+ (data[28] >> 2) & 0x3F, 25 * (data[28] & 0x03));
+ break;
+ default:
+ printf ("Row active to row active min %d ns\n", data[28]);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("RAS to CAS delay min %d.%02d ns\n",
+ (data[29] >> 2) & 0x3F, 25 * (data[29] & 0x03));
+ break;
+ default:
+ printf ("RAS to CAS delay min %d ns\n", data[29]);
+ break;
+ }
+
+ printf ("Minimum RAS pulse width %d ns\n", data[30]);
+
+ switch (type) {
+ case DDR2:
+ puts ("Density of each row ");
+ decode_bits (data[31], decode_row_density_DDR2, 1);
+ putc ('\n');
+ break;
+ default:
+ puts ("Density of each row ");
+ decode_bits (data[31], decode_row_density_default, 1);
+ putc ('\n');
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ puts ("Command and Address setup ");
+ if (data[32] >= 0xA0) {
+ printf ("1.%d%d ns\n",
+ ((data[32] >> 4) & 0x0F) - 10, data[32] & 0x0F);
+ } else {
+ printf ("0.%d%d ns\n",
+ ((data[32] >> 4) & 0x0F), data[32] & 0x0F);
+ }
+ break;
+ default:
+ printf ("Command and Address setup %c%d.%d ns\n",
+ (data[32] & 0x80) ? '-' : '+',
+ (data[32] >> 4) & 0x07, data[32] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ puts ("Command and Address hold ");
+ if (data[33] >= 0xA0) {
+ printf ("1.%d%d ns\n",
+ ((data[33] >> 4) & 0x0F) - 10, data[33] & 0x0F);
+ } else {
+ printf ("0.%d%d ns\n",
+ ((data[33] >> 4) & 0x0F), data[33] & 0x0F);
+ }
+ break;
+ default:
+ printf ("Command and Address hold %c%d.%d ns\n",
+ (data[33] & 0x80) ? '-' : '+',
+ (data[33] >> 4) & 0x07, data[33] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("Data signal input setup 0.%d%d ns\n",
+ (data[34] >> 4) & 0x0F, data[34] & 0x0F);
+ break;
+ default:
+ printf ("Data signal input setup %c%d.%d ns\n",
+ (data[34] & 0x80) ? '-' : '+',
+ (data[34] >> 4) & 0x07, data[34] & 0x0F);
+ break;
+ }
+
+ switch (type) {
+ case DDR2:
+ printf ("Data signal input hold 0.%d%d ns\n",
+ (data[35] >> 4) & 0x0F, data[35] & 0x0F);
+ break;
+ default:
+ printf ("Data signal input hold %c%d.%d ns\n",
+ (data[35] & 0x80) ? '-' : '+',
+ (data[35] >> 4) & 0x07, data[35] & 0x0F);
+ break;
+ }
+
+ puts ("Manufacturer's JEDEC ID ");
+ for (j = 64; j <= 71; j++)
+ printf ("%02X ", data[j]);
+ putc ('\n');
+ printf ("Manufacturing Location %02X\n", data[72]);
+ puts ("Manufacturer's Part Number ");
+ for (j = 73; j <= 90; j++)
+ printf ("%02X ", data[j]);
+ putc ('\n');
+ printf ("Revision Code %02X %02X\n", data[91], data[92]);
+ printf ("Manufacturing Date %02X %02X\n", data[93], data[94]);
+ puts ("Assembly Serial Number ");
+ for (j = 95; j <= 98; j++)
+ printf ("%02X ", data[j]);
+ putc ('\n');
+
+ if (DDR2 != type) {
+ printf ("Speed rating PC%d\n",
+ data[126] == 0x66 ? 66 : data[126]);
+ }
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_I2C_MUX)
+static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int ret=0;
+
+ if (argc == 1) {
+ /* show all busses */
+ I2C_MUX *mux;
+ I2C_MUX_DEVICE *device = i2c_mux_devices;
+
+ printf ("Busses reached over muxes:\n");
+ while (device != NULL) {
+ printf ("Bus ID: %x\n", device->busid);
+ printf (" reached over Mux(es):\n");
+ mux = device->mux;
+ while (mux != NULL) {
+ printf (" %s@%x ch: %x\n", mux->name, mux->chip, mux->channel);
+ mux = mux->next;
+ }
+ device = device->next;
+ }
+ } else {
+ I2C_MUX_DEVICE *dev;
+
+ dev = i2c_mux_ident_muxstring ((uchar *)argv[1]);
+ ret = 0;
+ }
+ return ret;
+}
+#endif /* CONFIG_I2C_MUX */
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int bus_idx, ret=0;
+
+ if (argc == 1)
+ /* querying current setting */
+ printf("Current bus is %d\n", i2c_get_bus_num());
+ else {
+ bus_idx = simple_strtoul(argv[1], NULL, 10);
+ printf("Setting bus to %d\n", bus_idx);
+ ret = i2c_set_bus_num(bus_idx);
+ if (ret)
+ printf("Failure changing bus number (%d)\n", ret);
+ }
+ return ret;
+}
+#endif /* CONFIG_I2C_MULTI_BUS */
+
+static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int speed, ret=0;
+
+ if (argc == 1)
+ /* querying current speed */
+ printf("Current bus speed=%d\n", i2c_get_bus_speed());
+ else {
+ speed = simple_strtoul(argv[1], NULL, 10);
+ printf("Setting bus speed to %d Hz\n", speed);
+ ret = i2c_set_bus_speed(speed);
+ if (ret)
+ printf("Failure changing bus speed (%d)\n", ret);
+ }
+ return ret;
+}
+
+static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_i2c_mem (cmdtp, 1, flag, argc, argv);
+}
+
+static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_i2c_mem (cmdtp, 0, flag, argc, argv);
+}
+
+static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ return 0;
+}
+
+static cmd_tbl_t cmd_i2c_sub[] = {
+#if defined(CONFIG_I2C_MUX)
+ U_BOOT_CMD_MKENT(bus, 1, 1, do_i2c_add_bus, "", ""),
+#endif /* CONFIG_I2C_MUX */
+ U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),
+#if defined(CONFIG_I2C_MULTI_BUS)
+ U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),
+#endif /* CONFIG_I2C_MULTI_BUS */
+ U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""),
+ U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""),
+ U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""),
+ U_BOOT_CMD_MKENT(mw, 3, 1, do_i2c_mw, "", ""),
+ U_BOOT_CMD_MKENT(nm, 2, 1, do_i2c_nm, "", ""),
+ U_BOOT_CMD_MKENT(probe, 0, 1, do_i2c_probe, "", ""),
+ U_BOOT_CMD_MKENT(read, 5, 1, do_i2c_read, "", ""),
+ U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""),
+#if defined(CONFIG_CMD_SDRAM)
+ U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(speed, 1, 1, do_i2c_bus_speed, "", ""),
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+void i2c_reloc(void) {
+ fixup_cmdtable(cmd_i2c_sub, ARRAY_SIZE(cmd_i2c_sub));
+}
+#endif
+
+static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /* Strip off leading 'i2c' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_i2c_sub[0], ARRAY_SIZE(cmd_i2c_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else
+ return cmd_usage(cmdtp);
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ i2c, 6, 1, do_i2c,
+ "I2C sub-system",
+#if defined(CONFIG_I2C_MUX)
+ "bus [muxtype:muxaddr:muxchannel] - add a new bus reached over muxes\ni2c "
+#endif /* CONFIG_I2C_MUX */
+ "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"
+#if defined(CONFIG_I2C_MULTI_BUS)
+ "i2c dev [dev] - show or set current I2C bus\n"
+#endif /* CONFIG_I2C_MULTI_BUS */
+ "i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n"
+ "i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n"
+ "i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n"
+ "i2c mw chip address[.0, .1, .2] value [count] - write to I2C device (fill)\n"
+ "i2c nm chip address[.0, .1, .2] - write to I2C device (constant address)\n"
+ "i2c probe - show devices on the I2C bus\n"
+ "i2c read chip address[.0, .1, .2] length memaddress - read to memory \n"
+ "i2c reset - re-init the I2C Controller\n"
+#if defined(CONFIG_CMD_SDRAM)
+ "i2c sdram chip - print SDRAM configuration information\n"
+#endif
+ "i2c speed [speed] - show or set I2C bus speed"
+);
+
+#if defined(CONFIG_I2C_MUX)
+static int i2c_mux_add_device(I2C_MUX_DEVICE *dev)
+{
+ I2C_MUX_DEVICE *devtmp = i2c_mux_devices;
+
+ if (i2c_mux_devices == NULL) {
+ i2c_mux_devices = dev;
+ return 0;
+ }
+ while (devtmp->next != NULL)
+ devtmp = devtmp->next;
+
+ devtmp->next = dev;
+ return 0;
+}
+
+I2C_MUX_DEVICE *i2c_mux_search_device(int id)
+{
+ I2C_MUX_DEVICE *device = i2c_mux_devices;
+
+ while (device != NULL) {
+ if (device->busid == id)
+ return device;
+ device = device->next;
+ }
+ return NULL;
+}
+
+/* searches in the buf from *pos the next ':'.
+ * returns:
+ * 0 if found (with *pos = where)
+ * < 0 if an error occured
+ * > 0 if the end of buf is reached
+ */
+static int i2c_mux_search_next (int *pos, uchar *buf, int len)
+{
+ while ((buf[*pos] != ':') && (*pos < len)) {
+ *pos += 1;
+ }
+ if (*pos >= len)
+ return 1;
+ if (buf[*pos] != ':')
+ return -1;
+ return 0;
+}
+
+static int i2c_mux_get_busid (void)
+{
+ int tmp = i2c_mux_busid;
+
+ i2c_mux_busid ++;
+ return tmp;
+}
+
+/* Analyses a Muxstring and sends immediately the
+ Commands to the Muxes. Runs from Flash.
+ */
+int i2c_mux_ident_muxstring_f (uchar *buf)
+{
+ int pos = 0;
+ int oldpos;
+ int ret = 0;
+ int len = strlen((char *)buf);
+ int chip;
+ uchar channel;
+ int was = 0;
+
+ while (ret == 0) {
+ oldpos = pos;
+ /* search name */
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret != 0)
+ printf ("ERROR\n");
+ /* search address */
+ pos ++;
+ oldpos = pos;
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret != 0)
+ printf ("ERROR\n");
+ buf[pos] = 0;
+ chip = simple_strtoul((char *)&buf[oldpos], NULL, 16);
+ buf[pos] = ':';
+ /* search channel */
+ pos ++;
+ oldpos = pos;
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret < 0)
+ printf ("ERROR\n");
+ was = 0;
+ if (buf[pos] != 0) {
+ buf[pos] = 0;
+ was = 1;
+ }
+ channel = simple_strtoul((char *)&buf[oldpos], NULL, 16);
+ if (was)
+ buf[pos] = ':';
+ if (i2c_write(chip, 0, 0, &channel, 1) != 0) {
+ printf ("Error setting Mux: chip:%x channel: \
+ %x\n", chip, channel);
+ return -1;
+ }
+ pos ++;
+ oldpos = pos;
+
+ }
+
+ return 0;
+}
+
+/* Analyses a Muxstring and if this String is correct
+ * adds a new I2C Bus.
+ */
+I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf)
+{
+ I2C_MUX_DEVICE *device;
+ I2C_MUX *mux;
+ int pos = 0;
+ int oldpos;
+ int ret = 0;
+ int len = strlen((char *)buf);
+ int was = 0;
+
+ device = (I2C_MUX_DEVICE *)malloc (sizeof(I2C_MUX_DEVICE));
+ device->mux = NULL;
+ device->busid = i2c_mux_get_busid ();
+ device->next = NULL;
+ while (ret == 0) {
+ mux = (I2C_MUX *)malloc (sizeof(I2C_MUX));
+ mux->next = NULL;
+ /* search name of mux */
+ oldpos = pos;
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret != 0)
+ printf ("%s no name.\n", __FUNCTION__);
+ mux->name = (char *)malloc (pos - oldpos + 1);
+ memcpy (mux->name, &buf[oldpos], pos - oldpos);
+ mux->name[pos - oldpos] = 0;
+ /* search address */
+ pos ++;
+ oldpos = pos;
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret != 0)
+ printf ("%s no mux address.\n", __FUNCTION__);
+ buf[pos] = 0;
+ mux->chip = simple_strtoul((char *)&buf[oldpos], NULL, 16);
+ buf[pos] = ':';
+ /* search channel */
+ pos ++;
+ oldpos = pos;
+ ret = i2c_mux_search_next(&pos, buf, len);
+ if (ret < 0)
+ printf ("%s no mux channel.\n", __FUNCTION__);
+ was = 0;
+ if (buf[pos] != 0) {
+ buf[pos] = 0;
+ was = 1;
+ }
+ mux->channel = simple_strtoul((char *)&buf[oldpos], NULL, 16);
+ if (was)
+ buf[pos] = ':';
+ if (device->mux == NULL)
+ device->mux = mux;
+ else {
+ I2C_MUX *muxtmp = device->mux;
+ while (muxtmp->next != NULL) {
+ muxtmp = muxtmp->next;
+ }
+ muxtmp->next = mux;
+ }
+ pos ++;
+ oldpos = pos;
+ }
+ if (ret > 0) {
+ /* Add Device */
+ i2c_mux_add_device (device);
+ return device;
+ }
+
+ return NULL;
+}
+
+int i2x_mux_select_mux(int bus)
+{
+ I2C_MUX_DEVICE *dev;
+ I2C_MUX *mux;
+
+ if ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC) {
+ /* select Default Mux Bus */
+#if defined(CONFIG_SYS_I2C_IVM_BUS)
+ i2c_mux_ident_muxstring_f ((uchar *)CONFIG_SYS_I2C_IVM_BUS);
+#else
+ {
+ unsigned char *buf;
+ buf = (unsigned char *) getenv("EEprom_ivm");
+ if (buf != NULL)
+ i2c_mux_ident_muxstring_f (buf);
+ }
+#endif
+ return 0;
+ }
+ dev = i2c_mux_search_device(bus);
+ if (dev == NULL)
+ return -1;
+
+ mux = dev->mux;
+ while (mux != NULL) {
+ if (i2c_write(mux->chip, 0, 0, &mux->channel, 1) != 0) {
+ printf ("Error setting Mux: chip:%x channel: \
+ %x\n", mux->chip, mux->channel);
+ return -1;
+ }
+ mux = mux->next;
+ }
+ return 0;
+}
+#endif /* CONFIG_I2C_MUX */
diff --git a/u-boot/common/cmd_ide.c b/u-boot/common/cmd_ide.c
new file mode 100644
index 0000000..a1f7e57
--- /dev/null
+++ b/u-boot/common/cmd_ide.c
@@ -0,0 +1,2027 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ *
+ */
+
+/*
+ * IDE support
+ */
+
+#include <common.h>
+#include <config.h>
+#include <watchdog.h>
+#include <command.h>
+#include <image.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA)
+# include <pcmcia.h>
+#endif
+
+#ifdef CONFIG_8xx
+# include <mpc8xx.h>
+#endif
+
+#ifdef CONFIG_MPC5xxx
+#include <mpc5xxx.h>
+#endif
+
+#ifdef CONFIG_ORION5X
+#include <asm/arch/orion5x.h>
+#elif defined CONFIG_KIRKWOOD
+#include <asm/arch/kirkwood.h>
+#endif
+
+#include <ide.h>
+#include <ata.h>
+
+#ifdef CONFIG_STATUS_LED
+# include <status_led.h>
+#endif
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#ifdef __PPC__
+# define EIEIO __asm__ volatile ("eieio")
+# define SYNC __asm__ volatile ("sync")
+#else
+# define EIEIO /* nothing */
+# define SYNC /* nothing */
+#endif
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+/* Timings for IDE Interface
+ *
+ * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
+ * 70 165 30 PIO-Mode 0, [ns]
+ * 4 9 2 [Cycles]
+ * 50 125 20 PIO-Mode 1, [ns]
+ * 3 7 2 [Cycles]
+ * 30 100 15 PIO-Mode 2, [ns]
+ * 2 6 1 [Cycles]
+ * 30 80 10 PIO-Mode 3, [ns]
+ * 2 5 1 [Cycles]
+ * 25 70 10 PIO-Mode 4, [ns]
+ * 2 4 1 [Cycles]
+ */
+
+const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
+{
+ /* Setup Length Hold */
+ { 70, 165, 30 }, /* PIO-Mode 0, [ns] */
+ { 50, 125, 20 }, /* PIO-Mode 1, [ns] */
+ { 30, 101, 15 }, /* PIO-Mode 2, [ns] */
+ { 30, 80, 10 }, /* PIO-Mode 3, [ns] */
+ { 25, 70, 10 }, /* PIO-Mode 4, [ns] */
+};
+
+static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
+
+#ifndef CONFIG_SYS_PIO_MODE
+#define CONFIG_SYS_PIO_MODE 0 /* use a relaxed default */
+#endif
+static int pio_mode = CONFIG_SYS_PIO_MODE;
+
+/* Make clock cycles and always round up */
+
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+/* ------------------------------------------------------------------------- */
+
+/* Current I/O Device */
+static int curr_device = -1;
+
+/* Current offset for IDE0 / IDE1 bus access */
+ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS] = {
+#if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
+ CONFIG_SYS_ATA_IDE0_OFFSET,
+#endif
+#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) && (CONFIG_SYS_IDE_MAXBUS > 1)
+ CONFIG_SYS_ATA_IDE1_OFFSET,
+#endif
+};
+
+
+static int ide_bus_ok[CONFIG_SYS_IDE_MAXBUS];
+
+block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+# if !defined(CONFIG_BMS2003) && \
+ !defined(CONFIG_CPC45) && \
+ !defined(CONFIG_KUP4K) && \
+ !defined(CONFIG_KUP4X)
+static void ide_led (uchar led, uchar status);
+#else
+extern void ide_led (uchar led, uchar status);
+#endif
+#else
+#define ide_led(a,b) /* dummy */
+#endif
+
+#ifdef CONFIG_IDE_RESET
+static void ide_reset (void);
+#else
+#define ide_reset() /* dummy */
+#endif
+
+static void ide_ident (block_dev_desc_t *dev_desc);
+static uchar ide_wait (int dev, ulong t);
+
+#define IDE_TIME_OUT 2000 /* 2 sec timeout */
+
+#define ATAPI_TIME_OUT 7000 /* 7 sec timeout (5 sec seems to work...) */
+
+#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
+
+static void input_data(int dev, ulong *sect_buf, int words);
+static void output_data(int dev, ulong *sect_buf, int words);
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+
+#ifndef CONFIG_SYS_ATA_PORT_ADDR
+#define CONFIG_SYS_ATA_PORT_ADDR(port) (port)
+#endif
+
+#ifdef CONFIG_ATAPI
+static void atapi_inquiry(block_dev_desc_t *dev_desc);
+ulong atapi_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer);
+#endif
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+static void set_pcmcia_timing (int pmode);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int rcode = 0;
+
+ switch (argc) {
+ case 0:
+ case 1:
+ return cmd_usage(cmdtp);
+ case 2:
+ if (strncmp(argv[1],"res",3) == 0) {
+ puts ("\nReset IDE"
+#ifdef CONFIG_IDE_8xx_DIRECT
+ " on PCMCIA " PCMCIA_SLOT_MSG
+#endif
+ ": ");
+
+ ide_init ();
+ return 0;
+ } else if (strncmp(argv[1],"inf",3) == 0) {
+ int i;
+
+ putc ('\n');
+
+ for (i=0; i<CONFIG_SYS_IDE_MAXDEVICE; ++i) {
+ if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN)
+ continue; /* list only known devices */
+ printf ("IDE device %d: ", i);
+ dev_print(&ide_dev_desc[i]);
+ }
+ return 0;
+
+ } else if (strncmp(argv[1],"dev",3) == 0) {
+ if ((curr_device < 0) || (curr_device >= CONFIG_SYS_IDE_MAXDEVICE)) {
+ puts ("\nno IDE devices available\n");
+ return 1;
+ }
+ printf ("\nIDE device %d: ", curr_device);
+ dev_print(&ide_dev_desc[curr_device]);
+ return 0;
+ } else if (strncmp(argv[1],"part",4) == 0) {
+ int dev, ok;
+
+ for (ok=0, dev=0; dev<CONFIG_SYS_IDE_MAXDEVICE; ++dev) {
+ if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+ ++ok;
+ if (dev)
+ putc ('\n');
+ print_part(&ide_dev_desc[dev]);
+ }
+ }
+ if (!ok) {
+ puts ("\nno IDE devices available\n");
+ rcode ++;
+ }
+ return rcode;
+ }
+ return cmd_usage(cmdtp);
+ case 3:
+ if (strncmp(argv[1],"dev",3) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ printf ("\nIDE device %d: ", dev);
+ if (dev >= CONFIG_SYS_IDE_MAXDEVICE) {
+ puts ("unknown device\n");
+ return 1;
+ }
+ dev_print(&ide_dev_desc[dev]);
+ /*ide_print (dev);*/
+
+ if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+ return 1;
+ }
+
+ curr_device = dev;
+
+ puts ("... is now current device\n");
+
+ return 0;
+ } else if (strncmp(argv[1],"part",4) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+ print_part(&ide_dev_desc[dev]);
+ } else {
+ printf ("\nIDE device %d not available\n", dev);
+ rcode = 1;
+ }
+ return rcode;
+#if 0
+ } else if (strncmp(argv[1],"pio",4) == 0) {
+ int mode = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
+ puts ("\nSetting ");
+ pio_mode = mode;
+ ide_init ();
+ } else {
+ printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
+ mode, IDE_MAX_PIO_MODE);
+ }
+ return;
+#endif
+ }
+
+ return cmd_usage(cmdtp);
+ default:
+ /* at least 4 args */
+
+ if (strcmp(argv[1],"read") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+#ifdef CONFIG_SYS_64BIT_LBA
+ lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
+
+ printf ("\nIDE read: device %d block # %Ld, count %ld ... ",
+ curr_device, blk, cnt);
+#else
+ lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
+
+ printf ("\nIDE read: device %d block # %ld, count %ld ... ",
+ curr_device, blk, cnt);
+#endif
+
+ n = ide_dev_desc[curr_device].block_read (curr_device,
+ blk, cnt,
+ (ulong *)addr);
+ /* flush cache after read */
+ flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz);
+
+ printf ("%ld blocks read: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ if (n==cnt) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (strcmp(argv[1],"write") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+#ifdef CONFIG_SYS_64BIT_LBA
+ lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
+
+ printf ("\nIDE write: device %d block # %Ld, count %ld ... ",
+ curr_device, blk, cnt);
+#else
+ lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
+
+ printf ("\nIDE write: device %d block # %ld, count %ld ... ",
+ curr_device, blk, cnt);
+#endif
+
+ n = ide_write (curr_device, blk, cnt, (ulong *)addr);
+
+ printf ("%ld blocks written: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ if (n==cnt)
+ return 0;
+ else
+ return 1;
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ return rcode;
+ }
+}
+
+int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev, part = 0;
+ ulong addr, cnt;
+ disk_partition_t info;
+ image_header_t *hdr;
+ int rcode = 0;
+#if defined(CONFIG_FIT)
+ const void *fit_hdr = NULL;
+#endif
+
+ show_boot_progress (41);
+ switch (argc) {
+ case 1:
+ addr = CONFIG_SYS_LOAD_ADDR;
+ boot_device = getenv ("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv ("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ default:
+ show_boot_progress (-42);
+ return cmd_usage(cmdtp);
+ }
+ show_boot_progress (42);
+
+ if (!boot_device) {
+ puts ("\n** No boot device **\n");
+ show_boot_progress (-43);
+ return 1;
+ }
+ show_boot_progress (43);
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+
+ if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) {
+ printf ("\n** Device %d not available\n", dev);
+ show_boot_progress (-44);
+ return 1;
+ }
+ show_boot_progress (44);
+
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ show_boot_progress (-45);
+ return 1;
+ }
+ part = simple_strtoul(++ep, NULL, 16);
+ }
+ show_boot_progress (45);
+ if (get_partition_info (&ide_dev_desc[dev], part, &info)) {
+ show_boot_progress (-46);
+ return 1;
+ }
+ show_boot_progress (46);
+ if ((strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) &&
+ (strncmp((char *)info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) {
+ printf ("\n** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ show_boot_progress (-47);
+ return 1;
+ }
+ show_boot_progress (47);
+
+ printf ("\nLoading from IDE device %d, partition %d: "
+ "Name: %.32s Type: %.32s\n",
+ dev, part, info.name, info.type);
+
+ debug ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
+ info.start, info.size, info.blksz);
+
+ if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ show_boot_progress (-48);
+ return 1;
+ }
+ show_boot_progress (48);
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+
+ show_boot_progress (49);
+
+ if (!image_check_hcrc (hdr)) {
+ puts ("\n** Bad Header Checksum **\n");
+ show_boot_progress (-50);
+ return 1;
+ }
+ show_boot_progress (50);
+
+ image_print_contents (hdr);
+
+ cnt = image_get_image_size (hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (const void *)addr;
+ puts ("Fit image detected...\n");
+
+ cnt = fit_get_size (fit_hdr);
+ break;
+#endif
+ default:
+ show_boot_progress (-49);
+ puts ("** Unknown image type\n");
+ return 1;
+ }
+
+ cnt += info.blksz - 1;
+ cnt /= info.blksz;
+ cnt -= 1;
+
+ if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt,
+ (ulong *)(addr+info.blksz)) != cnt) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ show_boot_progress (-51);
+ return 1;
+ }
+ show_boot_progress (51);
+
+#if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+ if (!fit_check_format (fit_hdr)) {
+ show_boot_progress (-140);
+ puts ("** Bad FIT image format\n");
+ return 1;
+ }
+ show_boot_progress (141);
+ fit_print_contents (fit_hdr);
+ }
+#endif
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+ char *local_args[2];
+
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+
+ printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+
+ do_bootm (cmdtp, 0, 1, local_args);
+ rcode = 1;
+ }
+ return rcode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void inline
+__ide_outb(int dev, int port, unsigned char val)
+{
+ debug ("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n",
+ dev, port, val, (ATA_CURR_BASE(dev)+CONFIG_SYS_ATA_PORT_ADDR(port)));
+ outb(val, (ATA_CURR_BASE(dev)+CONFIG_SYS_ATA_PORT_ADDR(port)));
+}
+void ide_outb (int dev, int port, unsigned char val)
+ __attribute__((weak, alias("__ide_outb")));
+
+unsigned char inline
+__ide_inb(int dev, int port)
+{
+ uchar val;
+ val = inb((ATA_CURR_BASE(dev)+CONFIG_SYS_ATA_PORT_ADDR(port)));
+ debug ("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n",
+ dev, port, (ATA_CURR_BASE(dev)+CONFIG_SYS_ATA_PORT_ADDR(port)), val);
+ return val;
+}
+unsigned char ide_inb(int dev, int port)
+ __attribute__((weak, alias("__ide_inb")));
+
+#ifdef CONFIG_TUNE_PIO
+int inline
+__ide_set_piomode(int pio_mode)
+{
+ return 0;
+}
+int inline ide_set_piomode(int pio_mode)
+ __attribute__((weak, alias("__ide_set_piomode")));
+#endif
+
+void ide_init (void)
+{
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+#endif
+ unsigned char c;
+ int i, bus;
+#if defined(CONFIG_SC3)
+ unsigned int ata_reset_time = ATA_RESET_TIME;
+#endif
+#ifdef CONFIG_IDE_8xx_PCCARD
+ extern int pcmcia_on (void);
+ extern int ide_devices_found; /* Initialized in check_ide_device() */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+#ifdef CONFIG_IDE_PREINIT
+ extern int ide_preinit (void);
+ WATCHDOG_RESET();
+
+ if (ide_preinit ()) {
+ puts ("ide_preinit failed\n");
+ return;
+ }
+#endif /* CONFIG_IDE_PREINIT */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+ extern int pcmcia_on (void);
+ extern int ide_devices_found; /* Initialized in check_ide_device() */
+
+ WATCHDOG_RESET();
+
+ ide_devices_found = 0;
+ /* initialize the PCMCIA IDE adapter card */
+ pcmcia_on();
+ if (!ide_devices_found)
+ return;
+ udelay (1000000); /* 1 s */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+ WATCHDOG_RESET();
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+ /* Initialize PIO timing tables */
+ for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
+ pio_config_clk[i].t_setup = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
+ gd->bus_clk);
+ pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
+ gd->bus_clk);
+ pio_config_clk[i].t_hold = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
+ gd->bus_clk);
+ debug ( "PIO Mode %d: setup=%2d ns/%d clk"
+ " len=%3d ns/%d clk"
+ " hold=%2d ns/%d clk\n",
+ i,
+ pio_config_ns[i].t_setup, pio_config_clk[i].t_setup,
+ pio_config_ns[i].t_length, pio_config_clk[i].t_length,
+ pio_config_ns[i].t_hold, pio_config_clk[i].t_hold);
+ }
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+ /* Reset the IDE just to be sure.
+ * Light LED's to show
+ */
+ ide_led ((LED_IDE1 | LED_IDE2), 1); /* LED's on */
+ ide_reset (); /* ATAPI Drives seems to need a proper IDE Reset */
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+ /* PCMCIA / IDE initialization for common mem space */
+ pcmp->pcmc_pgcrb = 0;
+
+ /* start in PIO mode 0 - most relaxed timings */
+ pio_mode = 0;
+ set_pcmcia_timing (pio_mode);
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+ /*
+ * Wait for IDE to get ready.
+ * According to spec, this can take up to 31 seconds!
+ */
+ for (bus=0; bus<CONFIG_SYS_IDE_MAXBUS; ++bus) {
+ int dev = bus * (CONFIG_SYS_IDE_MAXDEVICE / CONFIG_SYS_IDE_MAXBUS);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+ /* Skip non-ide devices from probing */
+ if ((ide_devices_found & (1 << bus)) == 0) {
+ ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+ continue;
+ }
+#endif
+ printf ("Bus %d: ", bus);
+
+ ide_bus_ok[bus] = 0;
+
+ /* Select device
+ */
+ udelay (100000); /* 100 ms */
+ ide_outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
+ udelay (100000); /* 100 ms */
+ i = 0;
+ do {
+ udelay (10000); /* 10 ms */
+
+ c = ide_inb (dev, ATA_STATUS);
+ i++;
+#if defined(CONFIG_SC3)
+ if (i > (ata_reset_time * 100)) {
+#else
+ if (i > (ATA_RESET_TIME * 100)) {
+#endif
+ puts ("** Timeout **\n");
+ ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+ return;
+ }
+ if ((i >= 100) && ((i%100)==0)) {
+ putc ('.');
+ }
+ } while (c & ATA_STAT_BUSY);
+
+ if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
+ puts ("not available ");
+ debug ("Status = 0x%02X ", c);
+#ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */
+ } else if ((c & ATA_STAT_READY) == 0) {
+ puts ("not available ");
+ debug ("Status = 0x%02X ", c);
+#endif
+ } else {
+ puts ("OK ");
+ ide_bus_ok[bus] = 1;
+ }
+ WATCHDOG_RESET();
+ }
+
+ putc ('\n');
+
+ ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+
+ curr_device = -1;
+ for (i=0; i<CONFIG_SYS_IDE_MAXDEVICE; ++i) {
+#ifdef CONFIG_IDE_LED
+ int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
+#endif
+ ide_dev_desc[i].type=DEV_TYPE_UNKNOWN;
+ ide_dev_desc[i].if_type=IF_TYPE_IDE;
+ ide_dev_desc[i].dev=i;
+ ide_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+ ide_dev_desc[i].blksz=0;
+ ide_dev_desc[i].lba=0;
+ ide_dev_desc[i].block_read=ide_read;
+ if (!ide_bus_ok[IDE_BUS(i)])
+ continue;
+ ide_led (led, 1); /* LED on */
+ ide_ident(&ide_dev_desc[i]);
+ ide_led (led, 0); /* LED off */
+ dev_print(&ide_dev_desc[i]);
+/* ide_print (i); */
+ if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
+ init_part (&ide_dev_desc[i]); /* initialize partition type */
+ if (curr_device < 0)
+ curr_device = i;
+ }
+ }
+ WATCHDOG_RESET();
+}
+
+/* ------------------------------------------------------------------------- */
+
+block_dev_desc_t * ide_get_dev(int dev)
+{
+ return (dev < CONFIG_SYS_IDE_MAXDEVICE) ? &ide_dev_desc[dev] : NULL;
+}
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+
+static void
+set_pcmcia_timing (int pmode)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+ ulong timings;
+
+ debug ("Set timing for PIO Mode %d\n", pmode);
+
+ timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold)
+ | PCMCIA_SST(pio_config_clk[pmode].t_setup)
+ | PCMCIA_SL (pio_config_clk[pmode].t_length)
+ ;
+
+ /* IDE 0
+ */
+ pcmp->pcmc_pbr0 = CONFIG_SYS_PCMCIA_PBR0;
+ pcmp->pcmc_por0 = CONFIG_SYS_PCMCIA_POR0
+#if (CONFIG_SYS_PCMCIA_POR0 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR0: %08x POR0: %08x\n", pcmp->pcmc_pbr0, pcmp->pcmc_por0);
+
+ pcmp->pcmc_pbr1 = CONFIG_SYS_PCMCIA_PBR1;
+ pcmp->pcmc_por1 = CONFIG_SYS_PCMCIA_POR1
+#if (CONFIG_SYS_PCMCIA_POR1 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR1: %08x POR1: %08x\n", pcmp->pcmc_pbr1, pcmp->pcmc_por1);
+
+ pcmp->pcmc_pbr2 = CONFIG_SYS_PCMCIA_PBR2;
+ pcmp->pcmc_por2 = CONFIG_SYS_PCMCIA_POR2
+#if (CONFIG_SYS_PCMCIA_POR2 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR2: %08x POR2: %08x\n", pcmp->pcmc_pbr2, pcmp->pcmc_por2);
+
+ pcmp->pcmc_pbr3 = CONFIG_SYS_PCMCIA_PBR3;
+ pcmp->pcmc_por3 = CONFIG_SYS_PCMCIA_POR3
+#if (CONFIG_SYS_PCMCIA_POR3 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR3: %08x POR3: %08x\n", pcmp->pcmc_pbr3, pcmp->pcmc_por3);
+
+ /* IDE 1
+ */
+ pcmp->pcmc_pbr4 = CONFIG_SYS_PCMCIA_PBR4;
+ pcmp->pcmc_por4 = CONFIG_SYS_PCMCIA_POR4
+#if (CONFIG_SYS_PCMCIA_POR4 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR4: %08x POR4: %08x\n", pcmp->pcmc_pbr4, pcmp->pcmc_por4);
+
+ pcmp->pcmc_pbr5 = CONFIG_SYS_PCMCIA_PBR5;
+ pcmp->pcmc_por5 = CONFIG_SYS_PCMCIA_POR5
+#if (CONFIG_SYS_PCMCIA_POR5 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR5: %08x POR5: %08x\n", pcmp->pcmc_pbr5, pcmp->pcmc_por5);
+
+ pcmp->pcmc_pbr6 = CONFIG_SYS_PCMCIA_PBR6;
+ pcmp->pcmc_por6 = CONFIG_SYS_PCMCIA_POR6
+#if (CONFIG_SYS_PCMCIA_POR6 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR6: %08x POR6: %08x\n", pcmp->pcmc_pbr6, pcmp->pcmc_por6);
+
+ pcmp->pcmc_pbr7 = CONFIG_SYS_PCMCIA_PBR7;
+ pcmp->pcmc_por7 = CONFIG_SYS_PCMCIA_POR7
+#if (CONFIG_SYS_PCMCIA_POR7 != 0)
+ | timings
+#endif
+ ;
+ debug ("PBR7: %08x POR7: %08x\n", pcmp->pcmc_pbr7, pcmp->pcmc_por7);
+
+}
+
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+/* ------------------------------------------------------------------------- */
+
+/* We only need to swap data if we are running on a big endian cpu. */
+/* But Au1x00 cpu:s already swaps data in big endian mode! */
+#if defined(__LITTLE_ENDIAN) || \
+ (defined(CONFIG_SOC_AU1X00) && !defined(CONFIG_GTH2))
+#define input_swap_data(x,y,z) input_data(x,y,z)
+#else
+static void
+input_swap_data(int dev, ulong *sect_buf, int words)
+{
+#if defined(CONFIG_CPC45)
+ uchar i;
+ volatile uchar *pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
+ volatile uchar *pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
+ ushort *dbuf = (ushort *)sect_buf;
+
+ while (words--) {
+ for (i=0; i<2; i++) {
+ *(((uchar *)(dbuf)) + 1) = *pbuf_even;
+ *(uchar *)dbuf = *pbuf_odd;
+ dbuf+=1;
+ }
+ }
+#else
+ volatile ushort *pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ ushort *dbuf = (ushort *)sect_buf;
+
+ debug("in input swap data base for read is %lx\n", (unsigned long) pbuf);
+
+ while (words--) {
+#ifdef __MIPS__
+ *dbuf++ = swab16p((u16*)pbuf);
+ *dbuf++ = swab16p((u16*)pbuf);
+#elif defined(CONFIG_PCS440EP)
+ *dbuf++ = *pbuf;
+ *dbuf++ = *pbuf;
+#else
+ *dbuf++ = ld_le16(pbuf);
+ *dbuf++ = ld_le16(pbuf);
+#endif /* !MIPS */
+ }
+#endif
+}
+#endif /* __LITTLE_ENDIAN || CONFIG_AU1X00 */
+
+
+#if defined(CONFIG_IDE_SWAP_IO)
+static void
+output_data(int dev, ulong *sect_buf, int words)
+{
+#if defined(CONFIG_CPC45)
+ uchar *dbuf;
+ volatile uchar *pbuf_even;
+ volatile uchar *pbuf_odd;
+
+ pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
+ pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
+ dbuf = (uchar *)sect_buf;
+ while (words--) {
+ EIEIO;
+ *pbuf_even = *dbuf++;
+ EIEIO;
+ *pbuf_odd = *dbuf++;
+ EIEIO;
+ *pbuf_even = *dbuf++;
+ EIEIO;
+ *pbuf_odd = *dbuf++;
+ }
+#else
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+ while (words--) {
+#if defined(CONFIG_PCS440EP)
+ /* not tested, because CF was write protected */
+ EIEIO;
+ *pbuf = ld_le16(dbuf++);
+ EIEIO;
+ *pbuf = ld_le16(dbuf++);
+#else
+ EIEIO;
+ *pbuf = *dbuf++;
+ EIEIO;
+ *pbuf = *dbuf++;
+#endif
+ }
+#endif
+}
+#else /* ! CONFIG_IDE_SWAP_IO */
+static void
+output_data(int dev, ulong *sect_buf, int words)
+{
+ outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, words<<1);
+}
+#endif /* CONFIG_IDE_SWAP_IO */
+
+#if defined(CONFIG_IDE_SWAP_IO)
+static void
+input_data(int dev, ulong *sect_buf, int words)
+{
+#if defined(CONFIG_CPC45)
+ uchar *dbuf;
+ volatile uchar *pbuf_even;
+ volatile uchar *pbuf_odd;
+
+ pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
+ pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
+ dbuf = (uchar *)sect_buf;
+ while (words--) {
+ *dbuf++ = *pbuf_even;
+ EIEIO;
+ SYNC;
+ *dbuf++ = *pbuf_odd;
+ EIEIO;
+ SYNC;
+ *dbuf++ = *pbuf_even;
+ EIEIO;
+ SYNC;
+ *dbuf++ = *pbuf_odd;
+ EIEIO;
+ SYNC;
+ }
+#else
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+
+ debug("in input data base for read is %lx\n", (unsigned long) pbuf);
+
+ while (words--) {
+#if defined(CONFIG_PCS440EP)
+ EIEIO;
+ *dbuf++ = ld_le16(pbuf);
+ EIEIO;
+ *dbuf++ = ld_le16(pbuf);
+#else
+ EIEIO;
+ *dbuf++ = *pbuf;
+ EIEIO;
+ *dbuf++ = *pbuf;
+#endif
+ }
+#endif
+}
+#else /* ! CONFIG_IDE_SWAP_IO */
+static void
+input_data(int dev, ulong *sect_buf, int words)
+{
+ insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, words << 1);
+}
+
+#endif /* CONFIG_IDE_SWAP_IO */
+
+/* -------------------------------------------------------------------------
+ */
+static void ide_ident (block_dev_desc_t *dev_desc)
+{
+ ulong iobuf[ATA_SECTORWORDS];
+ unsigned char c;
+ hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+#ifdef CONFIG_ATAPI
+ int retries = 0;
+ int do_retry = 0;
+#endif
+
+#ifdef CONFIG_TUNE_PIO
+ int pio_mode;
+#endif
+
+#if 0
+ int mode, cycle_time;
+#endif
+ int device;
+ device=dev_desc->dev;
+ printf (" Device %d: ", device);
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+ /* Select device
+ */
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ dev_desc->if_type=IF_TYPE_IDE;
+#ifdef CONFIG_ATAPI
+
+ do_retry = 0;
+ retries = 0;
+
+ /* Warning: This will be tricky to read */
+ while (retries <= 1) {
+ /* check signature */
+ if ((ide_inb(device,ATA_SECT_CNT) == 0x01) &&
+ (ide_inb(device,ATA_SECT_NUM) == 0x01) &&
+ (ide_inb(device,ATA_CYL_LOW) == 0x14) &&
+ (ide_inb(device,ATA_CYL_HIGH) == 0xEB)) {
+ /* ATAPI Signature found */
+ dev_desc->if_type=IF_TYPE_ATAPI;
+ /* Start Ident Command
+ */
+ ide_outb (device, ATA_COMMAND, ATAPI_CMD_IDENT);
+ /*
+ * Wait for completion - ATAPI devices need more time
+ * to become ready
+ */
+ c = ide_wait (device, ATAPI_TIME_OUT);
+ } else
+#endif
+ {
+ /* Start Ident Command
+ */
+ ide_outb (device, ATA_COMMAND, ATA_CMD_IDENT);
+
+ /* Wait for completion
+ */
+ c = ide_wait (device, IDE_TIME_OUT);
+ }
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+
+ if (((c & ATA_STAT_DRQ) == 0) ||
+ ((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
+#ifdef CONFIG_ATAPI
+ {
+ /* Need to soft reset the device in case it's an ATAPI... */
+ debug ("Retrying...\n");
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ udelay(100000);
+ ide_outb (device, ATA_COMMAND, 0x08);
+ udelay (500000); /* 500 ms */
+ }
+ /* Select device
+ */
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ retries++;
+#else
+ return;
+#endif
+ }
+#ifdef CONFIG_ATAPI
+ else
+ break;
+ } /* see above - ugly to read */
+
+ if (retries == 2) /* Not found */
+ return;
+#endif
+
+ input_swap_data (device, iobuf, ATA_SECTORWORDS);
+
+ ident_cpy ((unsigned char*)dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
+ ident_cpy ((unsigned char*)dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
+ ident_cpy ((unsigned char*)dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
+#ifdef __LITTLE_ENDIAN
+ /*
+ * firmware revision, model, and serial number have Big Endian Byte
+ * order in Word. Convert all three to little endian.
+ *
+ * See CF+ and CompactFlash Specification Revision 2.0:
+ * 6.2.1.6: Identify Drive, Table 39 for more details
+ */
+
+ strswab (dev_desc->revision);
+ strswab (dev_desc->vendor);
+ strswab (dev_desc->product);
+#endif /* __LITTLE_ENDIAN */
+
+ if ((iop->config & 0x0080)==0x0080)
+ dev_desc->removable = 1;
+ else
+ dev_desc->removable = 0;
+
+#ifdef CONFIG_TUNE_PIO
+ /* Mode 0 - 2 only, are directly determined by word 51. */
+ pio_mode = iop->tPIO;
+ if (pio_mode > 2) {
+ printf("WARNING: Invalid PIO (word 51 = %d).\n", pio_mode);
+ pio_mode = 0; /* Force it to dead slow, and hope for the best... */
+ }
+
+ /* Any CompactFlash Storage Card that supports PIO mode 3 or above
+ * shall set bit 1 of word 53 to one and support the fields contained
+ * in words 64 through 70.
+ */
+ if (iop->field_valid & 0x02) {
+ /* Mode 3 and above are possible. Check in order from slow
+ * to fast, so we wind up with the highest mode allowed.
+ */
+ if (iop->eide_pio_modes & 0x01)
+ pio_mode = 3;
+ if (iop->eide_pio_modes & 0x02)
+ pio_mode = 4;
+ if (ata_id_is_cfa((u16 *)iop)) {
+ if ((iop->cf_advanced_caps & 0x07) == 0x01)
+ pio_mode = 5;
+ if ((iop->cf_advanced_caps & 0x07) == 0x02)
+ pio_mode = 6;
+ }
+ }
+
+ /* System-specific, depends on bus speeds, etc. */
+ ide_set_piomode(pio_mode);
+#endif /* CONFIG_TUNE_PIO */
+
+#if 0
+ /*
+ * Drive PIO mode autoselection
+ */
+ mode = iop->tPIO;
+
+ printf ("tPIO = 0x%02x = %d\n",mode, mode);
+ if (mode > 2) { /* 2 is maximum allowed tPIO value */
+ mode = 2;
+ debug ("Override tPIO -> 2\n");
+ }
+ if (iop->field_valid & 2) { /* drive implements ATA2? */
+ debug ("Drive implements ATA2\n");
+ if (iop->capability & 8) { /* drive supports use_iordy? */
+ cycle_time = iop->eide_pio_iordy;
+ } else {
+ cycle_time = iop->eide_pio;
+ }
+ debug ("cycle time = %d\n", cycle_time);
+ mode = 4;
+ if (cycle_time > 120) mode = 3; /* 120 ns for PIO mode 4 */
+ if (cycle_time > 180) mode = 2; /* 180 ns for PIO mode 3 */
+ if (cycle_time > 240) mode = 1; /* 240 ns for PIO mode 4 */
+ if (cycle_time > 383) mode = 0; /* 383 ns for PIO mode 4 */
+ }
+ printf ("PIO mode to use: PIO %d\n", mode);
+#endif /* 0 */
+
+#ifdef CONFIG_ATAPI
+ if (dev_desc->if_type==IF_TYPE_ATAPI) {
+ atapi_inquiry(dev_desc);
+ return;
+ }
+#endif /* CONFIG_ATAPI */
+
+#ifdef __BIG_ENDIAN
+ /* swap shorts */
+ dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
+#else /* ! __BIG_ENDIAN */
+ /*
+ * do not swap shorts on little endian
+ *
+ * See CF+ and CompactFlash Specification Revision 2.0:
+ * 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details.
+ */
+ dev_desc->lba = iop->lba_capacity;
+#endif /* __BIG_ENDIAN */
+
+#ifdef CONFIG_LBA48
+ if (iop->command_set_2 & 0x0400) { /* LBA 48 support */
+ dev_desc->lba48 = 1;
+ dev_desc->lba = (unsigned long long)iop->lba48_capacity[0] |
+ ((unsigned long long)iop->lba48_capacity[1] << 16) |
+ ((unsigned long long)iop->lba48_capacity[2] << 32) |
+ ((unsigned long long)iop->lba48_capacity[3] << 48);
+ } else {
+ dev_desc->lba48 = 0;
+ }
+#endif /* CONFIG_LBA48 */
+ /* assuming HD */
+ dev_desc->type=DEV_TYPE_HARDDISK;
+ dev_desc->blksz=ATA_BLOCKSIZE;
+ dev_desc->lun=0; /* just to fill something in... */
+
+#if 0 /* only used to test the powersaving mode,
+ * if enabled, the drive goes after 5 sec
+ * in standby mode */
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = ide_wait (device, IDE_TIME_OUT);
+ ide_outb (device, ATA_SECT_CNT, 1);
+ ide_outb (device, ATA_LBA_LOW, 0);
+ ide_outb (device, ATA_LBA_MID, 0);
+ ide_outb (device, ATA_LBA_HIGH, 0);
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ ide_outb (device, ATA_COMMAND, 0xe3);
+ udelay (50);
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
+{
+ ulong n = 0;
+ unsigned char c;
+ unsigned char pwrsave=0; /* power save */
+#ifdef CONFIG_LBA48
+ unsigned char lba48 = 0;
+
+ if (blknr & 0x0000fffff0000000ULL) {
+ /* more than 28 bits used, use 48bit mode */
+ lba48 = 1;
+ }
+#endif
+ debug ("ide_read dev %d start %LX, blocks %lX buffer at %lX\n",
+ device, blknr, blkcnt, (ulong)buffer);
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto IDE_READ_E;
+ }
+
+ /* first check if the drive is in Powersaving mode, if yes,
+ * increase the timeout value */
+ ide_outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR);
+ udelay (50);
+
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto IDE_READ_E;
+ }
+ if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+ printf ("No Powersaving mode %X\n", c);
+ } else {
+ c = ide_inb(device,ATA_SECT_CNT);
+ debug ("Powersaving %02X\n",c);
+ if(c==0)
+ pwrsave=1;
+ }
+
+
+ while (blkcnt-- > 0) {
+
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ break;
+ }
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ /* write high bits */
+ ide_outb (device, ATA_SECT_CNT, 0);
+ ide_outb (device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
+#ifdef CONFIG_SYS_64BIT_LBA
+ ide_outb (device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
+ ide_outb (device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
+#else
+ ide_outb (device, ATA_LBA_MID, 0);
+ ide_outb (device, ATA_LBA_HIGH, 0);
+#endif
+ }
+#endif
+ ide_outb (device, ATA_SECT_CNT, 1);
+ ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+ ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+ ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) );
+ ide_outb (device, ATA_COMMAND, ATA_CMD_READ_EXT);
+
+ } else
+#endif
+ {
+ ide_outb (device, ATA_DEV_HD, ATA_LBA |
+ ATA_DEVICE(device) |
+ ((blknr >> 24) & 0xF) );
+ ide_outb (device, ATA_COMMAND, ATA_CMD_READ);
+ }
+
+ udelay (50);
+
+ if(pwrsave) {
+ c = ide_wait (device, IDE_SPIN_UP_TIME_OUT); /* may take up to 4 sec */
+ pwrsave=0;
+ } else {
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+ }
+
+ if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+#if defined(CONFIG_SYS_64BIT_LBA)
+ printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
+ device, blknr, c);
+#else
+ printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+ device, (ulong)blknr, c);
+#endif
+ break;
+ }
+
+ input_data (device, buffer, ATA_SECTORWORDS);
+ (void) ide_inb (device, ATA_STATUS); /* clear IRQ */
+
+ ++n;
+ ++blknr;
+ buffer += ATA_BLOCKSIZE;
+ }
+IDE_READ_E:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+ulong ide_write (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
+{
+ ulong n = 0;
+ unsigned char c;
+#ifdef CONFIG_LBA48
+ unsigned char lba48 = 0;
+
+ if (blknr & 0x0000fffff0000000ULL) {
+ /* more than 28 bits used, use 48bit mode */
+ lba48 = 1;
+ }
+#endif
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+ while (blkcnt-- > 0) {
+
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto WR_OUT;
+ }
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ /* write high bits */
+ ide_outb (device, ATA_SECT_CNT, 0);
+ ide_outb (device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
+#ifdef CONFIG_SYS_64BIT_LBA
+ ide_outb (device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
+ ide_outb (device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
+#else
+ ide_outb (device, ATA_LBA_MID, 0);
+ ide_outb (device, ATA_LBA_HIGH, 0);
+#endif
+ }
+#endif
+ ide_outb (device, ATA_SECT_CNT, 1);
+ ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+ ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+ ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) );
+ ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE_EXT);
+
+ } else
+#endif
+ {
+ ide_outb (device, ATA_DEV_HD, ATA_LBA |
+ ATA_DEVICE(device) |
+ ((blknr >> 24) & 0xF) );
+ ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE);
+ }
+
+ udelay (50);
+
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+
+ if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+#if defined(CONFIG_SYS_64BIT_LBA)
+ printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
+ device, blknr, c);
+#else
+ printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+ device, (ulong)blknr, c);
+#endif
+ goto WR_OUT;
+ }
+
+ output_data (device, buffer, ATA_SECTORWORDS);
+ c = ide_inb (device, ATA_STATUS); /* clear IRQ */
+ ++n;
+ ++blknr;
+ buffer += ATA_BLOCKSIZE;
+ }
+WR_OUT:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * copy src to dest, skipping leading and trailing blanks and null
+ * terminate the string
+ * "len" is the size of available memory including the terminating '\0'
+ */
+static void ident_cpy (unsigned char *dst, unsigned char *src, unsigned int len)
+{
+ unsigned char *end, *last;
+
+ last = dst;
+ end = src + len - 1;
+
+ /* reserve space for '\0' */
+ if (len < 2)
+ goto OUT;
+
+ /* skip leading white space */
+ while ((*src) && (src<end) && (*src==' '))
+ ++src;
+
+ /* copy string, omitting trailing white space */
+ while ((*src) && (src<end)) {
+ *dst++ = *src;
+ if (*src++ != ' ')
+ last = dst;
+ }
+OUT:
+ *last = '\0';
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Wait until Busy bit is off, or timeout (in ms)
+ * Return last status
+ */
+static uchar ide_wait (int dev, ulong t)
+{
+ ulong delay = 10 * t; /* poll every 100 us */
+ uchar c;
+
+ while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
+ udelay (100);
+ if (delay-- == 0) {
+ break;
+ }
+ }
+ return (c);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_RESET
+extern void ide_set_reset(int idereset);
+
+static void ide_reset (void)
+{
+#if defined(CONFIG_SYS_PB_12V_ENABLE) || defined(CONFIG_SYS_PB_IDE_MOTOR)
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+#endif
+ int i;
+
+ curr_device = -1;
+ for (i=0; i<CONFIG_SYS_IDE_MAXBUS; ++i)
+ ide_bus_ok[i] = 0;
+ for (i=0; i<CONFIG_SYS_IDE_MAXDEVICE; ++i)
+ ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+
+ ide_set_reset (1); /* assert reset */
+
+ /* the reset signal shall be asserted for et least 25 us */
+ udelay(25);
+
+ WATCHDOG_RESET();
+
+#ifdef CONFIG_SYS_PB_12V_ENABLE
+ immr->im_cpm.cp_pbdat &= ~(CONFIG_SYS_PB_12V_ENABLE); /* 12V Enable output OFF */
+ immr->im_cpm.cp_pbpar &= ~(CONFIG_SYS_PB_12V_ENABLE);
+ immr->im_cpm.cp_pbodr &= ~(CONFIG_SYS_PB_12V_ENABLE);
+ immr->im_cpm.cp_pbdir |= CONFIG_SYS_PB_12V_ENABLE;
+
+ /* wait 500 ms for the voltage to stabilize
+ */
+ for (i=0; i<500; ++i) {
+ udelay (1000);
+ }
+
+ immr->im_cpm.cp_pbdat |= CONFIG_SYS_PB_12V_ENABLE; /* 12V Enable output ON */
+#endif /* CONFIG_SYS_PB_12V_ENABLE */
+
+#ifdef CONFIG_SYS_PB_IDE_MOTOR
+ /* configure IDE Motor voltage monitor pin as input */
+ immr->im_cpm.cp_pbpar &= ~(CONFIG_SYS_PB_IDE_MOTOR);
+ immr->im_cpm.cp_pbodr &= ~(CONFIG_SYS_PB_IDE_MOTOR);
+ immr->im_cpm.cp_pbdir &= ~(CONFIG_SYS_PB_IDE_MOTOR);
+
+ /* wait up to 1 s for the motor voltage to stabilize
+ */
+ for (i=0; i<1000; ++i) {
+ if ((immr->im_cpm.cp_pbdat & CONFIG_SYS_PB_IDE_MOTOR) != 0) {
+ break;
+ }
+ udelay (1000);
+ }
+
+ if (i == 1000) { /* Timeout */
+ printf ("\nWarning: 5V for IDE Motor missing\n");
+# ifdef CONFIG_STATUS_LED
+# ifdef STATUS_LED_YELLOW
+ status_led_set (STATUS_LED_YELLOW, STATUS_LED_ON );
+# endif
+# ifdef STATUS_LED_GREEN
+ status_led_set (STATUS_LED_GREEN, STATUS_LED_OFF);
+# endif
+# endif /* CONFIG_STATUS_LED */
+ }
+#endif /* CONFIG_SYS_PB_IDE_MOTOR */
+
+ WATCHDOG_RESET();
+
+ /* de-assert RESET signal */
+ ide_set_reset(0);
+
+ /* wait 250 ms */
+ for (i=0; i<250; ++i) {
+ udelay (1000);
+ }
+}
+
+#endif /* CONFIG_IDE_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_IDE_LED) && \
+ !defined(CONFIG_CPC45) && \
+ !defined(CONFIG_KUP4K) && \
+ !defined(CONFIG_KUP4X)
+
+static uchar led_buffer = 0; /* Buffer for current LED status */
+
+static void ide_led (uchar led, uchar status)
+{
+ uchar *led_port = LED_PORT;
+
+ if (status) { /* switch LED on */
+ led_buffer |= led;
+ } else { /* switch LED off */
+ led_buffer &= ~led;
+ }
+
+ *led_port = led_buffer;
+}
+
+#endif /* CONFIG_IDE_LED */
+
+#if defined(CONFIG_OF_IDE_FIXUP)
+int ide_device_present(int dev)
+{
+ if (dev >= CONFIG_SYS_IDE_MAXBUS)
+ return 0;
+ return (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1);
+}
+#endif
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATAPI
+/****************************************************************************
+ * ATAPI Support
+ */
+
+#if defined(CONFIG_IDE_SWAP_IO)
+/* since ATAPI may use commands with not 4 bytes alligned length
+ * we have our own transfer functions, 2 bytes alligned */
+static void
+output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+#if defined(CONFIG_CPC45)
+ uchar *dbuf;
+ volatile uchar *pbuf_even;
+ volatile uchar *pbuf_odd;
+
+ pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
+ pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
+ while (shorts--) {
+ EIEIO;
+ *pbuf_even = *dbuf++;
+ EIEIO;
+ *pbuf_odd = *dbuf++;
+ }
+#else
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+
+ debug ("in output data shorts base for read is %lx\n", (unsigned long) pbuf);
+
+ while (shorts--) {
+ EIEIO;
+ *pbuf = *dbuf++;
+ }
+#endif
+}
+
+static void
+input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+#if defined(CONFIG_CPC45)
+ uchar *dbuf;
+ volatile uchar *pbuf_even;
+ volatile uchar *pbuf_odd;
+
+ pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
+ pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
+ while (shorts--) {
+ EIEIO;
+ *dbuf++ = *pbuf_even;
+ EIEIO;
+ *dbuf++ = *pbuf_odd;
+ }
+#else
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+
+ debug("in input data shorts base for read is %lx\n", (unsigned long) pbuf);
+
+ while (shorts--) {
+ EIEIO;
+ *dbuf++ = *pbuf;
+ }
+#endif
+}
+
+#else /* ! CONFIG_IDE_SWAP_IO */
+static void
+output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+ outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);
+}
+
+static void
+input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+ insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);
+}
+
+#endif /* CONFIG_IDE_SWAP_IO */
+
+/*
+ * Wait until (Status & mask) == res, or timeout (in ms)
+ * Return last status
+ * This is used since some ATAPI CD ROMs clears their Busy Bit first
+ * and then they set their DRQ Bit
+ */
+static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res)
+{
+ ulong delay = 10 * t; /* poll every 100 us */
+ uchar c;
+
+ c = ide_inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */
+ while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) {
+ /* break if error occurs (doesn't make sense to wait more) */
+ if((c & ATA_STAT_ERR)==ATA_STAT_ERR)
+ break;
+ udelay (100);
+ if (delay-- == 0) {
+ break;
+ }
+ }
+ return (c);
+}
+
+/*
+ * issue an atapi command
+ */
+unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen)
+{
+ unsigned char c,err,mask,res;
+ int n;
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ mask = ATA_STAT_BUSY|ATA_STAT_DRQ;
+ res = 0;
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & mask) != res) {
+ printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c);
+ err=0xFF;
+ goto AI_OUT;
+ }
+ /* write taskfile */
+ ide_outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
+ ide_outb (device, ATA_SECT_CNT, 0);
+ ide_outb (device, ATA_SECT_NUM, 0);
+ ide_outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF));
+ ide_outb (device, ATA_CYL_HIGH, (unsigned char)((buflen>>8) & 0xFF));
+ ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+ ide_outb (device, ATA_COMMAND, ATAPI_CMD_PACKET);
+ udelay (50);
+
+ mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+ res = ATA_STAT_DRQ;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+
+ if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
+ printf ("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c);
+ err=0xFF;
+ goto AI_OUT;
+ }
+
+ output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */
+ /* ATAPI Command written wait for completition */
+ udelay (5000); /* device must set bsy */
+
+ mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+ /* if no data wait for DRQ = 0 BSY = 0
+ * if data wait for DRQ = 1 BSY = 0 */
+ res=0;
+ if(buflen)
+ res = ATA_STAT_DRQ;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & mask) != res ) {
+ if (c & ATA_STAT_ERR) {
+ err=(ide_inb(device,ATA_ERROR_REG))>>4;
+ debug ("atapi_issue 1 returned sense key %X status %02X\n",err,c);
+ } else {
+ printf ("ATAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c);
+ err=0xFF;
+ }
+ goto AI_OUT;
+ }
+ n=ide_inb(device, ATA_CYL_HIGH);
+ n<<=8;
+ n+=ide_inb(device, ATA_CYL_LOW);
+ if(n>buflen) {
+ printf("ERROR, transfer bytes %d requested only %d\n",n,buflen);
+ err=0xff;
+ goto AI_OUT;
+ }
+ if((n==0)&&(buflen<0)) {
+ printf("ERROR, transfer bytes %d requested %d\n",n,buflen);
+ err=0xff;
+ goto AI_OUT;
+ }
+ if(n!=buflen) {
+ debug ("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen);
+ }
+ if(n!=0) { /* data transfer */
+ debug ("ATAPI_ISSUE: %d Bytes to transfer\n",n);
+ /* we transfer shorts */
+ n>>=1;
+ /* ok now decide if it is an in or output */
+ if ((ide_inb(device, ATA_SECT_CNT)&0x02)==0) {
+ debug ("Write to device\n");
+ output_data_shorts(device,(unsigned short *)buffer,n);
+ } else {
+ debug ("Read from device @ %p shorts %d\n",buffer,n);
+ input_data_shorts(device,(unsigned short *)buffer,n);
+ }
+ }
+ udelay(5000); /* seems that some CD ROMs need this... */
+ mask = ATA_STAT_BUSY|ATA_STAT_ERR;
+ res=0;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+ err=(ide_inb(device,ATA_ERROR_REG) >> 4);
+ debug ("atapi_issue 2 returned sense key %X status %X\n",err,c);
+ } else {
+ err = 0;
+ }
+AI_OUT:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (err);
+}
+
+/*
+ * sending the command to atapi_issue. If an status other than good
+ * returns, an request_sense will be issued
+ */
+
+#define ATAPI_DRIVE_NOT_READY 100
+#define ATAPI_UNIT_ATTN 10
+
+unsigned char atapi_issue_autoreq (int device,
+ unsigned char* ccb,
+ int ccblen,
+ unsigned char *buffer,
+ int buflen)
+{
+ unsigned char sense_data[18],sense_ccb[12];
+ unsigned char res,key,asc,ascq;
+ int notready,unitattn;
+
+ unitattn=ATAPI_UNIT_ATTN;
+ notready=ATAPI_DRIVE_NOT_READY;
+
+retry:
+ res= atapi_issue(device,ccb,ccblen,buffer,buflen);
+ if (res==0)
+ return (0); /* Ok */
+
+ if (res==0xFF)
+ return (0xFF); /* error */
+
+ debug ("(auto_req)atapi_issue returned sense key %X\n",res);
+
+ memset(sense_ccb,0,sizeof(sense_ccb));
+ memset(sense_data,0,sizeof(sense_data));
+ sense_ccb[0]=ATAPI_CMD_REQ_SENSE;
+ sense_ccb[4]=18; /* allocation Length */
+
+ res=atapi_issue(device,sense_ccb,12,sense_data,18);
+ key=(sense_data[2]&0xF);
+ asc=(sense_data[12]);
+ ascq=(sense_data[13]);
+
+ debug ("ATAPI_CMD_REQ_SENSE returned %x\n",res);
+ debug (" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
+ sense_data[0],
+ key,
+ asc,
+ ascq);
+
+ if((key==0))
+ return 0; /* ok device ready */
+
+ if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */
+ if(unitattn-->0) {
+ udelay(200*1000);
+ goto retry;
+ }
+ printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN);
+ goto error;
+ }
+ if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */
+ if (notready-->0) {
+ udelay(200*1000);
+ goto retry;
+ }
+ printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY);
+ goto error;
+ }
+ if(asc==0x3a) {
+ debug ("Media not present\n");
+ goto error;
+ }
+
+ printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+error:
+ debug ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+ return (0xFF);
+}
+
+
+static void atapi_inquiry(block_dev_desc_t * dev_desc)
+{
+ unsigned char ccb[12]; /* Command descriptor block */
+ unsigned char iobuf[64]; /* temp buf */
+ unsigned char c;
+ int device;
+
+ device=dev_desc->dev;
+ dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */
+ dev_desc->block_read=atapi_read;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+
+ ccb[0]=ATAPI_CMD_INQUIRY;
+ ccb[4]=40; /* allocation Legnth */
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40);
+
+ debug ("ATAPI_CMD_INQUIRY returned %x\n",c);
+ if (c!=0)
+ return;
+
+ /* copy device ident strings */
+ ident_cpy((unsigned char*)dev_desc->vendor,&iobuf[8],8);
+ ident_cpy((unsigned char*)dev_desc->product,&iobuf[16],16);
+ ident_cpy((unsigned char*)dev_desc->revision,&iobuf[32],5);
+
+ dev_desc->lun=0;
+ dev_desc->lba=0;
+ dev_desc->blksz=0;
+ dev_desc->type=iobuf[0] & 0x1f;
+
+ if ((iobuf[1]&0x80)==0x80)
+ dev_desc->removable = 1;
+ else
+ dev_desc->removable = 0;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ ccb[0]=ATAPI_CMD_START_STOP;
+ ccb[4]=0x03; /* start */
+
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+ debug ("ATAPI_CMD_START_STOP returned %x\n",c);
+ if (c!=0)
+ return;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+ debug ("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c);
+ if (c!=0)
+ return;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ ccb[0]=ATAPI_CMD_READ_CAP;
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8);
+ debug ("ATAPI_CMD_READ_CAP returned %x\n",c);
+ if (c!=0)
+ return;
+
+ debug ("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
+ iobuf[0],iobuf[1],iobuf[2],iobuf[3],
+ iobuf[4],iobuf[5],iobuf[6],iobuf[7]);
+
+ dev_desc->lba =((unsigned long)iobuf[0]<<24) +
+ ((unsigned long)iobuf[1]<<16) +
+ ((unsigned long)iobuf[2]<< 8) +
+ ((unsigned long)iobuf[3]);
+ dev_desc->blksz=((unsigned long)iobuf[4]<<24) +
+ ((unsigned long)iobuf[5]<<16) +
+ ((unsigned long)iobuf[6]<< 8) +
+ ((unsigned long)iobuf[7]);
+#ifdef CONFIG_LBA48
+ dev_desc->lba48 = 0; /* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */
+#endif
+ return;
+}
+
+
+/*
+ * atapi_read:
+ * we transfer only one block per command, since the multiple DRQ per
+ * command is not yet implemented
+ */
+#define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */
+#define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */
+#define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE /* max blocks */
+
+ulong atapi_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
+{
+ ulong n = 0;
+ unsigned char ccb[12]; /* Command descriptor block */
+ ulong cnt;
+
+ debug ("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n",
+ device, blknr, blkcnt, (ulong)buffer);
+
+ do {
+ if (blkcnt>ATAPI_READ_MAX_BLOCK) {
+ cnt=ATAPI_READ_MAX_BLOCK;
+ } else {
+ cnt=blkcnt;
+ }
+ ccb[0]=ATAPI_CMD_READ_12;
+ ccb[1]=0; /* reserved */
+ ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */
+ ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /* */
+ ccb[4]=(unsigned char) (blknr>> 8) & 0xFF;
+ ccb[5]=(unsigned char) blknr & 0xFF; /* LSB Block */
+ ccb[6]=(unsigned char) (cnt >>24) & 0xFF; /* MSB Block count */
+ ccb[7]=(unsigned char) (cnt >>16) & 0xFF;
+ ccb[8]=(unsigned char) (cnt >> 8) & 0xFF;
+ ccb[9]=(unsigned char) cnt & 0xFF; /* LSB Block */
+ ccb[10]=0; /* reserved */
+ ccb[11]=0; /* reserved */
+
+ if (atapi_issue_autoreq(device,ccb,12,
+ (unsigned char *)buffer,
+ cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) {
+ return (n);
+ }
+ n+=cnt;
+ blkcnt-=cnt;
+ blknr+=cnt;
+ buffer+=(cnt*ATAPI_READ_BLOCK_SIZE);
+ } while (blkcnt > 0);
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_ATAPI */
+
+U_BOOT_CMD(
+ ide, 5, 1, do_ide,
+ "IDE sub-system",
+ "reset - reset IDE controller\n"
+ "ide info - show available IDE devices\n"
+ "ide device [dev] - show or set current device\n"
+ "ide part [dev] - print partition table of one or all IDE devices\n"
+ "ide read addr blk# cnt\n"
+ "ide write addr blk# cnt - read/write `cnt'"
+ " blocks starting at block `blk#'\n"
+ " to/from memory address `addr'"
+);
+
+U_BOOT_CMD(
+ diskboot, 3, 1, do_diskboot,
+ "boot from IDE device",
+ "loadAddr dev:part"
+);
diff --git a/u-boot/common/cmd_immap.c b/u-boot/common/cmd_immap.c
new file mode 100644
index 0000000..1f59c1e
--- /dev/null
+++ b/u-boot/common/cmd_immap.c
@@ -0,0 +1,719 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * MPC8xx/MPC8260 Internal Memory Map Functions
+ */
+
+#include <common.h>
+#include <command.h>
+
+#if defined(CONFIG_8xx) || defined(CONFIG_8260)
+
+#if defined(CONFIG_8xx)
+#include <asm/8xx_immap.h>
+#include <commproc.h>
+#include <asm/iopin_8xx.h>
+#elif defined(CONFIG_8260)
+#include <asm/immap_8260.h>
+#include <asm/cpm_8260.h>
+#include <asm/iopin_8260.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void
+unimplemented ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf ("Sorry, but the '%s' command has not been implemented\n",
+ cmdtp->name);
+}
+
+int
+do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile sysconf8xx_t *sc = &immap->im_siu_conf;
+#elif defined(CONFIG_8260)
+ volatile sysconf8260_t *sc = &immap->im_siu_conf;
+#endif
+
+ printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr);
+#if defined(CONFIG_8xx)
+ printf ("SWT = %08x\n", sc->sc_swt);
+ printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask);
+ printf ("SIEL = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec);
+ printf ("TESR = %08x SDCR = %08x\n", sc->sc_tesr, sc->sc_sdcr);
+#elif defined(CONFIG_8260)
+ printf ("BCR = %08x\n", sc->sc_bcr);
+ printf ("P_ACR = %02x P_ALRH= %08x P_ALRL= %08x\n",
+ sc->sc_ppc_acr, sc->sc_ppc_alrh, sc->sc_ppc_alrl);
+ printf ("L_ACR = %02x L_ALRH= %08x L_ALRL= %08x\n",
+ sc->sc_lcl_acr, sc->sc_lcl_alrh, sc->sc_lcl_alrl);
+ printf ("PTESR1= %08x PTESR2= %08x\n", sc->sc_tescr1, sc->sc_tescr2);
+ printf ("LTESR1= %08x LTESR2= %08x\n", sc->sc_ltescr1, sc->sc_ltescr2);
+ printf ("PDTEA = %08x PDTEM = %02x\n", sc->sc_pdtea, sc->sc_pdtem);
+ printf ("LDTEA = %08x LDTEM = %02x\n", sc->sc_ldtea, sc->sc_ldtem);
+#endif
+ return 0;
+}
+
+int
+do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ int nbanks = 8;
+#elif defined(CONFIG_8260)
+ volatile memctl8260_t *memctl = &immap->im_memctl;
+ int nbanks = 12;
+#endif
+ volatile uint *p = &memctl->memc_br0;
+ int i;
+
+ for (i = 0; i < nbanks; i++, p += 2) {
+ if (i < 10) {
+ printf ("BR%d = %08x OR%d = %08x\n",
+ i, p[0], i, p[1]);
+ } else {
+ printf ("BR%d = %08x OR%d = %08x\n",
+ i, p[0], i, p[1]);
+ }
+ }
+
+ printf ("MAR = %08x", memctl->memc_mar);
+#if defined(CONFIG_8xx)
+ printf (" MCR = %08x\n", memctl->memc_mcr);
+#elif defined(CONFIG_8260)
+ putc ('\n');
+#endif
+ printf ("MAMR = %08x MBMR = %08x",
+ memctl->memc_mamr, memctl->memc_mbmr);
+#if defined(CONFIG_8xx)
+ printf ("\nMSTAT = %04x\n", memctl->memc_mstat);
+#elif defined(CONFIG_8260)
+ printf (" MCMR = %08x\n", memctl->memc_mcmr);
+#endif
+ printf ("MPTPR = %04x MDR = %08x\n",
+ memctl->memc_mptpr, memctl->memc_mdr);
+#if defined(CONFIG_8260)
+ printf ("PSDMR = %08x LSDMR = %08x\n",
+ memctl->memc_psdmr, memctl->memc_lsdmr);
+ printf ("PURT = %02x PSRT = %02x\n",
+ memctl->memc_purt, memctl->memc_psrt);
+ printf ("LURT = %02x LSRT = %02x\n",
+ memctl->memc_lurt, memctl->memc_lsrt);
+ printf ("IMMR = %08x\n", memctl->memc_immr);
+#endif
+ return 0;
+}
+
+int
+do_sitinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+#ifdef CONFIG_8260
+int
+do_icinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+#endif
+
+int
+do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile car8xx_t *car = &immap->im_clkrst;
+#elif defined(CONFIG_8260)
+ volatile car8260_t *car = &immap->im_clkrst;
+#endif
+
+#if defined(CONFIG_8xx)
+ printf ("SCCR = %08x\n", car->car_sccr);
+ printf ("PLPRCR= %08x\n", car->car_plprcr);
+ printf ("RSR = %08x\n", car->car_rsr);
+#elif defined(CONFIG_8260)
+ printf ("SCCR = %08x\n", car->car_sccr);
+ printf ("SCMR = %08x\n", car->car_scmr);
+ printf ("RSR = %08x\n", car->car_rsr);
+ printf ("RMR = %08x\n", car->car_rmr);
+#endif
+ return 0;
+}
+
+static int counter;
+
+static void
+header(void)
+{
+ char *data = "\
+ -------------------------------- --------------------------------\
+ 00000000001111111111222222222233 00000000001111111111222222222233\
+ 01234567890123456789012345678901 01234567890123456789012345678901\
+ -------------------------------- --------------------------------\
+ ";
+ int i;
+
+ if (counter % 2)
+ putc('\n');
+ counter = 0;
+
+ for (i = 0; i < 4; i++, data += 79)
+ printf("%.79s\n", data);
+}
+
+static void binary (char *label, uint value, int nbits)
+{
+ uint mask = 1 << (nbits - 1);
+ int i, second = (counter++ % 2);
+
+ if (second)
+ putc (' ');
+ puts (label);
+ for (i = 32 + 1; i != nbits; i--)
+ putc (' ');
+
+ while (mask != 0) {
+ if (value & mask)
+ putc ('1');
+ else
+ putc ('0');
+ mask >>= 1;
+ }
+
+ if (second)
+ putc ('\n');
+}
+
+#if defined(CONFIG_8xx)
+#define PA_NBITS 16
+#define PA_NB_ODR 8
+#define PB_NBITS 18
+#define PB_NB_ODR 16
+#define PC_NBITS 12
+#define PD_NBITS 13
+#elif defined(CONFIG_8260)
+#define PA_NBITS 32
+#define PA_NB_ODR 32
+#define PB_NBITS 28
+#define PB_NB_ODR 28
+#define PC_NBITS 32
+#define PD_NBITS 28
+#endif
+
+int
+do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile iop8xx_t *iop = &immap->im_ioport;
+ volatile ushort *l, *r;
+#elif defined(CONFIG_8260)
+ volatile iop8260_t *iop = &immap->im_ioport;
+ volatile uint *l, *r;
+#endif
+ volatile uint *R;
+
+ counter = 0;
+ header ();
+
+ /*
+ * Ports A & B
+ */
+
+#if defined(CONFIG_8xx)
+ l = &iop->iop_padir;
+ R = &immap->im_cpm.cp_pbdir;
+#elif defined(CONFIG_8260)
+ l = &iop->iop_pdira;
+ R = &iop->iop_pdirb;
+#endif
+ binary ("PA_DIR", *l++, PA_NBITS);
+ binary ("PB_DIR", *R++, PB_NBITS);
+ binary ("PA_PAR", *l++, PA_NBITS);
+ binary ("PB_PAR", *R++, PB_NBITS);
+#if defined(CONFIG_8260)
+ binary ("PA_SOR", *l++, PA_NBITS);
+ binary ("PB_SOR", *R++, PB_NBITS);
+#endif
+ binary ("PA_ODR", *l++, PA_NB_ODR);
+ binary ("PB_ODR", *R++, PB_NB_ODR);
+ binary ("PA_DAT", *l++, PA_NBITS);
+ binary ("PB_DAT", *R++, PB_NBITS);
+
+ header ();
+
+ /*
+ * Ports C & D
+ */
+
+#if defined(CONFIG_8xx)
+ l = &iop->iop_pcdir;
+ r = &iop->iop_pddir;
+#elif defined(CONFIG_8260)
+ l = &iop->iop_pdirc;
+ r = &iop->iop_pdird;
+#endif
+ binary ("PC_DIR", *l++, PC_NBITS);
+ binary ("PD_DIR", *r++, PD_NBITS);
+ binary ("PC_PAR", *l++, PC_NBITS);
+ binary ("PD_PAR", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+ binary ("PC_SO ", *l++, PC_NBITS);
+ binary (" ", 0, 0);
+ r++;
+#elif defined(CONFIG_8260)
+ binary ("PC_SOR", *l++, PC_NBITS);
+ binary ("PD_SOR", *r++, PD_NBITS);
+ binary ("PC_ODR", *l++, PC_NBITS);
+ binary ("PD_ODR", *r++, PD_NBITS);
+#endif
+ binary ("PC_DAT", *l++, PC_NBITS);
+ binary ("PD_DAT", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+ binary ("PC_INT", *l++, PC_NBITS);
+#endif
+
+ header ();
+ return 0;
+}
+
+/*
+ * set the io pins
+ * this needs a clean up for smaller tighter code
+ * use *uint and set the address based on cmd + port
+ */
+int
+do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint rcode = 0;
+ iopin_t iopin;
+ static uint port = 0;
+ static uint pin = 0;
+ static uint value = 0;
+ static enum {
+ DIR,
+ PAR,
+ SOR,
+ ODR,
+ DAT,
+#if defined(CONFIG_8xx)
+ INT
+#endif
+ } cmd = DAT;
+
+ if (argc != 5) {
+ puts ("iopset PORT PIN CMD VALUE\n");
+ return 1;
+ }
+ port = argv[1][0] - 'A';
+ if (port > 3)
+ port -= 0x20;
+ if (port > 3)
+ rcode = 1;
+ pin = simple_strtol (argv[2], NULL, 10);
+ if (pin > 31)
+ rcode = 1;
+
+
+ switch (argv[3][0]) {
+ case 'd':
+ if (argv[3][1] == 'a')
+ cmd = DAT;
+ else if (argv[3][1] == 'i')
+ cmd = DIR;
+ else
+ rcode = 1;
+ break;
+ case 'p':
+ cmd = PAR;
+ break;
+ case 'o':
+ cmd = ODR;
+ break;
+ case 's':
+ cmd = SOR;
+ break;
+#if defined(CONFIG_8xx)
+ case 'i':
+ cmd = INT;
+ break;
+#endif
+ default:
+ printf ("iopset: unknown command %s\n", argv[3]);
+ rcode = 1;
+ }
+ if (argv[4][0] == '1')
+ value = 1;
+ else if (argv[4][0] == '0')
+ value = 0;
+ else
+ rcode = 1;
+ if (rcode == 0) {
+ iopin.port = port;
+ iopin.pin = pin;
+ iopin.flag = 0;
+ switch (cmd) {
+ case DIR:
+ if (value)
+ iopin_set_out (&iopin);
+ else
+ iopin_set_in (&iopin);
+ break;
+ case PAR:
+ if (value)
+ iopin_set_ded (&iopin);
+ else
+ iopin_set_gen (&iopin);
+ break;
+ case SOR:
+ if (value)
+ iopin_set_opt2 (&iopin);
+ else
+ iopin_set_opt1 (&iopin);
+ break;
+ case ODR:
+ if (value)
+ iopin_set_odr (&iopin);
+ else
+ iopin_set_act (&iopin);
+ break;
+ case DAT:
+ if (value)
+ iopin_set_high (&iopin);
+ else
+ iopin_set_low (&iopin);
+ break;
+#if defined(CONFIG_8xx)
+ case INT:
+ if (value)
+ iopin_set_falledge (&iopin);
+ else
+ iopin_set_anyedge (&iopin);
+ break;
+#endif
+ }
+
+ }
+ return rcode;
+}
+
+int
+do_dmainfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_fccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+static void prbrg (int n, uint val)
+{
+ uint extc = (val >> 14) & 3;
+ uint cd = (val & CPM_BRG_CD_MASK) >> 1;
+ uint div16 = (val & CPM_BRG_DIV16) != 0;
+
+#if defined(CONFIG_8xx)
+ ulong clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
+ ulong clock = gd->brg_clk;
+#endif
+
+ printf ("BRG%d:", n);
+
+ if (val & CPM_BRG_RST)
+ puts (" RESET");
+ else
+ puts (" ");
+
+ if (val & CPM_BRG_EN)
+ puts (" ENABLED");
+ else
+ puts (" DISABLED");
+
+ printf (" EXTC=%d", extc);
+
+ if (val & CPM_BRG_ATB)
+ puts (" ATB");
+ else
+ puts (" ");
+
+ printf (" DIVIDER=%4d", cd);
+ if (extc == 0 && cd != 0) {
+ uint baudrate;
+
+ if (div16)
+ baudrate = (clock / 16) / (cd + 1);
+ else
+ baudrate = clock / (cd + 1);
+
+ printf ("=%6d bps", baudrate);
+ } else {
+ puts (" ");
+ }
+
+ if (val & CPM_BRG_DIV16)
+ puts (" DIV16");
+ else
+ puts (" ");
+
+ putc ('\n');
+}
+
+int
+do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile cpm8xx_t *cp = &immap->im_cpm;
+ volatile uint *p = &cp->cp_brgc1;
+#elif defined(CONFIG_8260)
+ volatile uint *p = &immap->im_brgc1;
+#endif
+ int i = 1;
+
+ while (i <= 4)
+ prbrg (i++, *p++);
+
+#if defined(CONFIG_8260)
+ p = &immap->im_brgc5;
+ while (i <= 8)
+ prbrg (i++, *p++);
+#endif
+ return 0;
+}
+
+int
+do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile i2c8xx_t *i2c = &immap->im_i2c;
+ volatile cpm8xx_t *cp = &immap->im_cpm;
+ volatile iic_t *iip = (iic_t *) & cp->cp_dparam[PROFF_IIC];
+#elif defined(CONFIG_8260)
+ volatile i2c8260_t *i2c = &immap->im_i2c;
+ volatile iic_t *iip;
+ uint dpaddr;
+
+ dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE]));
+ if (dpaddr == 0)
+ iip = NULL;
+ else
+ iip = (iic_t *) & immap->im_dprambase[dpaddr];
+#endif
+
+ printf ("I2MOD = %02x I2ADD = %02x\n", i2c->i2c_i2mod, i2c->i2c_i2add);
+ printf ("I2BRG = %02x I2COM = %02x\n", i2c->i2c_i2brg, i2c->i2c_i2com);
+ printf ("I2CER = %02x I2CMR = %02x\n", i2c->i2c_i2cer, i2c->i2c_i2cmr);
+
+ if (iip == NULL)
+ puts ("i2c parameter ram not allocated\n");
+ else {
+ printf ("RBASE = %08x TBASE = %08x\n",
+ iip->iic_rbase, iip->iic_tbase);
+ printf ("RFCR = %02x TFCR = %02x\n",
+ iip->iic_rfcr, iip->iic_tfcr);
+ printf ("MRBLR = %04x\n", iip->iic_mrblr);
+ printf ("RSTATE= %08x RDP = %08x\n",
+ iip->iic_rstate, iip->iic_rdp);
+ printf ("RBPTR = %04x RBC = %04x\n",
+ iip->iic_rbptr, iip->iic_rbc);
+ printf ("RXTMP = %08x\n", iip->iic_rxtmp);
+ printf ("TSTATE= %08x TDP = %08x\n",
+ iip->iic_tstate, iip->iic_tdp);
+ printf ("TBPTR = %04x TBC = %04x\n",
+ iip->iic_tbptr, iip->iic_tbc);
+ printf ("TXTMP = %08x\n", iip->iic_txtmp);
+ }
+ return 0;
+}
+
+int
+do_sccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_smcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_spiinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_muxinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_siinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_mccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ siuinfo, 1, 1, do_siuinfo,
+ "print System Interface Unit (SIU) registers",
+ ""
+);
+
+U_BOOT_CMD(
+ memcinfo, 1, 1, do_memcinfo,
+ "print Memory Controller registers",
+ ""
+);
+
+U_BOOT_CMD(
+ sitinfo, 1, 1, do_sitinfo,
+ "print System Integration Timers (SIT) registers",
+ ""
+);
+
+#ifdef CONFIG_8260
+U_BOOT_CMD(
+ icinfo, 1, 1, do_icinfo,
+ "print Interrupt Controller registers",
+ ""
+);
+#endif
+
+U_BOOT_CMD(
+ carinfo, 1, 1, do_carinfo,
+ "print Clocks and Reset registers",
+ ""
+);
+
+U_BOOT_CMD(
+ iopinfo, 1, 1, do_iopinfo,
+ "print I/O Port registers",
+ ""
+);
+
+U_BOOT_CMD(
+ iopset, 5, 0, do_iopset,
+ "set I/O Port registers",
+ "PORT PIN CMD VALUE\nPORT: A-D, PIN: 0-31, CMD: [dat|dir|odr|sor], VALUE: 0|1"
+);
+
+U_BOOT_CMD(
+ dmainfo, 1, 1, do_dmainfo,
+ "print SDMA/IDMA registers",
+ ""
+);
+
+U_BOOT_CMD(
+ fccinfo, 1, 1, do_fccinfo,
+ "print FCC registers",
+ ""
+);
+
+U_BOOT_CMD(
+ brginfo, 1, 1, do_brginfo,
+ "print Baud Rate Generator (BRG) registers",
+ ""
+);
+
+U_BOOT_CMD(
+ i2cinfo, 1, 1, do_i2cinfo,
+ "print I2C registers",
+ ""
+);
+
+U_BOOT_CMD(
+ sccinfo, 1, 1, do_sccinfo,
+ "print SCC registers",
+ ""
+);
+
+U_BOOT_CMD(
+ smcinfo, 1, 1, do_smcinfo,
+ "print SMC registers",
+ ""
+);
+
+U_BOOT_CMD(
+ spiinfo, 1, 1, do_spiinfo,
+ "print Serial Peripheral Interface (SPI) registers",
+ ""
+);
+
+U_BOOT_CMD(
+ muxinfo, 1, 1, do_muxinfo,
+ "print CPM Multiplexing registers",
+ ""
+);
+
+U_BOOT_CMD(
+ siinfo, 1, 1, do_siinfo,
+ "print Serial Interface (SI) registers",
+ ""
+);
+
+U_BOOT_CMD(
+ mccinfo, 1, 1, do_mccinfo,
+ "print MCC registers",
+ ""
+);
+
+#endif
diff --git a/u-boot/common/cmd_irq.c b/u-boot/common/cmd_irq.c
new file mode 100644
index 0000000..d35a43f
--- /dev/null
+++ b/u-boot/common/cmd_irq.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * 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 <config.h>
+#include <command.h>
+
+int do_interrupts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+ /* on */
+ if (strncmp(argv[1], "on", 2) == 0)
+ enable_interrupts();
+ else
+ disable_interrupts();
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ interrupts, 5, 0, do_interrupts,
+ "enable or disable interrupts",
+ "[on, off]"
+);
+
+/* Implemented in $(CPU)/interrupts.c */
+int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+U_BOOT_CMD(
+ irqinfo, 1, 1, do_irqinfo,
+ "print information about IRQs",
+ ""
+);
diff --git a/u-boot/common/cmd_itest.c b/u-boot/common/cmd_itest.c
new file mode 100644
index 0000000..2a238a4
--- /dev/null
+++ b/u-boot/common/cmd_itest.c
@@ -0,0 +1,193 @@
+/*
+ * (C) Copyright 2003
+ * Tait Electronics Limited, Christchurch, New Zealand
+ *
+ * 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
+ */
+
+/*
+ * This file provides a shell like 'test' function to return
+ * true/false from an integer or string compare of two memory
+ * locations or a location and a scalar/literal.
+ * A few parts were lifted from bash 'test' command
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+#define EQ 0
+#define NE 1
+#define LT 2
+#define GT 3
+#define LE 4
+#define GE 5
+
+struct op_tbl_s {
+ char *op; /* operator string */
+ int opcode; /* internal representation of opcode */
+};
+
+typedef struct op_tbl_s op_tbl_t;
+
+static const op_tbl_t op_table [] = {
+ { "-lt", LT },
+ { "<" , LT },
+ { "-gt", GT },
+ { ">" , GT },
+ { "-eq", EQ },
+ { "==" , EQ },
+ { "-ne", NE },
+ { "!=" , NE },
+ { "<>" , NE },
+ { "-ge", GE },
+ { ">=" , GE },
+ { "-le", LE },
+ { "<=" , LE },
+};
+
+static long evalexp(char *s, int w)
+{
+ long l = 0;
+ long *p;
+
+ /* if the parameter starts with a * then assume is a pointer to the value we want */
+ if (s[0] == '*') {
+ p = (long *)simple_strtoul(&s[1], NULL, 16);
+ switch (w) {
+ case 1: return((long)(*(unsigned char *)p));
+ case 2: return((long)(*(unsigned short *)p));
+ case 4: return(*p);
+ }
+ } else {
+ l = simple_strtoul(s, NULL, 16);
+ }
+
+ return (l & ((1 << (w * 8)) - 1));
+}
+
+static char * evalstr(char *s)
+{
+ /* if the parameter starts with a * then assume a string pointer else its a literal */
+ if (s[0] == '*') {
+ return (char *)simple_strtoul(&s[1], NULL, 16);
+ } else {
+ return s;
+ }
+}
+
+static int stringcomp(char *s, char *t, int op)
+{
+ int p;
+ char *l, *r;
+
+ l = evalstr(s);
+ r = evalstr(t);
+
+ p = strcmp(l, r);
+ switch (op) {
+ case EQ: return (p == 0);
+ case NE: return (p != 0);
+ case LT: return (p < 0);
+ case GT: return (p > 0);
+ case LE: return (p <= 0);
+ case GE: return (p >= 0);
+ }
+ return (0);
+}
+
+static int arithcomp (char *s, char *t, int op, int w)
+{
+ long l, r;
+
+ l = evalexp (s, w);
+ r = evalexp (t, w);
+
+ switch (op) {
+ case EQ: return (l == r);
+ case NE: return (l != r);
+ case LT: return (l < r);
+ case GT: return (l > r);
+ case LE: return (l <= r);
+ case GE: return (l >= r);
+ }
+ return (0);
+}
+
+int binary_test (char *op, char *arg1, char *arg2, int w)
+{
+ int len, i;
+ const op_tbl_t *optp;
+
+ len = strlen(op);
+
+ for (optp = (op_tbl_t *)&op_table, i = 0;
+ i < ARRAY_SIZE(op_table);
+ optp++, i++) {
+
+ if ((strncmp (op, optp->op, len) == 0) && (len == strlen (optp->op))) {
+ if (w == 0) {
+ return (stringcomp(arg1, arg2, optp->opcode));
+ } else {
+ return (arithcomp (arg1, arg2, optp->opcode, w));
+ }
+ }
+ }
+
+ printf("Unknown operator '%s'\n", op);
+ return 0; /* op code not found */
+}
+
+/* command line interface to the shell test */
+int do_itest ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] )
+{
+ int value, w;
+
+ /* Validate arguments */
+ if ((argc != 4))
+ return cmd_usage(cmdtp);
+
+ /* Check for a data width specification.
+ * Defaults to long (4) if no specification.
+ * Uses -2 as 'width' for .s (string) so as not to upset existing code
+ */
+ switch (w = cmd_get_data_size(argv[0], 4)) {
+ case 1:
+ case 2:
+ case 4:
+ value = binary_test (argv[2], argv[1], argv[3], w);
+ break;
+ case -2:
+ value = binary_test (argv[2], argv[1], argv[3], 0);
+ break;
+ case -1:
+ default:
+ puts("Invalid data width specifier\n");
+ value = 0;
+ break;
+ }
+
+ return !value;
+}
+
+U_BOOT_CMD(
+ itest, 4, 0, do_itest,
+ "return true/false on integer compare",
+ "[.b, .w, .l, .s] [*]value1 <op> [*]value2"
+);
diff --git a/u-boot/common/cmd_jffs2.c b/u-boot/common/cmd_jffs2.c
new file mode 100644
index 0000000..27296dd
--- /dev/null
+++ b/u-boot/common/cmd_jffs2.c
@@ -0,0 +1,637 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
+ *
+ * (C) Copyright 2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Added support for reading flash partition table from environment.
+ * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
+ * kernel tree.
+ *
+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * 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
+ */
+
+/*
+ * Three environment variables are used by the parsing routines:
+ *
+ * 'partition' - keeps current partition identifier
+ *
+ * partition := <part-id>
+ * <part-id> := <dev-id>,part_num
+ *
+ *
+ * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
+ *
+ * mtdids=<idmap>[,<idmap>,...]
+ *
+ * <idmap> := <dev-id>=<mtd-id>
+ * <dev-id> := 'nand'|'nor'|'onenand'<dev-num>
+ * <dev-num> := mtd device number, 0...
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ *
+ *
+ * 'mtdparts' - partition list
+ *
+ * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
+ *
+ * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
+ * <size> := standard linux memsize OR '-' to denote all remaining space
+ * <offset> := partition start offset within the device
+ * <name> := '(' NAME ')'
+ * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
+ *
+ * Notes:
+ * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
+ * - if the above variables are not set defaults for a given target are used
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * mtdids=nor0=edb7312-nor
+ * mtdparts=mtdparts=edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
+ * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ *
+ */
+
+/*
+ * JFFS2/CRAMFS support
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <jffs2/jffs2.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <cramfs/cramfs_fs.h>
+
+#if defined(CONFIG_CMD_NAND)
+#include <linux/mtd/nand.h>
+#include <nand.h>
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <onenand_uboot.h>
+#endif
+
+/* enable/disable debugging messages */
+#define DEBUG_JFFS
+#undef DEBUG_JFFS
+
+#ifdef DEBUG_JFFS
+# define DEBUGF(fmt, args...) printf(fmt ,##args)
+#else
+# define DEBUGF(fmt, args...)
+#endif
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xFFFFFFFF
+
+/* special offset value, it is used when not provided by user
+ *
+ * this value is used temporarily during parsing, later such offests
+ * are recalculated */
+#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
+
+/* minimum partition size */
+#define MIN_PART_SIZE 4096
+
+/* this flag needs to be set in part_info struct mask_flags
+ * field for read-only partitions */
+#define MTD_WRITEABLE_CMD 1
+
+/* current active device and partition number */
+#ifdef CONFIG_CMD_MTDPARTS
+/* Use the ones declared in cmd_mtdparts.c */
+extern struct mtd_device *current_mtd_dev;
+extern u8 current_mtd_partnum;
+#else
+/* Use local ones */
+struct mtd_device *current_mtd_dev = NULL;
+u8 current_mtd_partnum = 0;
+#endif
+
+#if defined(CONFIG_CMD_CRAMFS)
+extern int cramfs_check (struct part_info *info);
+extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
+extern int cramfs_ls (struct part_info *info, char *filename);
+extern int cramfs_info (struct part_info *info);
+#else
+/* defining empty macros for function names is ugly but avoids ifdef clutter
+ * all over the code */
+#define cramfs_check(x) (0)
+#define cramfs_load(x,y,z) (-1)
+#define cramfs_ls(x,y) (0)
+#define cramfs_info(x) (0)
+#endif
+
+#ifndef CONFIG_CMD_MTDPARTS
+/**
+ * Check device number to be within valid range for given device type.
+ *
+ * @param dev device to validate
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int mtd_device_validate(u8 type, u8 num, u32 *size)
+{
+ if (type == MTD_DEV_TYPE_NOR) {
+#if defined(CONFIG_CMD_FLASH)
+ if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
+ extern flash_info_t flash_info[];
+ *size = flash_info[num].size;
+
+ return 0;
+ }
+
+ printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
+ MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
+#else
+ printf("support for FLASH devices not present\n");
+#endif
+ } else if (type == MTD_DEV_TYPE_NAND) {
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+ if (num < CONFIG_SYS_MAX_NAND_DEVICE) {
+ *size = nand_info[num].size;
+ return 0;
+ }
+
+ printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
+ MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
+#else
+ printf("support for NAND devices not present\n");
+#endif
+ } else if (type == MTD_DEV_TYPE_ONENAND) {
+#if defined(CONFIG_CMD_ONENAND)
+ *size = onenand_mtd.size;
+ return 0;
+#else
+ printf("support for OneNAND devices not present\n");
+#endif
+ } else
+ printf("Unknown defice type %d\n", type);
+
+ return 1;
+}
+
+/**
+ * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
+ * return device type and number.
+ *
+ * @param id string describing device id
+ * @param ret_id output pointer to next char after parse completes (output)
+ * @param dev_type parsed device type (output)
+ * @param dev_num parsed device number (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+{
+ const char *p = id;
+
+ *dev_type = 0;
+ if (strncmp(p, "nand", 4) == 0) {
+ *dev_type = MTD_DEV_TYPE_NAND;
+ p += 4;
+ } else if (strncmp(p, "nor", 3) == 0) {
+ *dev_type = MTD_DEV_TYPE_NOR;
+ p += 3;
+ } else if (strncmp(p, "onenand", 7) == 0) {
+ *dev_type = MTD_DEV_TYPE_ONENAND;
+ p += 7;
+ } else {
+ printf("incorrect device type in %s\n", id);
+ return 1;
+ }
+
+ if (!isdigit(*p)) {
+ printf("incorrect device number in %s\n", id);
+ return 1;
+ }
+
+ *dev_num = simple_strtoul(p, (char **)&p, 0);
+ if (ret_id)
+ *ret_id = p;
+ return 0;
+}
+
+/*
+ * 'Static' version of command line mtdparts_init() routine. Single partition on
+ * a single device configuration.
+ */
+
+/**
+ * Calculate sector size.
+ *
+ * @return sector size
+ */
+static inline u32 get_part_sector_size_nand(struct mtdids *id)
+{
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+ nand_info_t *nand;
+
+ nand = &nand_info[id->num];
+
+ return nand->erasesize;
+#else
+ BUG();
+ return 0;
+#endif
+}
+
+static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_CMD_FLASH)
+ extern flash_info_t flash_info[];
+
+ u32 end_phys, start_phys, sector_size = 0, size = 0;
+ int i;
+ flash_info_t *flash;
+
+ flash = &flash_info[id->num];
+
+ start_phys = flash->start[0] + part->offset;
+ end_phys = start_phys + part->size - 1;
+
+ for (i = 0; i < flash->sector_count; i++) {
+ if (flash->start[i] >= end_phys)
+ break;
+
+ if (flash->start[i] >= start_phys) {
+ if (i == flash->sector_count - 1) {
+ size = flash->start[0] + flash->size - flash->start[i];
+ } else {
+ size = flash->start[i+1] - flash->start[i];
+ }
+
+ if (sector_size < size)
+ sector_size = size;
+ }
+ }
+
+ return sector_size;
+#else
+ BUG();
+ return 0;
+#endif
+}
+
+static inline u32 get_part_sector_size_onenand(void)
+{
+#if defined(CONFIG_CMD_ONENAND)
+ struct mtd_info *mtd;
+
+ mtd = &onenand_mtd;
+
+ return mtd->erasesize;
+#else
+ BUG();
+ return 0;
+#endif
+}
+
+static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part)
+{
+ if (id->type == MTD_DEV_TYPE_NAND)
+ return get_part_sector_size_nand(id);
+ else if (id->type == MTD_DEV_TYPE_NOR)
+ return get_part_sector_size_nor(id, part);
+ else if (id->type == MTD_DEV_TYPE_ONENAND)
+ return get_part_sector_size_onenand();
+ else
+ DEBUGF("Error: Unknown device type.\n");
+
+ return 0;
+}
+
+/**
+ * Parse and initialize global mtdids mapping and create global
+ * device/partition list.
+ *
+ * 'Static' version of command line mtdparts_init() routine. Single partition on
+ * a single device configuration.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+int mtdparts_init(void)
+{
+ static int initialized = 0;
+ u32 size;
+ char *dev_name;
+
+ DEBUGF("\n---mtdparts_init---\n");
+ if (!initialized) {
+ struct mtdids *id;
+ struct part_info *part;
+
+ initialized = 1;
+ current_mtd_dev = (struct mtd_device *)
+ malloc(sizeof(struct mtd_device) +
+ sizeof(struct part_info) +
+ sizeof(struct mtdids));
+ if (!current_mtd_dev) {
+ printf("out of memory\n");
+ return 1;
+ }
+ memset(current_mtd_dev, 0, sizeof(struct mtd_device) +
+ sizeof(struct part_info) + sizeof(struct mtdids));
+
+ id = (struct mtdids *)(current_mtd_dev + 1);
+ part = (struct part_info *)(id + 1);
+
+ /* id */
+ id->mtd_id = "single part";
+
+#if defined(CONFIG_JFFS2_DEV)
+ dev_name = CONFIG_JFFS2_DEV;
+#else
+ dev_name = "nor0";
+#endif
+
+ if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
+ (mtd_device_validate(id->type, id->num, &size) != 0)) {
+ printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
+ free(current_mtd_dev);
+ return 1;
+ }
+ id->size = size;
+ INIT_LIST_HEAD(&id->link);
+
+ DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
+ id->type, id->num, id->size, id->mtd_id);
+
+ /* partition */
+ part->name = "static";
+ part->auto_name = 0;
+
+#if defined(CONFIG_JFFS2_PART_SIZE)
+ part->size = CONFIG_JFFS2_PART_SIZE;
+#else
+ part->size = SIZE_REMAINING;
+#endif
+
+#if defined(CONFIG_JFFS2_PART_OFFSET)
+ part->offset = CONFIG_JFFS2_PART_OFFSET;
+#else
+ part->offset = 0x00000000;
+#endif
+
+ part->dev = current_mtd_dev;
+ INIT_LIST_HEAD(&part->link);
+
+ /* recalculate size if needed */
+ if (part->size == SIZE_REMAINING)
+ part->size = id->size - part->offset;
+
+ part->sector_size = get_part_sector_size(id, part);
+
+ DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
+ part->name, part->size, part->offset);
+
+ /* device */
+ current_mtd_dev->id = id;
+ INIT_LIST_HEAD(&current_mtd_dev->link);
+ current_mtd_dev->num_parts = 1;
+ INIT_LIST_HEAD(&current_mtd_dev->parts);
+ list_add(&part->link, &current_mtd_dev->parts);
+ }
+
+ return 0;
+}
+#endif /* #ifndef CONFIG_CMD_MTDPARTS */
+
+/**
+ * Return pointer to the partition of a requested number from a requested
+ * device.
+ *
+ * @param dev device that is to be searched for a partition
+ * @param part_num requested partition number
+ * @return pointer to the part_info, NULL otherwise
+ */
+static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num)
+{
+ struct list_head *entry;
+ struct part_info *part;
+ int num;
+
+ if (!dev)
+ return NULL;
+
+ DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ if (part_num >= dev->num_parts) {
+ printf("invalid partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+ return NULL;
+ }
+
+ /* locate partition number, return it */
+ num = 0;
+ list_for_each(entry, &dev->parts) {
+ part = list_entry(entry, struct part_info, link);
+
+ if (part_num == num++) {
+ return part;
+ }
+ }
+
+ return NULL;
+}
+
+/***************************************************/
+/* U-boot commands */
+/***************************************************/
+
+/**
+ * Routine implementing fsload u-boot command. This routine tries to load
+ * a requested file from jffs2/cramfs filesystem on a current partition.
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *fsname;
+ char *filename;
+ int size;
+ struct part_info *part;
+ ulong offset = load_addr;
+
+ /* pre-set Boot file name */
+ if ((filename = getenv("bootfile")) == NULL) {
+ filename = "uImage";
+ }
+
+ if (argc == 2) {
+ filename = argv[1];
+ }
+ if (argc == 3) {
+ offset = simple_strtoul(argv[1], NULL, 16);
+ load_addr = offset;
+ filename = argv[2];
+ }
+
+ /* make sure we are in sync with env variables */
+ if (mtdparts_init() !=0)
+ return 1;
+
+ if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
+
+ /* check partition type for cramfs */
+ fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
+ printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset);
+
+ if (cramfs_check(part)) {
+ size = cramfs_load ((char *) offset, part, filename);
+ } else {
+ /* if this is not cramfs assume jffs2 */
+ size = jffs2_1pass_load((char *)offset, part, filename);
+ }
+
+ if (size > 0) {
+ char buf[10];
+ printf("### %s load complete: %d bytes loaded to 0x%lx\n",
+ fsname, size, offset);
+ sprintf(buf, "%x", size);
+ setenv("filesize", buf);
+ } else {
+ printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename);
+ }
+
+ return !(size > 0);
+ }
+ return 1;
+}
+
+/**
+ * Routine implementing u-boot ls command which lists content of a given
+ * directory on a current partition.
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int ret;
+ struct part_info *part;
+
+ if (argc == 2)
+ filename = argv[1];
+
+ /* make sure we are in sync with env variables */
+ if (mtdparts_init() !=0)
+ return 1;
+
+ if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
+
+ /* check partition type for cramfs */
+ if (cramfs_check(part)) {
+ ret = cramfs_ls (part, filename);
+ } else {
+ /* if this is not cramfs assume jffs2 */
+ ret = jffs2_1pass_ls(part, filename);
+ }
+
+ return ret ? 0 : 1;
+ }
+ return 1;
+}
+
+/**
+ * Routine implementing u-boot fsinfo command. This routine prints out
+ * miscellaneous filesystem informations/statistics.
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct part_info *part;
+ char *fsname;
+ int ret;
+
+ /* make sure we are in sync with env variables */
+ if (mtdparts_init() !=0)
+ return 1;
+
+ if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
+
+ /* check partition type for cramfs */
+ fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
+ printf("### filesystem type is %s\n", fsname);
+
+ if (cramfs_check(part)) {
+ ret = cramfs_info (part);
+ } else {
+ /* if this is not cramfs assume jffs2 */
+ ret = jffs2_1pass_info(part);
+ }
+
+ return ret ? 0 : 1;
+ }
+ return 1;
+}
+
+/***************************************************/
+U_BOOT_CMD(
+ fsload, 3, 0, do_jffs2_fsload,
+ "load binary file from a filesystem image",
+ "[ off ] [ filename ]\n"
+ " - load binary file from flash bank\n"
+ " with offset 'off'"
+);
+U_BOOT_CMD(
+ ls, 2, 1, do_jffs2_ls,
+ "list files in a directory (default /)",
+ "[ directory ]"
+);
+
+U_BOOT_CMD(
+ fsinfo, 1, 1, do_jffs2_fsinfo,
+ "print information about filesystems",
+ ""
+);
+/***************************************************/
diff --git a/u-boot/common/cmd_license.c b/u-boot/common/cmd_license.c
new file mode 100644
index 0000000..70645d5
--- /dev/null
+++ b/u-boot/common/cmd_license.c
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * 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>
+
+/* COPYING is currently 15951 bytes in size */
+#define LICENSE_MAX 20480
+
+#include <command.h>
+#include <malloc.h>
+#include <license.h>
+
+int do_license(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *tok, *dst = malloc(LICENSE_MAX);
+ unsigned long len = LICENSE_MAX;
+
+ if (!dst)
+ return -1;
+
+ if (gunzip(dst, LICENSE_MAX, license_gz, &len) != 0) {
+ printf("Error uncompressing license text\n");
+ free(dst);
+ return -1;
+ }
+ puts(dst);
+ free(dst);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ license, 1, 1, do_license,
+ "print GPL license text",
+ ""
+);
diff --git a/u-boot/common/cmd_load.c b/u-boot/common/cmd_load.c
new file mode 100644
index 0000000..dad0303
--- /dev/null
+++ b/u-boot/common/cmd_load.c
@@ -0,0 +1,1119 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Serial up- and download support
+ */
+#include <common.h>
+#include <command.h>
+#include <s_record.h>
+#include <net.h>
+#include <exports.h>
+#include <xyzModem.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CMD_LOADB)
+static ulong load_serial_ymodem (ulong offset);
+#endif
+
+#if defined(CONFIG_CMD_LOADS)
+static ulong load_serial (long offset);
+static int read_record (char *buf, ulong len);
+# if defined(CONFIG_CMD_SAVES)
+static int save_serial (ulong offset, ulong size);
+static int write_record (char *buf);
+#endif
+
+static int do_echo = 1;
+#endif
+
+/* -------------------------------------------------------------------- */
+
+#if defined(CONFIG_CMD_LOADS)
+int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ long offset = 0;
+ ulong addr;
+ int i;
+ char *env_echo;
+ int rcode = 0;
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ int load_baudrate, current_baudrate;
+
+ load_baudrate = current_baudrate = gd->baudrate;
+#endif
+
+ if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) {
+ do_echo = 1;
+ } else {
+ do_echo = 0;
+ }
+
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ if (argc >= 2) {
+ offset = simple_strtol(argv[1], NULL, 16);
+ }
+ if (argc == 3) {
+ load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
+
+ /* default to current baudrate */
+ if (load_baudrate == 0)
+ load_baudrate = current_baudrate;
+ }
+ if (load_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ENTER ...\n",
+ load_baudrate);
+ udelay(50000);
+ gd->baudrate = load_baudrate;
+ serial_setbrg ();
+ udelay(50000);
+ for (;;) {
+ if (getc() == '\r')
+ break;
+ }
+ }
+#else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
+ if (argc == 2) {
+ offset = simple_strtol(argv[1], NULL, 16);
+ }
+#endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
+
+ printf ("## Ready for S-Record download ...\n");
+
+ addr = load_serial (offset);
+
+ /*
+ * Gather any trailing characters (for instance, the ^D which
+ * is sent by 'cu' after sending a file), and give the
+ * box some time (100 * 1 ms)
+ */
+ for (i=0; i<100; ++i) {
+ if (tstc()) {
+ (void) getc();
+ }
+ udelay(1000);
+ }
+
+ if (addr == ~0) {
+ printf ("## S-Record download aborted\n");
+ rcode = 1;
+ } else {
+ printf ("## Start Addr = 0x%08lX\n", addr);
+ load_addr = addr;
+ }
+
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ if (load_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ESC ...\n",
+ current_baudrate);
+ udelay (50000);
+ gd->baudrate = current_baudrate;
+ serial_setbrg ();
+ udelay (50000);
+ for (;;) {
+ if (getc() == 0x1B) /* ESC */
+ break;
+ }
+ }
+#endif
+ return rcode;
+}
+
+static ulong
+load_serial (long offset)
+{
+ char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */
+ char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */
+ int binlen; /* no. of data bytes in S-Rec. */
+ int type; /* return code for record type */
+ ulong addr; /* load address from S-Record */
+ ulong size; /* number of bytes transferred */
+ char buf[32];
+ ulong store_addr;
+ ulong start_addr = ~0;
+ ulong end_addr = 0;
+ int line_count = 0;
+
+ while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
+ type = srec_decode (record, &binlen, &addr, binbuf);
+
+ if (type < 0) {
+ return (~0); /* Invalid S-Record */
+ }
+
+ switch (type) {
+ case SREC_DATA2:
+ case SREC_DATA3:
+ case SREC_DATA4:
+ store_addr = addr + offset;
+#ifndef CONFIG_SYS_NO_FLASH
+ if (addr2info(store_addr)) {
+ int rc;
+
+ rc = flash_write((char *)binbuf,store_addr,binlen);
+ if (rc != 0) {
+ flash_perror (rc);
+ return (~0);
+ }
+ } else
+#endif
+ {
+ memcpy ((char *)(store_addr), binbuf, binlen);
+ }
+ if ((store_addr) < start_addr)
+ start_addr = store_addr;
+ if ((store_addr + binlen - 1) > end_addr)
+ end_addr = store_addr + binlen - 1;
+ break;
+ case SREC_END2:
+ case SREC_END3:
+ case SREC_END4:
+ udelay (10000);
+ size = end_addr - start_addr + 1;
+ printf ("\n"
+ "## First Load Addr = 0x%08lX\n"
+ "## Last Load Addr = 0x%08lX\n"
+ "## Total Size = 0x%08lX = %ld Bytes\n",
+ start_addr, end_addr, size, size
+ );
+ flush_cache (start_addr, size);
+ sprintf(buf, "%lX", size);
+ setenv("filesize", buf);
+ return (addr);
+ case SREC_START:
+ break;
+ default:
+ break;
+ }
+ if (!do_echo) { /* print a '.' every 100 lines */
+ if ((++line_count % 100) == 0)
+ putc ('.');
+ }
+ }
+
+ return (~0); /* Download aborted */
+}
+
+static int
+read_record (char *buf, ulong len)
+{
+ char *p;
+ char c;
+
+ --len; /* always leave room for terminating '\0' byte */
+
+ for (p=buf; p < buf+len; ++p) {
+ c = getc(); /* read character */
+ if (do_echo)
+ putc (c); /* ... and echo it */
+
+ switch (c) {
+ case '\r':
+ case '\n':
+ *p = '\0';
+ return (p - buf);
+ case '\0':
+ case 0x03: /* ^C - Control C */
+ return (-1);
+ default:
+ *p = c;
+ }
+
+ /* Check for the console hangup (if any different from serial) */
+ if (gd->jt[XF_getc] != getc) {
+ if (ctrlc()) {
+ return (-1);
+ }
+ }
+ }
+
+ /* line too long - truncate */
+ *p = '\0';
+ return (p - buf);
+}
+
+#if defined(CONFIG_CMD_SAVES)
+
+int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong offset = 0;
+ ulong size = 0;
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ int save_baudrate, current_baudrate;
+
+ save_baudrate = current_baudrate = gd->baudrate;
+#endif
+
+ if (argc >= 2) {
+ offset = simple_strtoul(argv[1], NULL, 16);
+ }
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ if (argc >= 3) {
+ size = simple_strtoul(argv[2], NULL, 16);
+ }
+ if (argc == 4) {
+ save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
+
+ /* default to current baudrate */
+ if (save_baudrate == 0)
+ save_baudrate = current_baudrate;
+ }
+ if (save_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ENTER ...\n",
+ save_baudrate);
+ udelay(50000);
+ gd->baudrate = save_baudrate;
+ serial_setbrg ();
+ udelay(50000);
+ for (;;) {
+ if (getc() == '\r')
+ break;
+ }
+ }
+#else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
+ if (argc == 3) {
+ size = simple_strtoul(argv[2], NULL, 16);
+ }
+#endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
+
+ printf ("## Ready for S-Record upload, press ENTER to proceed ...\n");
+ for (;;) {
+ if (getc() == '\r')
+ break;
+ }
+ if(save_serial (offset, size)) {
+ printf ("## S-Record upload aborted\n");
+ } else {
+ printf ("## S-Record upload complete\n");
+ }
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+ if (save_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ESC ...\n",
+ (int)current_baudrate);
+ udelay (50000);
+ gd->baudrate = current_baudrate;
+ serial_setbrg ();
+ udelay (50000);
+ for (;;) {
+ if (getc() == 0x1B) /* ESC */
+ break;
+ }
+ }
+#endif
+ return 0;
+}
+
+#define SREC3_START "S0030000FC\n"
+#define SREC3_FORMAT "S3%02X%08lX%s%02X\n"
+#define SREC3_END "S70500000000FA\n"
+#define SREC_BYTES_PER_RECORD 16
+
+static int save_serial (ulong address, ulong count)
+{
+ int i, c, reclen, checksum, length;
+ char *hex = "0123456789ABCDEF";
+ char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */
+ char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */
+
+ reclen = 0;
+ checksum = 0;
+
+ if(write_record(SREC3_START)) /* write the header */
+ return (-1);
+ do {
+ if(count) { /* collect hex data in the buffer */
+ c = *(volatile uchar*)(address + reclen); /* get one byte */
+ checksum += c; /* accumulate checksum */
+ data[2*reclen] = hex[(c>>4)&0x0f];
+ data[2*reclen+1] = hex[c & 0x0f];
+ data[2*reclen+2] = '\0';
+ ++reclen;
+ --count;
+ }
+ if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
+ /* enough data collected for one record: dump it */
+ if(reclen) { /* build & write a data record: */
+ /* address + data + checksum */
+ length = 4 + reclen + 1;
+
+ /* accumulate length bytes into checksum */
+ for(i = 0; i < 2; i++)
+ checksum += (length >> (8*i)) & 0xff;
+
+ /* accumulate address bytes into checksum: */
+ for(i = 0; i < 4; i++)
+ checksum += (address >> (8*i)) & 0xff;
+
+ /* make proper checksum byte: */
+ checksum = ~checksum & 0xff;
+
+ /* output one record: */
+ sprintf(record, SREC3_FORMAT, length, address, data, checksum);
+ if(write_record(record))
+ return (-1);
+ }
+ address += reclen; /* increment address */
+ checksum = 0;
+ reclen = 0;
+ }
+ }
+ while(count);
+ if(write_record(SREC3_END)) /* write the final record */
+ return (-1);
+ return(0);
+}
+
+static int
+write_record (char *buf)
+{
+ char c;
+
+ while((c = *buf++))
+ putc(c);
+
+ /* Check for the console hangup (if any different from serial) */
+
+ if (ctrlc()) {
+ return (-1);
+ }
+ return (0);
+}
+# endif
+
+#endif
+
+
+#if defined(CONFIG_CMD_LOADB)
+/*
+ * loadb command (load binary) included
+ */
+#define XON_CHAR 17
+#define XOFF_CHAR 19
+#define START_CHAR 0x01
+#define ETX_CHAR 0x03
+#define END_CHAR 0x0D
+#define SPACE 0x20
+#define K_ESCAPE 0x23
+#define SEND_TYPE 'S'
+#define DATA_TYPE 'D'
+#define ACK_TYPE 'Y'
+#define NACK_TYPE 'N'
+#define BREAK_TYPE 'B'
+#define tochar(x) ((char) (((x) + SPACE) & 0xff))
+#define untochar(x) ((int) (((x) - SPACE) & 0xff))
+
+static void set_kerm_bin_mode(unsigned long *);
+static int k_recv(void);
+static ulong load_serial_bin (ulong offset);
+
+
+char his_eol; /* character he needs at end of packet */
+int his_pad_count; /* number of pad chars he needs */
+char his_pad_char; /* pad chars he needs */
+char his_quote; /* quote chars he'll use */
+
+int do_load_serial_bin (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong offset = 0;
+ ulong addr;
+ int load_baudrate, current_baudrate;
+ int rcode = 0;
+ char *s;
+
+ /* pre-set offset from CONFIG_SYS_LOAD_ADDR */
+ offset = CONFIG_SYS_LOAD_ADDR;
+
+ /* pre-set offset from $loadaddr */
+ if ((s = getenv("loadaddr")) != NULL) {
+ offset = simple_strtoul(s, NULL, 16);
+ }
+
+ load_baudrate = current_baudrate = gd->baudrate;
+
+ if (argc >= 2) {
+ offset = simple_strtoul(argv[1], NULL, 16);
+ }
+ if (argc == 3) {
+ load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
+
+ /* default to current baudrate */
+ if (load_baudrate == 0)
+ load_baudrate = current_baudrate;
+ }
+
+ if (load_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ENTER ...\n",
+ load_baudrate);
+ udelay(50000);
+ gd->baudrate = load_baudrate;
+ serial_setbrg ();
+ udelay(50000);
+ for (;;) {
+ if (getc() == '\r')
+ break;
+ }
+ }
+
+ if (strcmp(argv[0],"loady")==0) {
+ printf ("## Ready for binary (ymodem) download "
+ "to 0x%08lX at %d bps...\n",
+ offset,
+ load_baudrate);
+
+ addr = load_serial_ymodem (offset);
+
+ } else {
+
+ printf ("## Ready for binary (kermit) download "
+ "to 0x%08lX at %d bps...\n",
+ offset,
+ load_baudrate);
+ addr = load_serial_bin (offset);
+
+ if (addr == ~0) {
+ load_addr = 0;
+ printf ("## Binary (kermit) download aborted\n");
+ rcode = 1;
+ } else {
+ printf ("## Start Addr = 0x%08lX\n", addr);
+ load_addr = addr;
+ }
+ }
+ if (load_baudrate != current_baudrate) {
+ printf ("## Switch baudrate to %d bps and press ESC ...\n",
+ current_baudrate);
+ udelay (50000);
+ gd->baudrate = current_baudrate;
+ serial_setbrg ();
+ udelay (50000);
+ for (;;) {
+ if (getc() == 0x1B) /* ESC */
+ break;
+ }
+ }
+
+ return rcode;
+}
+
+
+static ulong load_serial_bin (ulong offset)
+{
+ int size, i;
+ char buf[32];
+
+ set_kerm_bin_mode ((ulong *) offset);
+ size = k_recv ();
+
+ /*
+ * Gather any trailing characters (for instance, the ^D which
+ * is sent by 'cu' after sending a file), and give the
+ * box some time (100 * 1 ms)
+ */
+ for (i=0; i<100; ++i) {
+ if (tstc()) {
+ (void) getc();
+ }
+ udelay(1000);
+ }
+
+ flush_cache (offset, size);
+
+ printf("## Total Size = 0x%08x = %d Bytes\n", size, size);
+ sprintf(buf, "%X", size);
+ setenv("filesize", buf);
+
+ return offset;
+}
+
+void send_pad (void)
+{
+ int count = his_pad_count;
+
+ while (count-- > 0)
+ putc (his_pad_char);
+}
+
+/* converts escaped kermit char to binary char */
+char ktrans (char in)
+{
+ if ((in & 0x60) == 0x40) {
+ return (char) (in & ~0x40);
+ } else if ((in & 0x7f) == 0x3f) {
+ return (char) (in | 0x40);
+ } else
+ return in;
+}
+
+int chk1 (char *buffer)
+{
+ int total = 0;
+
+ while (*buffer) {
+ total += *buffer++;
+ }
+ return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
+}
+
+void s1_sendpacket (char *packet)
+{
+ send_pad ();
+ while (*packet) {
+ putc (*packet++);
+ }
+}
+
+static char a_b[24];
+void send_ack (int n)
+{
+ a_b[0] = START_CHAR;
+ a_b[1] = tochar (3);
+ a_b[2] = tochar (n);
+ a_b[3] = ACK_TYPE;
+ a_b[4] = '\0';
+ a_b[4] = tochar (chk1 (&a_b[1]));
+ a_b[5] = his_eol;
+ a_b[6] = '\0';
+ s1_sendpacket (a_b);
+}
+
+void send_nack (int n)
+{
+ a_b[0] = START_CHAR;
+ a_b[1] = tochar (3);
+ a_b[2] = tochar (n);
+ a_b[3] = NACK_TYPE;
+ a_b[4] = '\0';
+ a_b[4] = tochar (chk1 (&a_b[1]));
+ a_b[5] = his_eol;
+ a_b[6] = '\0';
+ s1_sendpacket (a_b);
+}
+
+
+void (*os_data_init) (void);
+void (*os_data_char) (char new_char);
+static int os_data_state, os_data_state_saved;
+static char *os_data_addr, *os_data_addr_saved;
+static char *bin_start_address;
+
+static void bin_data_init (void)
+{
+ os_data_state = 0;
+ os_data_addr = bin_start_address;
+}
+
+static void os_data_save (void)
+{
+ os_data_state_saved = os_data_state;
+ os_data_addr_saved = os_data_addr;
+}
+
+static void os_data_restore (void)
+{
+ os_data_state = os_data_state_saved;
+ os_data_addr = os_data_addr_saved;
+}
+
+static void bin_data_char (char new_char)
+{
+ switch (os_data_state) {
+ case 0: /* data */
+ *os_data_addr++ = new_char;
+ break;
+ }
+}
+
+static void set_kerm_bin_mode (unsigned long *addr)
+{
+ bin_start_address = (char *) addr;
+ os_data_init = bin_data_init;
+ os_data_char = bin_data_char;
+}
+
+
+/* k_data_* simply handles the kermit escape translations */
+static int k_data_escape, k_data_escape_saved;
+void k_data_init (void)
+{
+ k_data_escape = 0;
+ os_data_init ();
+}
+
+void k_data_save (void)
+{
+ k_data_escape_saved = k_data_escape;
+ os_data_save ();
+}
+
+void k_data_restore (void)
+{
+ k_data_escape = k_data_escape_saved;
+ os_data_restore ();
+}
+
+void k_data_char (char new_char)
+{
+ if (k_data_escape) {
+ /* last char was escape - translate this character */
+ os_data_char (ktrans (new_char));
+ k_data_escape = 0;
+ } else {
+ if (new_char == his_quote) {
+ /* this char is escape - remember */
+ k_data_escape = 1;
+ } else {
+ /* otherwise send this char as-is */
+ os_data_char (new_char);
+ }
+ }
+}
+
+#define SEND_DATA_SIZE 20
+char send_parms[SEND_DATA_SIZE];
+char *send_ptr;
+
+/* handle_send_packet interprits the protocol info and builds and
+ sends an appropriate ack for what we can do */
+void handle_send_packet (int n)
+{
+ int length = 3;
+ int bytes;
+
+ /* initialize some protocol parameters */
+ his_eol = END_CHAR; /* default end of line character */
+ his_pad_count = 0;
+ his_pad_char = '\0';
+ his_quote = K_ESCAPE;
+
+ /* ignore last character if it filled the buffer */
+ if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
+ --send_ptr;
+ bytes = send_ptr - send_parms; /* how many bytes we'll process */
+ do {
+ if (bytes-- <= 0)
+ break;
+ /* handle MAXL - max length */
+ /* ignore what he says - most I'll take (here) is 94 */
+ a_b[++length] = tochar (94);
+ if (bytes-- <= 0)
+ break;
+ /* handle TIME - time you should wait for my packets */
+ /* ignore what he says - don't wait for my ack longer than 1 second */
+ a_b[++length] = tochar (1);
+ if (bytes-- <= 0)
+ break;
+ /* handle NPAD - number of pad chars I need */
+ /* remember what he says - I need none */
+ his_pad_count = untochar (send_parms[2]);
+ a_b[++length] = tochar (0);
+ if (bytes-- <= 0)
+ break;
+ /* handle PADC - pad chars I need */
+ /* remember what he says - I need none */
+ his_pad_char = ktrans (send_parms[3]);
+ a_b[++length] = 0x40; /* He should ignore this */
+ if (bytes-- <= 0)
+ break;
+ /* handle EOL - end of line he needs */
+ /* remember what he says - I need CR */
+ his_eol = untochar (send_parms[4]);
+ a_b[++length] = tochar (END_CHAR);
+ if (bytes-- <= 0)
+ break;
+ /* handle QCTL - quote control char he'll use */
+ /* remember what he says - I'll use '#' */
+ his_quote = send_parms[5];
+ a_b[++length] = '#';
+ if (bytes-- <= 0)
+ break;
+ /* handle QBIN - 8-th bit prefixing */
+ /* ignore what he says - I refuse */
+ a_b[++length] = 'N';
+ if (bytes-- <= 0)
+ break;
+ /* handle CHKT - the clock check type */
+ /* ignore what he says - I do type 1 (for now) */
+ a_b[++length] = '1';
+ if (bytes-- <= 0)
+ break;
+ /* handle REPT - the repeat prefix */
+ /* ignore what he says - I refuse (for now) */
+ a_b[++length] = 'N';
+ if (bytes-- <= 0)
+ break;
+ /* handle CAPAS - the capabilities mask */
+ /* ignore what he says - I only do long packets - I don't do windows */
+ a_b[++length] = tochar (2); /* only long packets */
+ a_b[++length] = tochar (0); /* no windows */
+ a_b[++length] = tochar (94); /* large packet msb */
+ a_b[++length] = tochar (94); /* large packet lsb */
+ } while (0);
+
+ a_b[0] = START_CHAR;
+ a_b[1] = tochar (length);
+ a_b[2] = tochar (n);
+ a_b[3] = ACK_TYPE;
+ a_b[++length] = '\0';
+ a_b[length] = tochar (chk1 (&a_b[1]));
+ a_b[++length] = his_eol;
+ a_b[++length] = '\0';
+ s1_sendpacket (a_b);
+}
+
+/* k_recv receives a OS Open image file over kermit line */
+static int k_recv (void)
+{
+ char new_char;
+ char k_state, k_state_saved;
+ int sum;
+ int done;
+ int length;
+ int n, last_n;
+ int len_lo, len_hi;
+
+ /* initialize some protocol parameters */
+ his_eol = END_CHAR; /* default end of line character */
+ his_pad_count = 0;
+ his_pad_char = '\0';
+ his_quote = K_ESCAPE;
+
+ /* initialize the k_recv and k_data state machine */
+ done = 0;
+ k_state = 0;
+ k_data_init ();
+ k_state_saved = k_state;
+ k_data_save ();
+ n = 0; /* just to get rid of a warning */
+ last_n = -1;
+
+ /* expect this "type" sequence (but don't check):
+ S: send initiate
+ F: file header
+ D: data (multiple)
+ Z: end of file
+ B: break transmission
+ */
+
+ /* enter main loop */
+ while (!done) {
+ /* set the send packet pointer to begining of send packet parms */
+ send_ptr = send_parms;
+
+ /* With each packet, start summing the bytes starting with the length.
+ Save the current sequence number.
+ Note the type of the packet.
+ If a character less than SPACE (0x20) is received - error.
+ */
+
+#if 0
+ /* OLD CODE, Prior to checking sequence numbers */
+ /* first have all state machines save current states */
+ k_state_saved = k_state;
+ k_data_save ();
+#endif
+
+ /* get a packet */
+ /* wait for the starting character or ^C */
+ for (;;) {
+ switch (getc ()) {
+ case START_CHAR: /* start packet */
+ goto START;
+ case ETX_CHAR: /* ^C waiting for packet */
+ return (0);
+ default:
+ ;
+ }
+ }
+START:
+ /* get length of packet */
+ sum = 0;
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ length = untochar (new_char);
+ /* get sequence number */
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ n = untochar (new_char);
+ --length;
+
+ /* NEW CODE - check sequence numbers for retried packets */
+ /* Note - this new code assumes that the sequence number is correctly
+ * received. Handling an invalid sequence number adds another layer
+ * of complexity that may not be needed - yet! At this time, I'm hoping
+ * that I don't need to buffer the incoming data packets and can write
+ * the data into memory in real time.
+ */
+ if (n == last_n) {
+ /* same sequence number, restore the previous state */
+ k_state = k_state_saved;
+ k_data_restore ();
+ } else {
+ /* new sequence number, checkpoint the download */
+ last_n = n;
+ k_state_saved = k_state;
+ k_data_save ();
+ }
+ /* END NEW CODE */
+
+ /* get packet type */
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ k_state = new_char;
+ --length;
+ /* check for extended length */
+ if (length == -2) {
+ /* (length byte was 0, decremented twice) */
+ /* get the two length bytes */
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ len_hi = untochar (new_char);
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ len_lo = untochar (new_char);
+ length = len_hi * 95 + len_lo;
+ /* check header checksum */
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f))
+ goto packet_error;
+ sum += new_char & 0xff;
+/* --length; */ /* new length includes only data and block check to come */
+ }
+ /* bring in rest of packet */
+ while (length > 1) {
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ sum += new_char & 0xff;
+ --length;
+ if (k_state == DATA_TYPE) {
+ /* pass on the data if this is a data packet */
+ k_data_char (new_char);
+ } else if (k_state == SEND_TYPE) {
+ /* save send pack in buffer as is */
+ *send_ptr++ = new_char;
+ /* if too much data, back off the pointer */
+ if (send_ptr >= &send_parms[SEND_DATA_SIZE])
+ --send_ptr;
+ }
+ }
+ /* get and validate checksum character */
+ new_char = getc ();
+ if ((new_char & 0xE0) == 0)
+ goto packet_error;
+ if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f))
+ goto packet_error;
+ /* get END_CHAR */
+ new_char = getc ();
+ if (new_char != END_CHAR) {
+ packet_error:
+ /* restore state machines */
+ k_state = k_state_saved;
+ k_data_restore ();
+ /* send a negative acknowledge packet in */
+ send_nack (n);
+ } else if (k_state == SEND_TYPE) {
+ /* crack the protocol parms, build an appropriate ack packet */
+ handle_send_packet (n);
+ } else {
+ /* send simple acknowledge packet in */
+ send_ack (n);
+ /* quit if end of transmission */
+ if (k_state == BREAK_TYPE)
+ done = 1;
+ }
+ }
+ return ((ulong) os_data_addr - (ulong) bin_start_address);
+}
+
+static int getcxmodem(void) {
+ if (tstc())
+ return (getc());
+ return -1;
+}
+static ulong load_serial_ymodem (ulong offset)
+{
+ int size;
+ char buf[32];
+ int err;
+ int res;
+ connection_info_t info;
+ char ymodemBuf[1024];
+ ulong store_addr = ~0;
+ ulong addr = 0;
+
+ size = 0;
+ info.mode = xyzModem_ymodem;
+ res = xyzModem_stream_open (&info, &err);
+ if (!res) {
+
+ while ((res =
+ xyzModem_stream_read (ymodemBuf, 1024, &err)) > 0) {
+ store_addr = addr + offset;
+ size += res;
+ addr += res;
+#ifndef CONFIG_SYS_NO_FLASH
+ if (addr2info (store_addr)) {
+ int rc;
+
+ rc = flash_write ((char *) ymodemBuf,
+ store_addr, res);
+ if (rc != 0) {
+ flash_perror (rc);
+ return (~0);
+ }
+ } else
+#endif
+ {
+ memcpy ((char *) (store_addr), ymodemBuf,
+ res);
+ }
+
+ }
+ } else {
+ printf ("%s\n", xyzModem_error (err));
+ }
+
+ xyzModem_stream_close (&err);
+ xyzModem_stream_terminate (false, &getcxmodem);
+
+
+ flush_cache (offset, size);
+
+ printf ("## Total Size = 0x%08x = %d Bytes\n", size, size);
+ sprintf (buf, "%X", size);
+ setenv ("filesize", buf);
+
+ return offset;
+}
+
+#endif
+
+/* -------------------------------------------------------------------- */
+
+#if defined(CONFIG_CMD_LOADS)
+
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+U_BOOT_CMD(
+ loads, 3, 0, do_load_serial,
+ "load S-Record file over serial line",
+ "[ off ] [ baud ]\n"
+ " - load S-Record file over serial line"
+ " with offset 'off' and baudrate 'baud'"
+);
+
+#else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
+U_BOOT_CMD(
+ loads, 2, 0, do_load_serial,
+ "load S-Record file over serial line",
+ "[ off ]\n"
+ " - load S-Record file over serial line with offset 'off'"
+);
+#endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
+
+/*
+ * SAVES always requires LOADS support, but not vice versa
+ */
+
+
+#if defined(CONFIG_CMD_SAVES)
+#ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
+U_BOOT_CMD(
+ saves, 4, 0, do_save_serial,
+ "save S-Record file over serial line",
+ "[ off ] [size] [ baud ]\n"
+ " - save S-Record file over serial line"
+ " with offset 'off', size 'size' and baudrate 'baud'"
+);
+#else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
+U_BOOT_CMD(
+ saves, 3, 0, do_save_serial,
+ "save S-Record file over serial line",
+ "[ off ] [size]\n"
+ " - save S-Record file over serial line with offset 'off' and size 'size'"
+);
+#endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
+#endif
+#endif
+
+
+#if defined(CONFIG_CMD_LOADB)
+U_BOOT_CMD(
+ loadb, 3, 0, do_load_serial_bin,
+ "load binary file over serial line (kermit mode)",
+ "[ off ] [ baud ]\n"
+ " - load binary file over serial line"
+ " with offset 'off' and baudrate 'baud'"
+);
+
+U_BOOT_CMD(
+ loady, 3, 0, do_load_serial_bin,
+ "load binary file over serial line (ymodem mode)",
+ "[ off ] [ baud ]\n"
+ " - load binary file over serial line"
+ " with offset 'off' and baudrate 'baud'"
+);
+
+#endif
+
+/* -------------------------------------------------------------------- */
+
+#if defined(CONFIG_CMD_HWFLOW)
+int do_hwflow (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ extern int hwflow_onoff(int);
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "off") == 0)
+ hwflow_onoff(-1);
+ else
+ if (strcmp(argv[1], "on") == 0)
+ hwflow_onoff(1);
+ else
+ return cmd_usage(cmdtp);
+ }
+ printf("RTS/CTS hardware flow control: %s\n", hwflow_onoff(0) ? "on" : "off");
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+
+U_BOOT_CMD(
+ hwflow, 2, 0, do_hwflow,
+ "turn RTS/CTS hardware flow control in serial line on/off",
+ "[on|off]"
+);
+
+#endif
diff --git a/u-boot/common/cmd_log.c b/u-boot/common/cmd_log.c
new file mode 100644
index 0000000..0e89357
--- /dev/null
+++ b/u-boot/common/cmd_log.c
@@ -0,0 +1,317 @@
+/*
+ * (C) Copyright 2002-2007
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de.
+ *
+ * Code used from linux/kernel/printk.c
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 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
+ *
+ * Comments:
+ *
+ * After relocating the code, the environment variable "loglevel" is
+ * copied to console_loglevel. The functionality is similar to the
+ * handling in the Linux kernel, i.e. messages logged with a priority
+ * less than console_loglevel are also output to stdout.
+ *
+ * If you want messages with the default level (e.g. POST messages) to
+ * appear on stdout also, make sure the environment variable
+ * "loglevel" is set at boot time to a number higher than
+ * default_message_loglevel below.
+ */
+
+/*
+ * Logbuffer handling routines
+ */
+
+#include <common.h>
+#include <command.h>
+#include <stdio_dev.h>
+#include <post.h>
+#include <logbuff.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Local prototypes */
+static void logbuff_putc (const char c);
+static void logbuff_puts (const char *s);
+static int logbuff_printk(const char *line);
+
+static char buf[1024];
+
+/* This combination will not print messages with the default loglevel */
+static unsigned console_loglevel = 3;
+static unsigned default_message_loglevel = 4;
+static unsigned log_version = 1;
+#ifdef CONFIG_ALT_LB_ADDR
+static volatile logbuff_t *log;
+#else
+static logbuff_t *log;
+#endif
+static char *lbuf;
+
+unsigned long __logbuffer_base(void)
+{
+ return CONFIG_SYS_SDRAM_BASE + gd->bd->bi_memsize - LOGBUFF_LEN;
+}
+unsigned long logbuffer_base (void) __attribute__((weak, alias("__logbuffer_base")));
+
+void logbuff_init_ptrs (void)
+{
+ unsigned long tag, post_word;
+ char *s;
+
+#ifdef CONFIG_ALT_LB_ADDR
+ log = (logbuff_t *)CONFIG_ALT_LH_ADDR;
+ lbuf = (char *)CONFIG_ALT_LB_ADDR;
+#else
+ log = (logbuff_t *)(logbuffer_base ()) - 1;
+ lbuf = (char *)log->buf;
+#endif
+
+ /* Set up log version */
+ if ((s = getenv ("logversion")) != NULL)
+ log_version = (int)simple_strtoul (s, NULL, 10);
+
+ if (log_version == 2)
+ tag = log->v2.tag;
+ else
+ tag = log->v1.tag;
+ post_word = post_word_load();
+#ifdef CONFIG_POST
+ /* The post routines have setup the word so we can simply test it */
+ if (tag != LOGBUFF_MAGIC || (post_word & POST_COLDBOOT)) {
+ logbuff_reset ();
+ }
+#else
+ /* No post routines, so we do our own checking */
+ if (tag != LOGBUFF_MAGIC || post_word != LOGBUFF_MAGIC) {
+ logbuff_reset ();
+ post_word_store (LOGBUFF_MAGIC);
+ }
+#endif
+ if (log_version == 2 && (long)log->v2.start > (long)log->v2.con)
+ log->v2.start = log->v2.con;
+
+ /* Initialize default loglevel if present */
+ if ((s = getenv ("loglevel")) != NULL)
+ console_loglevel = (int)simple_strtoul (s, NULL, 10);
+
+ gd->flags |= GD_FLG_LOGINIT;
+}
+
+void logbuff_reset (void)
+{
+#ifndef CONFIG_ALT_LB_ADDR
+ memset (log, 0, sizeof (logbuff_t));
+#endif
+ if (log_version == 2) {
+ log->v2.tag = LOGBUFF_MAGIC;
+#ifdef CONFIG_ALT_LB_ADDR
+ log->v2.start = 0;
+ log->v2.con = 0;
+ log->v2.end = 0;
+ log->v2.chars = 0;
+#endif
+ } else {
+ log->v1.tag = LOGBUFF_MAGIC;
+#ifdef CONFIG_ALT_LB_ADDR
+ log->v1.dummy = 0;
+ log->v1.start = 0;
+ log->v1.size = 0;
+ log->v1.chars = 0;
+#endif
+ }
+}
+
+int drv_logbuff_init (void)
+{
+ struct stdio_dev logdev;
+ int rc;
+
+ /* Device initialization */
+ memset (&logdev, 0, sizeof (logdev));
+
+ strcpy (logdev.name, "logbuff");
+ logdev.ext = 0; /* No extensions */
+ logdev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ logdev.putc = logbuff_putc; /* 'putc' function */
+ logdev.puts = logbuff_puts; /* 'puts' function */
+
+ rc = stdio_register (&logdev);
+
+ return (rc == 0) ? 1 : rc;
+}
+
+static void logbuff_putc (const char c)
+{
+ char buf[2];
+ buf[0] = c;
+ buf[1] = '\0';
+ logbuff_printk (buf);
+}
+
+static void logbuff_puts (const char *s)
+{
+ logbuff_printk (s);
+}
+
+void logbuff_log(char *msg)
+{
+ if ((gd->flags & GD_FLG_LOGINIT)) {
+ logbuff_printk (msg);
+ } else {
+ /* Can happen only for pre-relocated errors as logging */
+ /* at that stage should be disabled */
+ puts (msg);
+ }
+}
+
+/*
+ * Subroutine: do_log
+ *
+ * Description: Handler for 'log' command..
+ *
+ * Inputs: argv[1] contains the subcommand
+ *
+ * Return: None
+ *
+ */
+int do_log (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *s;
+ unsigned long i, start, size;
+
+ if (strcmp(argv[1],"append") == 0) {
+ /* Log concatenation of all arguments separated by spaces */
+ for (i=2; i<argc; i++) {
+ logbuff_printk (argv[i]);
+ logbuff_putc ((i<argc-1) ? ' ' : '\n');
+ }
+ return 0;
+ }
+
+ switch (argc) {
+
+ case 2:
+ if (strcmp(argv[1],"show") == 0) {
+ if (log_version == 2) {
+ start = log->v2.start;
+ size = log->v2.end - log->v2.start;
+ }
+ else {
+ start = log->v1.start;
+ size = log->v1.size;
+ }
+ for (i=0; i < (size&LOGBUFF_MASK); i++) {
+ s = lbuf+((start+i)&LOGBUFF_MASK);
+ putc (*s);
+ }
+ return 0;
+ } else if (strcmp(argv[1],"reset") == 0) {
+ logbuff_reset ();
+ return 0;
+ } else if (strcmp(argv[1],"info") == 0) {
+ printf ("Logbuffer at %08lx\n", (unsigned long)lbuf);
+ if (log_version == 2) {
+ printf ("log_start = %08lx\n", log->v2.start);
+ printf ("log_end = %08lx\n", log->v2.end);
+ printf ("logged_chars = %08lx\n", log->v2.chars);
+ }
+ else {
+ printf ("log_start = %08lx\n", log->v1.start);
+ printf ("log_size = %08lx\n", log->v1.size);
+ printf ("logged_chars = %08lx\n", log->v1.chars);
+ }
+ return 0;
+ }
+ return cmd_usage(cmdtp);
+
+ default:
+ return cmd_usage(cmdtp);
+ }
+}
+
+U_BOOT_CMD(
+ log, 255, 1, do_log,
+ "manipulate logbuffer",
+ "info - show pointer details\n"
+ "log reset - clear contents\n"
+ "log show - show contents\n"
+ "log append <msg> - append <msg> to the logbuffer"
+);
+
+static int logbuff_printk(const char *line)
+{
+ int i;
+ char *msg, *p, *buf_end;
+ int line_feed;
+ static signed char msg_level = -1;
+
+ strcpy (buf + 3, line);
+ i = strlen (line);
+ buf_end = buf + 3 + i;
+ for (p = buf + 3; p < buf_end; p++) {
+ msg = p;
+ if (msg_level < 0) {
+ if (
+ p[0] != '<' ||
+ p[1] < '0' ||
+ p[1] > '7' ||
+ p[2] != '>'
+ ) {
+ p -= 3;
+ p[0] = '<';
+ p[1] = default_message_loglevel + '0';
+ p[2] = '>';
+ } else
+ msg += 3;
+ msg_level = p[1] - '0';
+ }
+ line_feed = 0;
+ for (; p < buf_end; p++) {
+ if (log_version == 2) {
+ lbuf[log->v2.end & LOGBUFF_MASK] = *p;
+ log->v2.end++;
+ if (log->v2.end - log->v2.start > LOGBUFF_LEN)
+ log->v2.start++;
+ log->v2.chars++;
+ }
+ else {
+ lbuf[(log->v1.start + log->v1.size) &
+ LOGBUFF_MASK] = *p;
+ if (log->v1.size < LOGBUFF_LEN)
+ log->v1.size++;
+ else
+ log->v1.start++;
+ log->v1.chars++;
+ }
+ if (*p == '\n') {
+ line_feed = 1;
+ break;
+ }
+ }
+ if (msg_level < console_loglevel) {
+ printf("%s", msg);
+ }
+ if (line_feed)
+ msg_level = -1;
+ }
+ return i;
+}
diff --git a/u-boot/common/cmd_mac.c b/u-boot/common/cmd_mac.c
new file mode 100644
index 0000000..1884c2a
--- /dev/null
+++ b/u-boot/common/cmd_mac.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2006 Freescale Semiconductor
+ * York Sun (yorksun@freescale.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+
+extern int do_mac(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+U_BOOT_CMD(
+ mac, 3, 1, do_mac,
+ "display and program the system ID and MAC addresses in EEPROM",
+ "[read|save|id|num|errata|date|ports|0|1|2|3|4|5|6|7]\n"
+ "read\n"
+ " - show content of EEPROM\n"
+ "mac save\n"
+ " - save to the EEPROM\n"
+ "mac id\n"
+ " - program system id\n"
+ "mac num\n"
+ " - program system serial number\n"
+ "mac errata\n"
+ " - program errata data\n"
+ "mac date\n"
+ " - program date\n"
+ "mac ports\n"
+ " - program the number of ports\n"
+ "mac X\n"
+ " - program the MAC address for port X [X=0...7]"
+);
diff --git a/u-boot/common/cmd_mem.c b/u-boot/common/cmd_mem.c
new file mode 100644
index 0000000..4b524cf
--- /dev/null
+++ b/u-boot/common/cmd_mem.c
@@ -0,0 +1,1362 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Memory Functions
+ *
+ * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
+ */
+
+#include <common.h>
+#include <command.h>
+#ifdef CONFIG_HAS_DATAFLASH
+#include <dataflash.h>
+#endif
+#include <watchdog.h>
+
+#include <u-boot/md5.h>
+#include <sha1.h>
+
+#ifdef CMD_MEM_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+static int mod_mem(cmd_tbl_t *, int, int, int, char * const []);
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+static uint dp_last_addr, dp_last_size;
+static uint dp_last_length = 0x40;
+static uint mm_last_addr, mm_last_size;
+
+static ulong base_address = 0;
+
+/* Memory Display
+ *
+ * Syntax:
+ * md{.b, .w, .l} {addr} {len}
+ */
+#define DISP_LINE_LEN 16
+int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, length;
+#if defined(CONFIG_HAS_DATAFLASH)
+ ulong nbytes, linebytes;
+#endif
+ int size;
+ int rc = 0;
+
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = dp_last_addr;
+ size = dp_last_size;
+ length = dp_last_length;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ addr += base_address;
+
+ /* If another parameter, it is the length to display.
+ * Length is the number of objects, not number of bytes.
+ */
+ if (argc > 2)
+ length = simple_strtoul(argv[2], NULL, 16);
+ }
+
+#if defined(CONFIG_HAS_DATAFLASH)
+ /* Print the lines.
+ *
+ * We buffer all read data, so we can make sure data is read only
+ * once, and all accesses are with the specified bus width.
+ */
+ nbytes = length * size;
+ do {
+ char linebuf[DISP_LINE_LEN];
+ void* p;
+ linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+
+ rc = read_dataflash(addr, (linebytes/size)*size, linebuf);
+ p = (rc == DATAFLASH_OK) ? linebuf : (void*)addr;
+ print_buffer(addr, p, size, linebytes/size, DISP_LINE_LEN/size);
+
+ nbytes -= linebytes;
+ addr += linebytes;
+ if (ctrlc()) {
+ rc = 1;
+ break;
+ }
+ } while (nbytes > 0);
+#else
+
+# if defined(CONFIG_BLACKFIN)
+ /* See if we're trying to display L1 inst */
+ if (addr_bfin_on_chip_mem(addr)) {
+ char linebuf[DISP_LINE_LEN];
+ ulong linebytes, nbytes = length * size;
+ do {
+ linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
+ memcpy(linebuf, (void *)addr, linebytes);
+ print_buffer(addr, linebuf, size, linebytes/size, DISP_LINE_LEN/size);
+
+ nbytes -= linebytes;
+ addr += linebytes;
+ if (ctrlc()) {
+ rc = 1;
+ break;
+ }
+ } while (nbytes > 0);
+ } else
+# endif
+
+ {
+ /* Print the lines. */
+ print_buffer(addr, (void*)addr, size, length, DISP_LINE_LEN/size);
+ addr += size*length;
+ }
+#endif
+
+ dp_last_addr = addr;
+ dp_last_length = length;
+ dp_last_size = size;
+ return (rc);
+}
+
+int do_mem_mm ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_mem (cmdtp, 1, flag, argc, argv);
+}
+int do_mem_nm ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_mem (cmdtp, 0, flag, argc, argv);
+}
+
+int do_mem_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, writeval, count;
+ int size;
+
+ if ((argc < 3) || (argc > 4))
+ return cmd_usage(cmdtp);
+
+ /* Check for size specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 1)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ addr += base_address;
+
+ /* Get the value to write.
+ */
+ writeval = simple_strtoul(argv[2], NULL, 16);
+
+ /* Count ? */
+ if (argc == 4) {
+ count = simple_strtoul(argv[3], NULL, 16);
+ } else {
+ count = 1;
+ }
+
+ while (count-- > 0) {
+ if (size == 4)
+ *((ulong *)addr) = (ulong )writeval;
+ else if (size == 2)
+ *((ushort *)addr) = (ushort)writeval;
+ else
+ *((u_char *)addr) = (u_char)writeval;
+ addr += size;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_MX_CYCLIC
+int do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ ulong count;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ count = simple_strtoul(argv[3], NULL, 10);
+
+ for (;;) {
+ do_mem_md (NULL, 0, 3, argv);
+
+ /* delay for <count> ms... */
+ for (i=0; i<count; i++)
+ udelay (1000);
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ puts("Abort\n");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+int do_mem_mwc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ ulong count;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ count = simple_strtoul(argv[3], NULL, 10);
+
+ for (;;) {
+ do_mem_mw (NULL, 0, 3, argv);
+
+ /* delay for <count> ms... */
+ for (i=0; i<count; i++)
+ udelay (1000);
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ puts("Abort\n");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MX_CYCLIC */
+
+int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr1, addr2, count, ngood;
+ int size;
+ int rcode = 0;
+
+ if (argc != 4)
+ return cmd_usage(cmdtp);
+
+ /* Check for size specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ addr1 = simple_strtoul(argv[1], NULL, 16);
+ addr1 += base_address;
+
+ addr2 = simple_strtoul(argv[2], NULL, 16);
+ addr2 += base_address;
+
+ count = simple_strtoul(argv[3], NULL, 16);
+
+#ifdef CONFIG_HAS_DATAFLASH
+ if (addr_dataflash(addr1) | addr_dataflash(addr2)){
+ puts ("Comparison with DataFlash space not supported.\n\r");
+ return 0;
+ }
+#endif
+
+#ifdef CONFIG_BLACKFIN
+ if (addr_bfin_on_chip_mem(addr1) || addr_bfin_on_chip_mem(addr2)) {
+ puts ("Comparison with L1 instruction memory not supported.\n\r");
+ return 0;
+ }
+#endif
+
+ ngood = 0;
+
+ while (count-- > 0) {
+ if (size == 4) {
+ ulong word1 = *(ulong *)addr1;
+ ulong word2 = *(ulong *)addr2;
+ if (word1 != word2) {
+ printf("word at 0x%08lx (0x%08lx) "
+ "!= word at 0x%08lx (0x%08lx)\n",
+ addr1, word1, addr2, word2);
+ rcode = 1;
+ break;
+ }
+ }
+ else if (size == 2) {
+ ushort hword1 = *(ushort *)addr1;
+ ushort hword2 = *(ushort *)addr2;
+ if (hword1 != hword2) {
+ printf("halfword at 0x%08lx (0x%04x) "
+ "!= halfword at 0x%08lx (0x%04x)\n",
+ addr1, hword1, addr2, hword2);
+ rcode = 1;
+ break;
+ }
+ }
+ else {
+ u_char byte1 = *(u_char *)addr1;
+ u_char byte2 = *(u_char *)addr2;
+ if (byte1 != byte2) {
+ printf("byte at 0x%08lx (0x%02x) "
+ "!= byte at 0x%08lx (0x%02x)\n",
+ addr1, byte1, addr2, byte2);
+ rcode = 1;
+ break;
+ }
+ }
+ ngood++;
+ addr1 += size;
+ addr2 += size;
+
+ /* reset watchdog from time to time */
+ if ((count % (64 << 10)) == 0)
+ WATCHDOG_RESET();
+ }
+
+ printf("Total of %ld %s%s were the same\n",
+ ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte",
+ ngood == 1 ? "" : "s");
+ return rcode;
+}
+
+int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, dest, count;
+ int size;
+
+ if (argc != 4)
+ return cmd_usage(cmdtp);
+
+ /* Check for size specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+ addr += base_address;
+
+ dest = simple_strtoul(argv[2], NULL, 16);
+ dest += base_address;
+
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if (count == 0) {
+ puts ("Zero length ???\n");
+ return 1;
+ }
+
+#ifndef CONFIG_SYS_NO_FLASH
+ /* check if we are copying to Flash */
+ if ( (addr2info(dest) != NULL)
+#ifdef CONFIG_HAS_DATAFLASH
+ && (!addr_dataflash(dest))
+#endif
+ ) {
+ int rc;
+
+ puts ("Copy to Flash... ");
+
+ rc = flash_write ((char *)addr, dest, count*size);
+ if (rc != 0) {
+ flash_perror (rc);
+ return (1);
+ }
+ puts ("done\n");
+ return 0;
+ }
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+ /* Check if we are copying from RAM or Flash to DataFlash */
+ if (addr_dataflash(dest) && !addr_dataflash(addr)){
+ int rc;
+
+ puts ("Copy to DataFlash... ");
+
+ rc = write_dataflash (dest, addr, count*size);
+
+ if (rc != 1) {
+ dataflash_perror (rc);
+ return (1);
+ }
+ puts ("done\n");
+ return 0;
+ }
+
+ /* Check if we are copying from DataFlash to RAM */
+ if (addr_dataflash(addr) && !addr_dataflash(dest)
+#ifndef CONFIG_SYS_NO_FLASH
+ && (addr2info(dest) == NULL)
+#endif
+ ){
+ int rc;
+ rc = read_dataflash(addr, count * size, (char *) dest);
+ if (rc != 1) {
+ dataflash_perror (rc);
+ return (1);
+ }
+ return 0;
+ }
+
+ if (addr_dataflash(addr) && addr_dataflash(dest)){
+ puts ("Unsupported combination of source/destination.\n\r");
+ return 1;
+ }
+#endif
+
+#ifdef CONFIG_BLACKFIN
+ /* See if we're copying to/from L1 inst */
+ if (addr_bfin_on_chip_mem(dest) || addr_bfin_on_chip_mem(addr)) {
+ memcpy((void *)dest, (void *)addr, count * size);
+ return 0;
+ }
+#endif
+
+ while (count-- > 0) {
+ if (size == 4)
+ *((ulong *)dest) = *((ulong *)addr);
+ else if (size == 2)
+ *((ushort *)dest) = *((ushort *)addr);
+ else
+ *((u_char *)dest) = *((u_char *)addr);
+ addr += size;
+ dest += size;
+
+ /* reset watchdog from time to time */
+ if ((count % (64 << 10)) == 0)
+ WATCHDOG_RESET();
+ }
+ return 0;
+}
+
+int do_mem_base (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc > 1) {
+ /* Set new base address.
+ */
+ base_address = simple_strtoul(argv[1], NULL, 16);
+ }
+ /* Print the current base address.
+ */
+ printf("Base Address: 0x%08lx\n", base_address);
+ return 0;
+}
+
+int do_mem_loop (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, length, i, junk;
+ int size;
+ volatile uint *longp;
+ volatile ushort *shortp;
+ volatile u_char *cp;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ /* Check for a size spefication.
+ * Defaults to long if no or incorrect specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ /* Address is always specified.
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ /* Length is the number of objects, not number of bytes.
+ */
+ length = simple_strtoul(argv[2], NULL, 16);
+
+ /* We want to optimize the loops to run as fast as possible.
+ * If we have only one object, just run infinite loops.
+ */
+ if (length == 1) {
+ if (size == 4) {
+ longp = (uint *)addr;
+ for (;;)
+ i = *longp;
+ }
+ if (size == 2) {
+ shortp = (ushort *)addr;
+ for (;;)
+ i = *shortp;
+ }
+ cp = (u_char *)addr;
+ for (;;)
+ i = *cp;
+ }
+
+ if (size == 4) {
+ for (;;) {
+ longp = (uint *)addr;
+ i = length;
+ while (i-- > 0)
+ junk = *longp++;
+ }
+ }
+ if (size == 2) {
+ for (;;) {
+ shortp = (ushort *)addr;
+ i = length;
+ while (i-- > 0)
+ junk = *shortp++;
+ }
+ }
+ for (;;) {
+ cp = (u_char *)addr;
+ i = length;
+ while (i-- > 0)
+ junk = *cp++;
+ }
+}
+
+#ifdef CONFIG_LOOPW
+int do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, length, i, data;
+ int size;
+ volatile uint *longp;
+ volatile ushort *shortp;
+ volatile u_char *cp;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ /* Check for a size spefication.
+ * Defaults to long if no or incorrect specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ /* Address is always specified.
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ /* Length is the number of objects, not number of bytes.
+ */
+ length = simple_strtoul(argv[2], NULL, 16);
+
+ /* data to write */
+ data = simple_strtoul(argv[3], NULL, 16);
+
+ /* We want to optimize the loops to run as fast as possible.
+ * If we have only one object, just run infinite loops.
+ */
+ if (length == 1) {
+ if (size == 4) {
+ longp = (uint *)addr;
+ for (;;)
+ *longp = data;
+ }
+ if (size == 2) {
+ shortp = (ushort *)addr;
+ for (;;)
+ *shortp = data;
+ }
+ cp = (u_char *)addr;
+ for (;;)
+ *cp = data;
+ }
+
+ if (size == 4) {
+ for (;;) {
+ longp = (uint *)addr;
+ i = length;
+ while (i-- > 0)
+ *longp++ = data;
+ }
+ }
+ if (size == 2) {
+ for (;;) {
+ shortp = (ushort *)addr;
+ i = length;
+ while (i-- > 0)
+ *shortp++ = data;
+ }
+ }
+ for (;;) {
+ cp = (u_char *)addr;
+ i = length;
+ while (i-- > 0)
+ *cp++ = data;
+ }
+}
+#endif /* CONFIG_LOOPW */
+
+/*
+ * Perform a memory test. A more complete alternative test can be
+ * configured using CONFIG_SYS_ALT_MEMTEST. The complete test loops until
+ * interrupted by ctrl-c or by a failure of one of the sub-tests.
+ */
+int do_mem_mtest (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ vu_long *addr, *start, *end;
+ ulong val;
+ ulong readback;
+ ulong errs = 0;
+ int iterations = 1;
+ int iteration_limit;
+
+#if defined(CONFIG_SYS_ALT_MEMTEST)
+ vu_long len;
+ vu_long offset;
+ vu_long test_offset;
+ vu_long pattern;
+ vu_long temp;
+ vu_long anti_pattern;
+ vu_long num_words;
+#if defined(CONFIG_SYS_MEMTEST_SCRATCH)
+ vu_long *dummy = (vu_long*)CONFIG_SYS_MEMTEST_SCRATCH;
+#else
+ vu_long *dummy = 0; /* yes, this is address 0x0, not NULL */
+#endif
+ int j;
+
+ static const ulong bitpattern[] = {
+ 0x00000001, /* single bit */
+ 0x00000003, /* two adjacent bits */
+ 0x00000007, /* three adjacent bits */
+ 0x0000000F, /* four adjacent bits */
+ 0x00000005, /* two non-adjacent bits */
+ 0x00000015, /* three non-adjacent bits */
+ 0x00000055, /* four non-adjacent bits */
+ 0xaaaaaaaa, /* alternating 1/0 */
+ };
+#else
+ ulong incr;
+ ulong pattern;
+#endif
+
+ if (argc > 1)
+ start = (ulong *)simple_strtoul(argv[1], NULL, 16);
+ else
+ start = (ulong *)CONFIG_SYS_MEMTEST_START;
+
+ if (argc > 2)
+ end = (ulong *)simple_strtoul(argv[2], NULL, 16);
+ else
+ end = (ulong *)(CONFIG_SYS_MEMTEST_END);
+
+ if (argc > 3)
+ pattern = (ulong)simple_strtoul(argv[3], NULL, 16);
+ else
+ pattern = 0;
+
+ if (argc > 4)
+ iteration_limit = (ulong)simple_strtoul(argv[4], NULL, 16);
+ else
+ iteration_limit = 0;
+
+#if defined(CONFIG_SYS_ALT_MEMTEST)
+ printf ("Testing %08x ... %08x:\n", (uint)start, (uint)end);
+ PRINTF("%s:%d: start 0x%p end 0x%p\n",
+ __FUNCTION__, __LINE__, start, end);
+
+ for (;;) {
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+
+
+ if (iteration_limit && iterations > iteration_limit) {
+ printf("Tested %d iteration(s) with %lu errors.\n",
+ iterations-1, errs);
+ return errs != 0;
+ }
+
+ printf("Iteration: %6d\r", iterations);
+ PRINTF("\n");
+ iterations++;
+
+ /*
+ * Data line test: write a pattern to the first
+ * location, write the 1's complement to a 'parking'
+ * address (changes the state of the data bus so a
+ * floating bus doen't give a false OK), and then
+ * read the value back. Note that we read it back
+ * into a variable because the next time we read it,
+ * it might be right (been there, tough to explain to
+ * the quality guys why it prints a failure when the
+ * "is" and "should be" are obviously the same in the
+ * error message).
+ *
+ * Rather than exhaustively testing, we test some
+ * patterns by shifting '1' bits through a field of
+ * '0's and '0' bits through a field of '1's (i.e.
+ * pattern and ~pattern).
+ */
+ addr = start;
+ for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) {
+ val = bitpattern[j];
+ for(; val != 0; val <<= 1) {
+ *addr = val;
+ *dummy = ~val; /* clear the test data off of the bus */
+ readback = *addr;
+ if(readback != val) {
+ printf ("FAILURE (data line): "
+ "expected %08lx, actual %08lx\n",
+ val, readback);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ *addr = ~val;
+ *dummy = val;
+ readback = *addr;
+ if(readback != ~val) {
+ printf ("FAILURE (data line): "
+ "Is %08lx, should be %08lx\n",
+ readback, ~val);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ }
+ }
+
+ /*
+ * Based on code whose Original Author and Copyright
+ * information follows: Copyright (c) 1998 by Michael
+ * Barr. This software is placed into the public
+ * domain and may be used for any purpose. However,
+ * this notice must not be changed or removed and no
+ * warranty is either expressed or implied by its
+ * publication or distribution.
+ */
+
+ /*
+ * Address line test
+ *
+ * Description: Test the address bus wiring in a
+ * memory region by performing a walking
+ * 1's test on the relevant bits of the
+ * address and checking for aliasing.
+ * This test will find single-bit
+ * address failures such as stuck -high,
+ * stuck-low, and shorted pins. The base
+ * address and size of the region are
+ * selected by the caller.
+ *
+ * Notes: For best results, the selected base
+ * address should have enough LSB 0's to
+ * guarantee single address bit changes.
+ * For example, to test a 64-Kbyte
+ * region, select a base address on a
+ * 64-Kbyte boundary. Also, select the
+ * region size as a power-of-two if at
+ * all possible.
+ *
+ * Returns: 0 if the test succeeds, 1 if the test fails.
+ */
+ len = ((ulong)end - (ulong)start)/sizeof(vu_long);
+ pattern = (vu_long) 0xaaaaaaaa;
+ anti_pattern = (vu_long) 0x55555555;
+
+ PRINTF("%s:%d: length = 0x%.8lx\n",
+ __FUNCTION__, __LINE__,
+ len);
+ /*
+ * Write the default pattern at each of the
+ * power-of-two offsets.
+ */
+ for (offset = 1; offset < len; offset <<= 1) {
+ start[offset] = pattern;
+ }
+
+ /*
+ * Check for address bits stuck high.
+ */
+ test_offset = 0;
+ start[test_offset] = anti_pattern;
+
+ for (offset = 1; offset < len; offset <<= 1) {
+ temp = start[offset];
+ if (temp != pattern) {
+ printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:"
+ " expected 0x%.8lx, actual 0x%.8lx\n",
+ (ulong)&start[offset], pattern, temp);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ }
+ start[test_offset] = pattern;
+ WATCHDOG_RESET();
+
+ /*
+ * Check for addr bits stuck low or shorted.
+ */
+ for (test_offset = 1; test_offset < len; test_offset <<= 1) {
+ start[test_offset] = anti_pattern;
+
+ for (offset = 1; offset < len; offset <<= 1) {
+ temp = start[offset];
+ if ((temp != pattern) && (offset != test_offset)) {
+ printf ("\nFAILURE: Address bit stuck low or shorted @"
+ " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n",
+ (ulong)&start[offset], pattern, temp);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ }
+ start[test_offset] = pattern;
+ }
+
+ /*
+ * Description: Test the integrity of a physical
+ * memory device by performing an
+ * increment/decrement test over the
+ * entire region. In the process every
+ * storage bit in the device is tested
+ * as a zero and a one. The base address
+ * and the size of the region are
+ * selected by the caller.
+ *
+ * Returns: 0 if the test succeeds, 1 if the test fails.
+ */
+ num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1;
+
+ /*
+ * Fill memory with a known pattern.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ WATCHDOG_RESET();
+ start[offset] = pattern;
+ }
+
+ /*
+ * Check each location and invert it for the second pass.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ WATCHDOG_RESET();
+ temp = start[offset];
+ if (temp != pattern) {
+ printf ("\nFAILURE (read/write) @ 0x%.8lx:"
+ " expected 0x%.8lx, actual 0x%.8lx)\n",
+ (ulong)&start[offset], pattern, temp);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+
+ anti_pattern = ~pattern;
+ start[offset] = anti_pattern;
+ }
+
+ /*
+ * Check each location for the inverted pattern and zero it.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ WATCHDOG_RESET();
+ anti_pattern = ~pattern;
+ temp = start[offset];
+ if (temp != anti_pattern) {
+ printf ("\nFAILURE (read/write): @ 0x%.8lx:"
+ " expected 0x%.8lx, actual 0x%.8lx)\n",
+ (ulong)&start[offset], anti_pattern, temp);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ start[offset] = 0;
+ }
+ }
+
+#else /* The original, quickie test */
+ incr = 1;
+ for (;;) {
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+
+ if (iteration_limit && iterations > iteration_limit) {
+ printf("Tested %d iteration(s) with %lu errors.\n",
+ iterations-1, errs);
+ return errs != 0;
+ }
+ ++iterations;
+
+ printf ("\rPattern %08lX Writing..."
+ "%12s"
+ "\b\b\b\b\b\b\b\b\b\b",
+ pattern, "");
+
+ for (addr=start,val=pattern; addr<end; addr++) {
+ WATCHDOG_RESET();
+ *addr = val;
+ val += incr;
+ }
+
+ puts ("Reading...");
+
+ for (addr=start,val=pattern; addr<end; addr++) {
+ WATCHDOG_RESET();
+ readback = *addr;
+ if (readback != val) {
+ printf ("\nMem error @ 0x%08X: "
+ "found %08lX, expected %08lX\n",
+ (uint)addr, readback, val);
+ errs++;
+ if (ctrlc()) {
+ putc ('\n');
+ return 1;
+ }
+ }
+ val += incr;
+ }
+
+ /*
+ * Flip the pattern each time to make lots of zeros and
+ * then, the next time, lots of ones. We decrement
+ * the "negative" patterns and increment the "positive"
+ * patterns to preserve this feature.
+ */
+ if(pattern & 0x80000000) {
+ pattern = -pattern; /* complement & increment */
+ }
+ else {
+ pattern = ~pattern;
+ }
+ incr = -incr;
+ }
+#endif
+ return 0; /* not reached */
+}
+
+
+/* Modify memory.
+ *
+ * Syntax:
+ * mm{.b, .w, .l} {addr}
+ * nm{.b, .w, .l} {addr}
+ */
+static int
+mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+ ulong addr, i;
+ int nbytes, size;
+ extern char console_buffer[];
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+ reset_cmd_timeout(); /* got a good command to get here */
+#endif
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = mm_last_addr;
+ size = mm_last_size;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ if ((size = cmd_get_data_size(argv[0], 4)) < 0)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ addr += base_address;
+ }
+
+#ifdef CONFIG_HAS_DATAFLASH
+ if (addr_dataflash(addr)){
+ puts ("Can't modify DataFlash in place. Use cp instead.\n\r");
+ return 0;
+ }
+#endif
+
+#ifdef CONFIG_BLACKFIN
+ if (addr_bfin_on_chip_mem(addr)) {
+ puts ("Can't modify L1 instruction in place. Use cp instead.\n\r");
+ return 0;
+ }
+#endif
+
+ /* Print the address, followed by value. Then accept input for
+ * the next value. A non-converted value exits.
+ */
+ do {
+ printf("%08lx:", addr);
+ if (size == 4)
+ printf(" %08x", *((uint *)addr));
+ else if (size == 2)
+ printf(" %04x", *((ushort *)addr));
+ else
+ printf(" %02x", *((u_char *)addr));
+
+ nbytes = readline (" ? ");
+ if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+ /* <CR> pressed as only input, don't modify current
+ * location and move to next. "-" pressed will go back.
+ */
+ if (incrflag)
+ addr += nbytes ? -size : size;
+ nbytes = 1;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ reset_cmd_timeout(); /* good enough to not time out */
+#endif
+ }
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (nbytes == -2) {
+ break; /* timed out, exit the command */
+ }
+#endif
+ else {
+ char *endp;
+ i = simple_strtoul(console_buffer, &endp, 16);
+ nbytes = endp - console_buffer;
+ if (nbytes) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ /* good enough to not time out
+ */
+ reset_cmd_timeout();
+#endif
+ if (size == 4)
+ *((uint *)addr) = i;
+ else if (size == 2)
+ *((ushort *)addr) = i;
+ else
+ *((u_char *)addr) = i;
+ if (incrflag)
+ addr += size;
+ }
+ }
+ } while (nbytes);
+
+ mm_last_addr = addr;
+ mm_last_size = size;
+ return 0;
+}
+
+#ifndef CONFIG_CRC32_VERIFY
+
+int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, length;
+ ulong crc;
+ ulong *ptr;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul (argv[1], NULL, 16);
+ addr += base_address;
+
+ length = simple_strtoul (argv[2], NULL, 16);
+
+ crc = crc32 (0, (const uchar *) addr, length);
+
+ printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
+ addr, addr + length - 1, crc);
+
+ if (argc > 3) {
+ ptr = (ulong *) simple_strtoul (argv[3], NULL, 16);
+ *ptr = crc;
+ }
+
+ return 0;
+}
+
+#else /* CONFIG_CRC32_VERIFY */
+
+int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, length;
+ ulong crc;
+ ulong *ptr;
+ ulong vcrc;
+ int verify;
+ int ac;
+ char * const *av;
+
+ if (argc < 3) {
+usage:
+ return cmd_usage(cmdtp);
+ }
+
+ av = argv + 1;
+ ac = argc - 1;
+ if (strcmp(*av, "-v") == 0) {
+ verify = 1;
+ av++;
+ ac--;
+ if (ac < 3)
+ goto usage;
+ } else
+ verify = 0;
+
+ addr = simple_strtoul(*av++, NULL, 16);
+ addr += base_address;
+ length = simple_strtoul(*av++, NULL, 16);
+
+ crc = crc32(0, (const uchar *) addr, length);
+
+ if (!verify) {
+ printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
+ addr, addr + length - 1, crc);
+ if (ac > 2) {
+ ptr = (ulong *) simple_strtoul (*av++, NULL, 16);
+ *ptr = crc;
+ }
+ } else {
+ vcrc = simple_strtoul(*av++, NULL, 16);
+ if (vcrc != crc) {
+ printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n",
+ addr, addr + length - 1, crc, vcrc);
+ return 1;
+ }
+ }
+
+ return 0;
+
+}
+#endif /* CONFIG_CRC32_VERIFY */
+
+#ifdef CONFIG_CMD_MD5SUM
+int do_md5sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, len;
+ unsigned int i;
+ u8 output[16];
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+ len = simple_strtoul(argv[2], NULL, 16);
+
+ md5((unsigned char *) addr, len, output);
+ printf("md5 for %08lx ... %08lx ==> ", addr, addr + len - 1);
+ for (i = 0; i < 16; i++)
+ printf("%02x", output[i]);
+ printf("\n");
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CMD_SHA1SUM
+int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, len;
+ unsigned int i;
+ u8 output[20];
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+ len = simple_strtoul(argv[2], NULL, 16);
+
+ sha1_csum((unsigned char *) addr, len, output);
+ printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1);
+ for (i = 0; i < 20; i++)
+ printf("%02x", output[i]);
+ printf("\n");
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CMD_UNZIP
+int do_unzip ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long src, dst;
+ unsigned long src_len = ~0UL, dst_len = ~0UL;
+ char buf[32];
+
+ switch (argc) {
+ case 4:
+ dst_len = simple_strtoul(argv[3], NULL, 16);
+ /* fall through */
+ case 3:
+ src = simple_strtoul(argv[1], NULL, 16);
+ dst = simple_strtoul(argv[2], NULL, 16);
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (gunzip((void *) dst, dst_len, (void *) src, &src_len) != 0)
+ return 1;
+
+ printf("Uncompressed size: %ld = 0x%lX\n", src_len, src_len);
+ sprintf(buf, "%lX", src_len);
+ setenv("filesize", buf);
+
+ return 0;
+}
+#endif /* CONFIG_CMD_UNZIP */
+
+
+/**************************************************/
+U_BOOT_CMD(
+ md, 3, 1, do_mem_md,
+ "memory display",
+ "[.b, .w, .l] address [# of objects]"
+);
+
+
+U_BOOT_CMD(
+ mm, 2, 1, do_mem_mm,
+ "memory modify (auto-incrementing address)",
+ "[.b, .w, .l] address"
+);
+
+
+U_BOOT_CMD(
+ nm, 2, 1, do_mem_nm,
+ "memory modify (constant address)",
+ "[.b, .w, .l] address"
+);
+
+U_BOOT_CMD(
+ mw, 4, 1, do_mem_mw,
+ "memory write (fill)",
+ "[.b, .w, .l] address value [count]"
+);
+
+U_BOOT_CMD(
+ cp, 4, 1, do_mem_cp,
+ "memory copy",
+ "[.b, .w, .l] source target count"
+);
+
+U_BOOT_CMD(
+ cmp, 4, 1, do_mem_cmp,
+ "memory compare",
+ "[.b, .w, .l] addr1 addr2 count"
+);
+
+#ifndef CONFIG_CRC32_VERIFY
+
+U_BOOT_CMD(
+ crc32, 4, 1, do_mem_crc,
+ "checksum calculation",
+ "address count [addr]\n - compute CRC32 checksum [save at addr]"
+);
+
+#else /* CONFIG_CRC32_VERIFY */
+
+U_BOOT_CMD(
+ crc32, 5, 1, do_mem_crc,
+ "checksum calculation",
+ "address count [addr]\n - compute CRC32 checksum [save at addr]\n"
+ "-v address count crc\n - verify crc of memory area"
+);
+
+#endif /* CONFIG_CRC32_VERIFY */
+
+U_BOOT_CMD(
+ base, 2, 1, do_mem_base,
+ "print or set address offset",
+ "\n - print address offset for memory commands\n"
+ "base off\n - set address offset for memory commands to 'off'"
+);
+
+U_BOOT_CMD(
+ loop, 3, 1, do_mem_loop,
+ "infinite loop on address range",
+ "[.b, .w, .l] address number_of_objects"
+);
+
+#ifdef CONFIG_LOOPW
+U_BOOT_CMD(
+ loopw, 4, 1, do_mem_loopw,
+ "infinite write loop on address range",
+ "[.b, .w, .l] address number_of_objects data_to_write"
+);
+#endif /* CONFIG_LOOPW */
+
+U_BOOT_CMD(
+ mtest, 5, 1, do_mem_mtest,
+ "simple RAM read/write test",
+ "[start [end [pattern [iterations]]]]"
+);
+
+#ifdef CONFIG_MX_CYCLIC
+U_BOOT_CMD(
+ mdc, 4, 1, do_mem_mdc,
+ "memory display cyclic",
+ "[.b, .w, .l] address count delay(ms)"
+);
+
+U_BOOT_CMD(
+ mwc, 4, 1, do_mem_mwc,
+ "memory write cyclic",
+ "[.b, .w, .l] address value delay(ms)"
+);
+#endif /* CONFIG_MX_CYCLIC */
+
+#ifdef CONFIG_CMD_MD5SUM
+U_BOOT_CMD(
+ md5sum, 3, 1, do_md5sum,
+ "compute MD5 message digest",
+ "address count"
+);
+#endif
+
+#ifdef CONFIG_CMD_SHA1SUM
+U_BOOT_CMD(
+ sha1sum, 3, 1, do_sha1sum,
+ "compute SHA1 message digest",
+ "address count"
+);
+#endif /* CONFIG_CMD_SHA1SUM */
+
+#ifdef CONFIG_CMD_UNZIP
+U_BOOT_CMD(
+ unzip, 4, 1, do_unzip,
+ "unzip a memory region",
+ "srcaddr dstaddr [dstsize]"
+);
+#endif /* CONFIG_CMD_UNZIP */
diff --git a/u-boot/common/cmd_mfsl.c b/u-boot/common/cmd_mfsl.c
new file mode 100644
index 0000000..00180b0
--- /dev/null
+++ b/u-boot/common/cmd_mfsl.c
@@ -0,0 +1,404 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * 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
+ */
+
+/*
+ * Microblaze FSL support
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <asm/asm.h>
+
+int do_frd (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned int fslnum;
+ unsigned int num;
+ unsigned int blocking;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ fslnum = (unsigned int)simple_strtoul (argv[1], NULL, 16);
+ blocking = (unsigned int)simple_strtoul (argv[2], NULL, 16);
+ if (fslnum < 0 || fslnum >= XILINX_FSL_NUMBER) {
+ puts ("Bad number of FSL\n");
+ return cmd_usage(cmdtp);
+ }
+
+ switch (fslnum) {
+#if (XILINX_FSL_NUMBER > 0)
+ case 0:
+ switch (blocking) {
+ case 0: NGET (num, 0);
+ break;
+ case 1: NCGET (num, 0);
+ break;
+ case 2: GET (num, 0);
+ break;
+ case 3: CGET (num, 0);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 1)
+ case 1:
+ switch (blocking) {
+ case 0: NGET (num, 1);
+ break;
+ case 1: NCGET (num, 1);
+ break;
+ case 2: GET (num, 1);
+ break;
+ case 3: CGET (num, 1);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 2)
+ case 2:
+ switch (blocking) {
+ case 0: NGET (num, 2);
+ break;
+ case 1: NCGET (num, 2);
+ break;
+ case 2: GET (num, 2);
+ break;
+ case 3: CGET (num, 2);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 3)
+ case 3:
+ switch (blocking) {
+ case 0: NGET (num, 3);
+ break;
+ case 1: NCGET (num, 3);
+ break;
+ case 2: GET (num, 3);
+ break;
+ case 3: CGET (num, 3);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 4)
+ case 4:
+ switch (blocking) {
+ case 0: NGET (num, 4);
+ break;
+ case 1: NCGET (num, 4);
+ break;
+ case 2: GET (num, 4);
+ break;
+ case 3: CGET (num, 4);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 5)
+ case 5:
+ switch (blocking) {
+ case 0: NGET (num, 5);
+ break;
+ case 1: NCGET (num, 5);
+ break;
+ case 2: GET (num, 5);
+ break;
+ case 3: CGET (num, 5);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 6)
+ case 6:
+ switch (blocking) {
+ case 0: NGET (num, 6);
+ break;
+ case 1: NCGET (num, 6);
+ break;
+ case 2: GET (num, 6);
+ break;
+ case 3: CGET (num, 6);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 7)
+ case 7:
+ switch (blocking) {
+ case 0: NGET (num, 7);
+ break;
+ case 1: NCGET (num, 7);
+ break;
+ case 2: GET (num, 7);
+ break;
+ case 3: CGET (num, 7);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+ default:
+ return 1;
+ }
+
+ printf ("%01x: 0x%08x - %s %s read\n", fslnum, num,
+ blocking < 2 ? "non blocking" : "blocking",
+ ((blocking == 1) || (blocking == 3)) ? "control" : "data" );
+ return 0;
+}
+
+int do_fwr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned int fslnum;
+ unsigned int num;
+ unsigned int blocking;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ fslnum = (unsigned int)simple_strtoul (argv[1], NULL, 16);
+ num = (unsigned int)simple_strtoul (argv[2], NULL, 16);
+ blocking = (unsigned int)simple_strtoul (argv[3], NULL, 16);
+ if (fslnum < 0 || fslnum >= XILINX_FSL_NUMBER)
+ return cmd_usage(cmdtp);
+
+ switch (fslnum) {
+#if (XILINX_FSL_NUMBER > 0)
+ case 0:
+ switch (blocking) {
+ case 0: NPUT (num, 0);
+ break;
+ case 1: NCPUT (num, 0);
+ break;
+ case 2: PUT (num, 0);
+ break;
+ case 3: CPUT (num, 0);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 1)
+ case 1:
+ switch (blocking) {
+ case 0: NPUT (num, 1);
+ break;
+ case 1: NCPUT (num, 1);
+ break;
+ case 2: PUT (num, 1);
+ break;
+ case 3: CPUT (num, 1);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 2)
+ case 2:
+ switch (blocking) {
+ case 0: NPUT (num, 2);
+ break;
+ case 1: NCPUT (num, 2);
+ break;
+ case 2: PUT (num, 2);
+ break;
+ case 3: CPUT (num, 2);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 3)
+ case 3:
+ switch (blocking) {
+ case 0: NPUT (num, 3);
+ break;
+ case 1: NCPUT (num, 3);
+ break;
+ case 2: PUT (num, 3);
+ break;
+ case 3: CPUT (num, 3);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 4)
+ case 4:
+ switch (blocking) {
+ case 0: NPUT (num, 4);
+ break;
+ case 1: NCPUT (num, 4);
+ break;
+ case 2: PUT (num, 4);
+ break;
+ case 3: CPUT (num, 4);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 5)
+ case 5:
+ switch (blocking) {
+ case 0: NPUT (num, 5);
+ break;
+ case 1: NCPUT (num, 5);
+ break;
+ case 2: PUT (num, 5);
+ break;
+ case 3: CPUT (num, 5);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 6)
+ case 6:
+ switch (blocking) {
+ case 0: NPUT (num, 6);
+ break;
+ case 1: NCPUT (num, 6);
+ break;
+ case 2: PUT (num, 6);
+ break;
+ case 3: CPUT (num, 6);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+#if (XILINX_FSL_NUMBER > 7)
+ case 7:
+ switch (blocking) {
+ case 0: NPUT (num, 7);
+ break;
+ case 1: NCPUT (num, 7);
+ break;
+ case 2: PUT (num, 7);
+ break;
+ case 3: CPUT (num, 7);
+ break;
+ default:
+ return 2;
+ }
+ break;
+#endif
+ default:
+ return 1;
+ }
+
+ printf ("%01x: 0x%08x - %s %s write\n", fslnum, num,
+ blocking < 2 ? "non blocking" : "blocking",
+ ((blocking == 1) || (blocking == 3)) ? "control" : "data" );
+ return 0;
+
+}
+
+int do_rspr (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned int reg = 0;
+ unsigned int val = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ reg = (unsigned int)simple_strtoul (argv[1], NULL, 16);
+ val = (unsigned int)simple_strtoul (argv[2], NULL, 16);
+ switch (reg) {
+ case 0x1:
+ if (argc > 2) {
+ MTS (val, rmsr);
+ NOP;
+ MFS (val, rmsr);
+ } else {
+ MFS (val, rmsr);
+ }
+ puts ("MSR");
+ break;
+ case 0x3:
+ MFS (val, rear);
+ puts ("EAR");
+ break;
+ case 0x5:
+ MFS (val, resr);
+ puts ("ESR");
+ break;
+ default:
+ puts ("Unsupported register\n");
+ return 1;
+ }
+ printf (": 0x%08x\n", val);
+ return 0;
+}
+
+/***************************************************/
+
+U_BOOT_CMD (frd, 3, 1, do_frd,
+ "read data from FSL",
+ "- [fslnum [0|1|2|3]]\n"
+ " 0 - non blocking data read\n"
+ " 1 - non blocking control read\n"
+ " 2 - blocking data read\n"
+ " 3 - blocking control read");
+
+U_BOOT_CMD (fwr, 4, 1, do_fwr,
+ "write data to FSL",
+ "- [fslnum [0|1|2|3]]\n"
+ " 0 - non blocking data write\n"
+ " 1 - non blocking control write\n"
+ " 2 - blocking data write\n"
+ " 3 - blocking control write");
+
+U_BOOT_CMD (rspr, 3, 1, do_rspr,
+ "read/write special purpose register",
+ "- reg_num [write value] read/write special purpose register\n"
+ " 1 - MSR - Machine status register\n"
+ " 3 - EAR - Exception address register\n"
+ " 5 - ESR - Exception status register");
diff --git a/u-boot/common/cmd_mgdisk.c b/u-boot/common/cmd_mgdisk.c
new file mode 100644
index 0000000..d99af2d
--- /dev/null
+++ b/u-boot/common/cmd_mgdisk.c
@@ -0,0 +1,71 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75@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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include <mg_disk.h>
+
+int do_mg_disk_cmd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u32 from, to, size;
+
+ switch (argc) {
+ case 2:
+ if (!strcmp(argv[1], "init"))
+ mg_disk_init();
+ else
+ return 1;
+ break;
+ case 5:
+ from = simple_strtoul(argv[2], NULL, 0);
+ to = simple_strtoul(argv[3], NULL, 0);
+ size = simple_strtoul(argv[4], NULL, 0);
+
+ if (!strcmp(argv[1], "read"))
+ mg_disk_read(from, (u8 *)to, size);
+ else if (!strcmp(argv[1], "write"))
+ mg_disk_write(to, (u8 *)from, size);
+ else if (!strcmp(argv[1], "readsec"))
+ mg_disk_read_sects((void *)to, from, size);
+ else if (!strcmp(argv[1], "writesec"))
+ mg_disk_write_sects((void *)from, to, size);
+ else
+ return 1;
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ return 0;
+}
+
+U_BOOT_CMD(
+ mgd, 5, 0, do_mg_disk_cmd,
+ "mgine m[g]flash command\n",
+ ": mgine mflash IO mode (disk) command\n"
+ " - initialize : mgd init\n"
+ " - random read : mgd read [from] [to] [size]\n"
+ " - random write : mgd write [from] [to] [size]\n"
+ " - sector read : mgd readsec [sector] [to] [counts]\n"
+ " - sector write : mgd writesec [from] [sector] [counts]"
+);
diff --git a/u-boot/common/cmd_mii.c b/u-boot/common/cmd_mii.c
new file mode 100644
index 0000000..23b723e
--- /dev/null
+++ b/u-boot/common/cmd_mii.c
@@ -0,0 +1,452 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MII Utilities
+ */
+
+#include <common.h>
+#include <command.h>
+#include <miiphy.h>
+
+typedef struct _MII_reg_desc_t {
+ ushort regno;
+ char * name;
+} MII_reg_desc_t;
+
+static const MII_reg_desc_t reg_0_5_desc_tbl[] = {
+ { MII_BMCR, "PHY control register" },
+ { MII_BMSR, "PHY status register" },
+ { MII_PHYSID1, "PHY ID 1 register" },
+ { MII_PHYSID2, "PHY ID 2 register" },
+ { MII_ADVERTISE, "Autonegotiation advertisement register" },
+ { MII_LPA, "Autonegotiation partner abilities register" },
+};
+
+typedef struct _MII_field_desc_t {
+ ushort hi;
+ ushort lo;
+ ushort mask;
+ char * name;
+} MII_field_desc_t;
+
+static const MII_field_desc_t reg_0_desc_tbl[] = {
+ { 15, 15, 0x01, "reset" },
+ { 14, 14, 0x01, "loopback" },
+ { 13, 6, 0x81, "speed selection" }, /* special */
+ { 12, 12, 0x01, "A/N enable" },
+ { 11, 11, 0x01, "power-down" },
+ { 10, 10, 0x01, "isolate" },
+ { 9, 9, 0x01, "restart A/N" },
+ { 8, 8, 0x01, "duplex" }, /* special */
+ { 7, 7, 0x01, "collision test enable" },
+ { 5, 0, 0x3f, "(reserved)" }
+};
+
+static const MII_field_desc_t reg_1_desc_tbl[] = {
+ { 15, 15, 0x01, "100BASE-T4 able" },
+ { 14, 14, 0x01, "100BASE-X full duplex able" },
+ { 13, 13, 0x01, "100BASE-X half duplex able" },
+ { 12, 12, 0x01, "10 Mbps full duplex able" },
+ { 11, 11, 0x01, "10 Mbps half duplex able" },
+ { 10, 10, 0x01, "100BASE-T2 full duplex able" },
+ { 9, 9, 0x01, "100BASE-T2 half duplex able" },
+ { 8, 8, 0x01, "extended status" },
+ { 7, 7, 0x01, "(reserved)" },
+ { 6, 6, 0x01, "MF preamble suppression" },
+ { 5, 5, 0x01, "A/N complete" },
+ { 4, 4, 0x01, "remote fault" },
+ { 3, 3, 0x01, "A/N able" },
+ { 2, 2, 0x01, "link status" },
+ { 1, 1, 0x01, "jabber detect" },
+ { 0, 0, 0x01, "extended capabilities" },
+};
+
+static const MII_field_desc_t reg_2_desc_tbl[] = {
+ { 15, 0, 0xffff, "OUI portion" },
+};
+
+static const MII_field_desc_t reg_3_desc_tbl[] = {
+ { 15, 10, 0x3f, "OUI portion" },
+ { 9, 4, 0x3f, "manufacturer part number" },
+ { 3, 0, 0x0f, "manufacturer rev. number" },
+};
+
+static const MII_field_desc_t reg_4_desc_tbl[] = {
+ { 15, 15, 0x01, "next page able" },
+ { 14, 14, 0x01, "reserved" },
+ { 13, 13, 0x01, "remote fault" },
+ { 12, 12, 0x01, "reserved" },
+ { 11, 11, 0x01, "asymmetric pause" },
+ { 10, 10, 0x01, "pause enable" },
+ { 9, 9, 0x01, "100BASE-T4 able" },
+ { 8, 8, 0x01, "100BASE-TX full duplex able" },
+ { 7, 7, 0x01, "100BASE-TX able" },
+ { 6, 6, 0x01, "10BASE-T full duplex able" },
+ { 5, 5, 0x01, "10BASE-T able" },
+ { 4, 0, 0x1f, "xxx to do" },
+};
+
+static const MII_field_desc_t reg_5_desc_tbl[] = {
+ { 15, 15, 0x01, "next page able" },
+ { 14, 14, 0x01, "acknowledge" },
+ { 13, 13, 0x01, "remote fault" },
+ { 12, 12, 0x01, "(reserved)" },
+ { 11, 11, 0x01, "asymmetric pause able" },
+ { 10, 10, 0x01, "pause able" },
+ { 9, 9, 0x01, "100BASE-T4 able" },
+ { 8, 8, 0x01, "100BASE-X full duplex able" },
+ { 7, 7, 0x01, "100BASE-TX able" },
+ { 6, 6, 0x01, "10BASE-T full duplex able" },
+ { 5, 5, 0x01, "10BASE-T able" },
+ { 4, 0, 0x1f, "xxx to do" },
+};
+typedef struct _MII_field_desc_and_len_t {
+ const MII_field_desc_t *pdesc;
+ ushort len;
+} MII_field_desc_and_len_t;
+
+static const MII_field_desc_and_len_t desc_and_len_tbl[] = {
+ { reg_0_desc_tbl, ARRAY_SIZE(reg_0_desc_tbl) },
+ { reg_1_desc_tbl, ARRAY_SIZE(reg_1_desc_tbl) },
+ { reg_2_desc_tbl, ARRAY_SIZE(reg_2_desc_tbl) },
+ { reg_3_desc_tbl, ARRAY_SIZE(reg_3_desc_tbl) },
+ { reg_4_desc_tbl, ARRAY_SIZE(reg_4_desc_tbl) },
+ { reg_5_desc_tbl, ARRAY_SIZE(reg_5_desc_tbl) },
+};
+
+static void dump_reg(
+ ushort regval,
+ const MII_reg_desc_t *prd,
+ const MII_field_desc_and_len_t *pdl);
+
+static int special_field(
+ ushort regno,
+ const MII_field_desc_t *pdesc,
+ ushort regval);
+
+static void MII_dump_0_to_5(
+ ushort regvals[6],
+ uchar reglo,
+ uchar reghi)
+{
+ ulong i;
+
+ for (i = 0; i < 6; i++) {
+ if ((reglo <= i) && (i <= reghi))
+ dump_reg(regvals[i], &reg_0_5_desc_tbl[i],
+ &desc_and_len_tbl[i]);
+ }
+}
+
+static void dump_reg(
+ ushort regval,
+ const MII_reg_desc_t *prd,
+ const MII_field_desc_and_len_t *pdl)
+{
+ ulong i;
+ ushort mask_in_place;
+ const MII_field_desc_t *pdesc;
+
+ printf("%u. (%04hx) -- %s --\n",
+ prd->regno, regval, prd->name);
+
+ for (i = 0; i < pdl->len; i++) {
+ pdesc = &pdl->pdesc[i];
+
+ mask_in_place = pdesc->mask << pdesc->lo;
+
+ printf(" (%04hx:%04hx) %u.",
+ mask_in_place,
+ regval & mask_in_place,
+ prd->regno);
+
+ if (special_field(prd->regno, pdesc, regval)) {
+ }
+ else {
+ if (pdesc->hi == pdesc->lo)
+ printf("%2u ", pdesc->lo);
+ else
+ printf("%2u-%2u", pdesc->hi, pdesc->lo);
+ printf(" = %5u %s",
+ (regval & mask_in_place) >> pdesc->lo,
+ pdesc->name);
+ }
+ printf("\n");
+
+ }
+ printf("\n");
+}
+
+/* Special fields:
+** 0.6,13
+** 0.8
+** 2.15-0
+** 3.15-0
+** 4.4-0
+** 5.4-0
+*/
+
+static int special_field(
+ ushort regno,
+ const MII_field_desc_t *pdesc,
+ ushort regval)
+{
+ if ((regno == MII_BMCR) && (pdesc->lo == 6)) {
+ ushort speed_bits = regval & (BMCR_SPEED1000 | BMCR_SPEED100);
+ printf("%2u,%2u = b%u%u speed selection = %s Mbps",
+ 6, 13,
+ (regval >> 6) & 1,
+ (regval >> 13) & 1,
+ speed_bits == BMCR_SPEED1000 ? "1000" :
+ speed_bits == BMCR_SPEED100 ? "100" :
+ "10");
+ return 1;
+ }
+
+ else if ((regno == MII_BMCR) && (pdesc->lo == 8)) {
+ printf("%2u = %5u duplex = %s",
+ pdesc->lo,
+ (regval >> pdesc->lo) & 1,
+ ((regval >> pdesc->lo) & 1) ? "full" : "half");
+ return 1;
+ }
+
+ else if ((regno == MII_ADVERTISE) && (pdesc->lo == 0)) {
+ ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
+ printf("%2u-%2u = %5u selector = %s",
+ pdesc->hi, pdesc->lo, sel_bits,
+ sel_bits == PHY_ANLPAR_PSB_802_3 ?
+ "IEEE 802.3" :
+ sel_bits == PHY_ANLPAR_PSB_802_9 ?
+ "IEEE 802.9 ISLAN-16T" :
+ "???");
+ return 1;
+ }
+
+ else if ((regno == MII_LPA) && (pdesc->lo == 0)) {
+ ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
+ printf("%2u-%2u = %u selector = %s",
+ pdesc->hi, pdesc->lo, sel_bits,
+ sel_bits == PHY_ANLPAR_PSB_802_3 ?
+ "IEEE 802.3" :
+ sel_bits == PHY_ANLPAR_PSB_802_9 ?
+ "IEEE 802.9 ISLAN-16T" :
+ "???");
+ return 1;
+ }
+
+ return 0;
+}
+
+static char last_op[2];
+static uint last_data;
+static uint last_addr_lo;
+static uint last_addr_hi;
+static uint last_reg_lo;
+static uint last_reg_hi;
+
+static void extract_range(
+ char * input,
+ unsigned char * plo,
+ unsigned char * phi)
+{
+ char * end;
+ *plo = simple_strtoul(input, &end, 16);
+ if (*end == '-') {
+ end++;
+ *phi = simple_strtoul(end, NULL, 16);
+ }
+ else {
+ *phi = *plo;
+ }
+}
+
+/* ---------------------------------------------------------------- */
+static int do_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char op[2];
+ unsigned char addrlo, addrhi, reglo, reghi;
+ unsigned char addr, reg;
+ unsigned short data;
+ int rcode = 0;
+ const char *devname;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+#if defined(CONFIG_MII_INIT)
+ mii_init ();
+#endif
+
+ /*
+ * We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ op[0] = last_op[0];
+ op[1] = last_op[1];
+ addrlo = last_addr_lo;
+ addrhi = last_addr_hi;
+ reglo = last_reg_lo;
+ reghi = last_reg_hi;
+ data = last_data;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ op[0] = argv[1][0];
+ if (strlen(argv[1]) > 1)
+ op[1] = argv[1][1];
+ else
+ op[1] = '\0';
+
+ if (argc >= 3)
+ extract_range(argv[2], &addrlo, &addrhi);
+ if (argc >= 4)
+ extract_range(argv[3], &reglo, &reghi);
+ if (argc >= 5)
+ data = simple_strtoul (argv[4], NULL, 16);
+ }
+
+ /* use current device */
+ devname = miiphy_get_current_dev();
+
+ /*
+ * check info/read/write.
+ */
+ if (op[0] == 'i') {
+ unsigned char j, start, end;
+ unsigned int oui;
+ unsigned char model;
+ unsigned char rev;
+
+ /*
+ * Look for any and all PHYs. Valid addresses are 0..31.
+ */
+ if (argc >= 3) {
+ start = addrlo; end = addrhi;
+ } else {
+ start = 0; end = 31;
+ }
+
+ for (j = start; j <= end; j++) {
+ if (miiphy_info (devname, j, &oui, &model, &rev) == 0) {
+ printf("PHY 0x%02X: "
+ "OUI = 0x%04X, "
+ "Model = 0x%02X, "
+ "Rev = 0x%02X, "
+ "%3dbase%s, %s\n",
+ j, oui, model, rev,
+ miiphy_speed (devname, j),
+ miiphy_is_1000base_x (devname, j)
+ ? "X" : "T",
+ (miiphy_duplex (devname, j) == FULL)
+ ? "FDX" : "HDX");
+ }
+ }
+ } else if (op[0] == 'r') {
+ for (addr = addrlo; addr <= addrhi; addr++) {
+ for (reg = reglo; reg <= reghi; reg++) {
+ data = 0xffff;
+ if (miiphy_read (devname, addr, reg, &data) != 0) {
+ printf(
+ "Error reading from the PHY addr=%02x reg=%02x\n",
+ addr, reg);
+ rcode = 1;
+ } else {
+ if ((addrlo != addrhi) || (reglo != reghi))
+ printf("addr=%02x reg=%02x data=",
+ (uint)addr, (uint)reg);
+ printf("%04X\n", data & 0x0000FFFF);
+ }
+ }
+ if ((addrlo != addrhi) && (reglo != reghi))
+ printf("\n");
+ }
+ } else if (op[0] == 'w') {
+ for (addr = addrlo; addr <= addrhi; addr++) {
+ for (reg = reglo; reg <= reghi; reg++) {
+ if (miiphy_write (devname, addr, reg, data) != 0) {
+ printf("Error writing to the PHY addr=%02x reg=%02x\n",
+ addr, reg);
+ rcode = 1;
+ }
+ }
+ }
+ } else if (strncmp(op, "du", 2) == 0) {
+ ushort regs[6];
+ int ok = 1;
+ if ((reglo > 5) || (reghi > 5)) {
+ printf(
+ "The MII dump command only formats the "
+ "standard MII registers, 0-5.\n");
+ return 1;
+ }
+ for (addr = addrlo; addr <= addrhi; addr++) {
+ for (reg = reglo; reg < reghi + 1; reg++) {
+ if (miiphy_read(devname, addr, reg, &regs[reg]) != 0) {
+ ok = 0;
+ printf(
+ "Error reading from the PHY addr=%02x reg=%02x\n",
+ addr, reg);
+ rcode = 1;
+ }
+ }
+ if (ok)
+ MII_dump_0_to_5(regs, reglo, reghi);
+ printf("\n");
+ }
+ } else if (strncmp(op, "de", 2) == 0) {
+ if (argc == 2)
+ miiphy_listdev ();
+ else
+ miiphy_set_current_dev (argv[2]);
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ /*
+ * Save the parameters for repeats.
+ */
+ last_op[0] = op[0];
+ last_op[1] = op[1];
+ last_addr_lo = addrlo;
+ last_addr_hi = addrhi;
+ last_reg_lo = reglo;
+ last_reg_hi = reghi;
+ last_data = data;
+
+ return rcode;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ mii, 5, 1, do_mii,
+ "MII utility commands",
+ "device - list available devices\n"
+ "mii device <devname> - set current device\n"
+ "mii info <addr> - display MII PHY info\n"
+ "mii read <addr> <reg> - read MII PHY <addr> register <reg>\n"
+ "mii write <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
+ "mii dump <addr> <reg> - pretty-print <addr> <reg> (0-5 only)\n"
+ "Addr and/or reg may be ranges, e.g. 2-7."
+);
diff --git a/u-boot/common/cmd_misc.c b/u-boot/common/cmd_misc.c
new file mode 100644
index 0000000..061b1bb
--- /dev/null
+++ b/u-boot/common/cmd_misc.c
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Misc functions
+ */
+#include <common.h>
+#include <command.h>
+
+int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong start = get_timer(0);
+ ulong delay;
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+ delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ;
+
+ while (get_timer(start) < delay) {
+ if (ctrlc ())
+ return (-1);
+
+ udelay (100);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ sleep , 2, 1, do_sleep,
+ "delay execution for some time",
+ "N\n"
+ " - delay execution for N seconds (N is _decimal_ !!!)"
+);
diff --git a/u-boot/common/cmd_mmc.c b/u-boot/common/cmd_mmc.c
new file mode 100644
index 0000000..4323f76
--- /dev/null
+++ b/u-boot/common/cmd_mmc.c
@@ -0,0 +1,251 @@
+/*
+ * (C) Copyright 2003
+ * Kyle Harris, kharris@nexus-tech.net
+ *
+ * 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 <mmc.h>
+
+#ifndef CONFIG_GENERIC_MMC
+static int curr_device = -1;
+
+int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int dev;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "init") == 0) {
+ if (argc == 2) {
+ if (curr_device < 0)
+ dev = 1;
+ else
+ dev = curr_device;
+ } else if (argc == 3) {
+ dev = (int)simple_strtoul(argv[2], NULL, 10);
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ if (mmc_legacy_init(dev) != 0) {
+ puts("No MMC card found\n");
+ return 1;
+ }
+
+ curr_device = dev;
+ printf("mmc%d is available\n", curr_device);
+ } else if (strcmp(argv[1], "device") == 0) {
+ if (argc == 2) {
+ if (curr_device < 0) {
+ puts("No MMC device available\n");
+ return 1;
+ }
+ } else if (argc == 3) {
+ dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+#ifdef CONFIG_SYS_MMC_SET_DEV
+ if (mmc_set_dev(dev) != 0)
+ return 1;
+#endif
+ curr_device = dev;
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ printf("mmc%d is current device\n", curr_device);
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ mmc, 3, 1, do_mmc,
+ "MMC sub-system",
+ "init [dev] - init MMC sub system\n"
+ "mmc device [dev] - show or set current device"
+);
+#else /* !CONFIG_GENERIC_MMC */
+
+static void print_mmcinfo(struct mmc *mmc)
+{
+ printf("Device: %s\n", mmc->name);
+ printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24);
+ printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff);
+ printf("Name: %c%c%c%c%c \n", mmc->cid[0] & 0xff,
+ (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
+ (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
+
+ printf("Tran Speed: %d\n", mmc->tran_speed);
+ printf("Rd Block Len: %d\n", mmc->read_bl_len);
+
+ printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC",
+ (mmc->version >> 4) & 0xf, mmc->version & 0xf);
+
+ printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No");
+ printf("Capacity: %lld\n", mmc->capacity);
+
+ printf("Bus Width: %d-bit\n", mmc->bus_width);
+}
+
+int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct mmc *mmc;
+ int dev_num;
+
+ if (argc < 2)
+ dev_num = 0;
+ else
+ dev_num = simple_strtoul(argv[1], NULL, 0);
+
+ mmc = find_mmc_device(dev_num);
+
+ if (mmc) {
+ mmc_init(mmc);
+
+ print_mmcinfo(mmc);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ mmcinfo, 2, 0, do_mmcinfo,
+ "display MMC info",
+ "<dev num>\n"
+ " - device number of the device to dislay info of\n"
+ ""
+);
+
+int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int rc = 0;
+
+ switch (argc) {
+ case 3:
+ if (strcmp(argv[1], "rescan") == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ struct mmc *mmc = find_mmc_device(dev);
+
+ if (!mmc)
+ return 1;
+
+ mmc_init(mmc);
+
+ return 0;
+ } else if (strncmp(argv[1], "part", 4) == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ block_dev_desc_t *mmc_dev;
+ struct mmc *mmc = find_mmc_device(dev);
+
+ if (!mmc) {
+ puts("no mmc devices available\n");
+ return 1;
+ }
+ mmc_init(mmc);
+ mmc_dev = mmc_get_dev(dev);
+ if (mmc_dev != NULL &&
+ mmc_dev->type != DEV_TYPE_UNKNOWN) {
+ print_part(mmc_dev);
+ return 0;
+ }
+
+ puts("get mmc type error!\n");
+ return 1;
+ }
+
+ case 0:
+ case 1:
+ case 4:
+ return cmd_usage(cmdtp);
+
+ case 2:
+ if (!strcmp(argv[1], "list")) {
+ print_mmc_devices('\n');
+ return 0;
+ }
+ return 1;
+ default: /* at least 5 args */
+ if (strcmp(argv[1], "read") == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ void *addr = (void *)simple_strtoul(argv[3], NULL, 16);
+ u32 cnt = simple_strtoul(argv[5], NULL, 16);
+ u32 n;
+ u32 blk = simple_strtoul(argv[4], NULL, 16);
+ struct mmc *mmc = find_mmc_device(dev);
+
+ if (!mmc)
+ return 1;
+
+ printf("\nMMC read: dev # %d, block # %d, count %d ... ",
+ dev, blk, cnt);
+
+ mmc_init(mmc);
+
+ n = mmc->block_dev.block_read(dev, blk, cnt, addr);
+
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512); /* FIXME */
+
+ printf("%d blocks read: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ return (n == cnt) ? 0 : 1;
+ } else if (strcmp(argv[1], "write") == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ void *addr = (void *)simple_strtoul(argv[3], NULL, 16);
+ u32 cnt = simple_strtoul(argv[5], NULL, 16);
+ u32 n;
+ struct mmc *mmc = find_mmc_device(dev);
+
+ int blk = simple_strtoul(argv[4], NULL, 16);
+
+ if (!mmc)
+ return 1;
+
+ printf("\nMMC write: dev # %d, block # %d, count %d ... ",
+ dev, blk, cnt);
+
+ mmc_init(mmc);
+
+ n = mmc->block_dev.block_write(dev, blk, cnt, addr);
+
+ printf("%d blocks written: %s\n",
+ n, (n == cnt) ? "OK" : "ERROR");
+ return (n == cnt) ? 0 : 1;
+ } else
+ rc = cmd_usage(cmdtp);
+
+ return rc;
+ }
+}
+
+U_BOOT_CMD(
+ mmc, 6, 1, do_mmcops,
+ "MMC sub system",
+ "read <device num> addr blk# cnt\n"
+ "mmc write <device num> addr blk# cnt\n"
+ "mmc rescan <device num>\n"
+ "mmc part <device num> - lists available partition on mmc\n"
+ "mmc list - lists available devices");
+#endif
diff --git a/u-boot/common/cmd_mp.c b/u-boot/common/cmd_mp.c
new file mode 100644
index 0000000..f19bf41
--- /dev/null
+++ b/u-boot/common/cmd_mp.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * 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>
+
+int
+cpu_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long cpuid;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ cpuid = simple_strtoul(argv[1], NULL, 10);
+ if (cpuid >= cpu_numcores()) {
+ printf ("Core num: %lu is out of range[0..%d]\n",
+ cpuid, cpu_numcores() - 1);
+ return 1;
+ }
+
+
+ if (argc == 3) {
+ if (strncmp(argv[2], "reset", 5) == 0)
+ cpu_reset(cpuid);
+ else if (strncmp(argv[2], "status", 6) == 0)
+ cpu_status(cpuid);
+ else if (strncmp(argv[2], "disable", 7) == 0)
+ return cpu_disable(cpuid);
+ else
+ return cmd_usage(cmdtp);
+
+ return 0;
+ }
+
+ /* 4 or greater, make sure its release */
+ if (strncmp(argv[2], "release", 7) != 0)
+ return cmd_usage(cmdtp);
+
+ if (cpu_release(cpuid, argc - 3, argv + 3))
+ return cmd_usage(cmdtp);
+
+ return 0;
+}
+
+#ifdef CONFIG_PPC
+#define CPU_ARCH_HELP \
+ " [args] : <pir> <r3> <r6>\n" \
+ " pir - processor id (if writeable)\n" \
+ " r3 - value for gpr 3\n" \
+ " r6 - value for gpr 6\n" \
+ "\n" \
+ " Use '-' for any arg if you want the default value.\n" \
+ " Default for r3 is <num> and r6 is 0\n" \
+ "\n" \
+ " When cpu <num> is released r4 and r5 = 0.\n" \
+ " r7 will contain the size of the initial mapped area"
+#endif
+
+U_BOOT_CMD(
+ cpu, CONFIG_SYS_MAXARGS, 1, cpu_cmd,
+ "Multiprocessor CPU boot manipulation and release",
+ "<num> reset - Reset cpu <num>\n"
+ "cpu <num> status - Status of cpu <num>\n"
+ "cpu <num> disable - Disable cpu <num>\n"
+ "cpu <num> release <addr> [args] - Release cpu <num> at <addr> with [args]"
+#ifdef CPU_ARCH_HELP
+ "\n"
+ CPU_ARCH_HELP
+#endif
+);
diff --git a/u-boot/common/cmd_mtdparts.c b/u-boot/common/cmd_mtdparts.c
new file mode 100644
index 0000000..5481c88
--- /dev/null
+++ b/u-boot/common/cmd_mtdparts.c
@@ -0,0 +1,2092 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
+ *
+ * (C) Copyright 2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Added support for reading flash partition table from environment.
+ * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
+ * kernel tree.
+ *
+ * (C) Copyright 2008
+ * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
+ *
+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * 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
+ */
+
+/*
+ * Three environment variables are used by the parsing routines:
+ *
+ * 'partition' - keeps current partition identifier
+ *
+ * partition := <part-id>
+ * <part-id> := <dev-id>,part_num
+ *
+ *
+ * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
+ *
+ * mtdids=<idmap>[,<idmap>,...]
+ *
+ * <idmap> := <dev-id>=<mtd-id>
+ * <dev-id> := 'nand'|'nor'|'onenand'<dev-num>
+ * <dev-num> := mtd device number, 0...
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ *
+ *
+ * 'mtdparts' - partition list
+ *
+ * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
+ *
+ * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
+ * <size> := standard linux memsize OR '-' to denote all remaining space
+ * <offset> := partition start offset within the device
+ * <name> := '(' NAME ')'
+ * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
+ *
+ * Notes:
+ * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
+ * - if the above variables are not set defaults for a given target are used
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * mtdids=nor0=edb7312-nor
+ * mtdparts=mtdparts=edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
+ * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <jffs2/load_kernel.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+
+#if defined(CONFIG_CMD_NAND)
+#include <linux/mtd/nand.h>
+#include <nand.h>
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+#include <linux/mtd/onenand.h>
+#include <onenand_uboot.h>
+#endif
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xFFFFFFFF
+
+/* special offset value, it is used when not provided by user
+ *
+ * this value is used temporarily during parsing, later such offests
+ * are recalculated */
+#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
+
+/* minimum partition size */
+#define MIN_PART_SIZE 4096
+
+/* this flag needs to be set in part_info struct mask_flags
+ * field for read-only partitions */
+#define MTD_WRITEABLE_CMD 1
+
+/* default values for mtdids and mtdparts variables */
+#if defined(MTDIDS_DEFAULT)
+static const char *const mtdids_default = MTDIDS_DEFAULT;
+#else
+static const char *const mtdids_default = NULL;
+#endif
+
+#if defined(MTDPARTS_DEFAULT)
+static const char *const mtdparts_default = MTDPARTS_DEFAULT;
+#else
+static const char *const mtdparts_default = NULL;
+#endif
+
+/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
+#define MTDIDS_MAXLEN 128
+#define MTDPARTS_MAXLEN 512
+#define PARTITION_MAXLEN 16
+static char last_ids[MTDIDS_MAXLEN];
+static char last_parts[MTDPARTS_MAXLEN];
+static char last_partition[PARTITION_MAXLEN];
+
+/* low level jffs2 cache cleaning routine */
+extern void jffs2_free_cache(struct part_info *part);
+
+/* mtdids mapping list, filled by parse_ids() */
+struct list_head mtdids;
+
+/* device/partition list, parse_cmdline() parses into here */
+struct list_head devices;
+
+/* current active device and partition number */
+struct mtd_device *current_mtd_dev = NULL;
+u8 current_mtd_partnum = 0;
+
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num);
+
+/* command line only routines */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
+static int device_del(struct mtd_device *dev);
+
+/**
+ * Parses a string into a number. The number stored at ptr is
+ * potentially suffixed with K (for kilobytes, or 1024 bytes),
+ * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
+ * 1073741824). If the number is suffixed with K, M, or G, then
+ * the return value is the number multiplied by one kilobyte, one
+ * megabyte, or one gigabyte, respectively.
+ *
+ * @param ptr where parse begins
+ * @param retptr output pointer to next char after parse completes (output)
+ * @return resulting unsigned int
+ */
+static unsigned long memsize_parse (const char *const ptr, const char **retptr)
+{
+ unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
+
+ switch (**retptr) {
+ case 'G':
+ case 'g':
+ ret <<= 10;
+ case 'M':
+ case 'm':
+ ret <<= 10;
+ case 'K':
+ case 'k':
+ ret <<= 10;
+ (*retptr)++;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * Format string describing supplied size. This routine does the opposite job
+ * to memsize_parse(). Size in bytes is converted to string and if possible
+ * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
+ *
+ * Note, that this routine does not check for buffer overflow, it's the caller
+ * who must assure enough space.
+ *
+ * @param buf output buffer
+ * @param size size to be converted to string
+ */
+static void memsize_format(char *buf, u32 size)
+{
+#define SIZE_GB ((u32)1024*1024*1024)
+#define SIZE_MB ((u32)1024*1024)
+#define SIZE_KB ((u32)1024)
+
+ if ((size % SIZE_GB) == 0)
+ sprintf(buf, "%ug", size/SIZE_GB);
+ else if ((size % SIZE_MB) == 0)
+ sprintf(buf, "%um", size/SIZE_MB);
+ else if (size % SIZE_KB == 0)
+ sprintf(buf, "%uk", size/SIZE_KB);
+ else
+ sprintf(buf, "%u", size);
+}
+
+/**
+ * This routine does global indexing of all partitions. Resulting index for
+ * current partition is saved in 'mtddevnum'. Current partition name in
+ * 'mtddevname'.
+ */
+static void index_partitions(void)
+{
+ char buf[16];
+ u16 mtddevnum;
+ struct part_info *part;
+ struct list_head *dentry;
+ struct mtd_device *dev;
+
+ debug("--- index partitions ---\n");
+
+ if (current_mtd_dev) {
+ mtddevnum = 0;
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+ if (dev == current_mtd_dev) {
+ mtddevnum += current_mtd_partnum;
+ sprintf(buf, "%d", mtddevnum);
+ setenv("mtddevnum", buf);
+ break;
+ }
+ mtddevnum += dev->num_parts;
+ }
+
+ part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
+ setenv("mtddevname", part->name);
+
+ debug("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
+ } else {
+ setenv("mtddevnum", NULL);
+ setenv("mtddevname", NULL);
+
+ debug("=> mtddevnum NULL\n=> mtddevname NULL\n");
+ }
+}
+
+/**
+ * Save current device and partition in environment variable 'partition'.
+ */
+static void current_save(void)
+{
+ char buf[16];
+
+ debug("--- current_save ---\n");
+
+ if (current_mtd_dev) {
+ sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_mtd_dev->id->type),
+ current_mtd_dev->id->num, current_mtd_partnum);
+
+ setenv("partition", buf);
+ strncpy(last_partition, buf, 16);
+
+ debug("=> partition %s\n", buf);
+ } else {
+ setenv("partition", NULL);
+ last_partition[0] = '\0';
+
+ debug("=> partition NULL\n");
+ }
+ index_partitions();
+}
+
+
+/**
+ * Produce a mtd_info given a type and num.
+ *
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+ char mtd_dev[16];
+
+ sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+ *mtd = get_mtd_device_nm(mtd_dev);
+ if (IS_ERR(*mtd)) {
+ printf("Device %s not found!\n", mtd_dev);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Performs sanity check for supplied flash partition.
+ * Table of existing MTD flash devices is searched and partition device
+ * is located. Alignment with the granularity of nand erasesize is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
+{
+ struct mtd_info *mtd = NULL;
+ int i, j;
+ ulong start;
+
+ if (get_mtd_info(id->type, id->num, &mtd))
+ return 1;
+
+ part->sector_size = mtd->erasesize;
+
+ if (!mtd->numeraseregions) {
+ /*
+ * Only one eraseregion (NAND, OneNAND or uniform NOR),
+ * checking for alignment is easy here
+ */
+ if ((unsigned long)part->offset % mtd->erasesize) {
+ printf("%s%d: partition (%s) start offset"
+ "alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ if (part->size % mtd->erasesize) {
+ printf("%s%d: partition (%s) size alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+ } else {
+ /*
+ * Multiple eraseregions (non-uniform NOR),
+ * checking for alignment is more complex here
+ */
+
+ /* Check start alignment */
+ for (i = 0; i < mtd->numeraseregions; i++) {
+ start = mtd->eraseregions[i].offset;
+ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
+ if (part->offset == start)
+ goto start_ok;
+ start += mtd->eraseregions[i].erasesize;
+ }
+ }
+
+ printf("%s%d: partition (%s) start offset alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+
+ start_ok:
+
+ /* Check end/size alignment */
+ for (i = 0; i < mtd->numeraseregions; i++) {
+ start = mtd->eraseregions[i].offset;
+ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
+ if ((part->offset + part->size) == start)
+ goto end_ok;
+ start += mtd->eraseregions[i].erasesize;
+ }
+ }
+ /* Check last sector alignment */
+ if ((part->offset + part->size) == start)
+ goto end_ok;
+
+ printf("%s%d: partition (%s) size alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+
+ end_ok:
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Performs sanity check for supplied partition. Offset and size are verified
+ * to be within valid range. Partition type is checked and either
+ * parts_validate_nor() or parts_validate_nand() is called with the argument
+ * of part.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate(struct mtdids *id, struct part_info *part)
+{
+ if (part->size == SIZE_REMAINING)
+ part->size = id->size - part->offset;
+
+ if (part->offset > id->size) {
+ printf("%s: offset %08x beyond flash size %08x\n",
+ id->mtd_id, part->offset, id->size);
+ return 1;
+ }
+
+ if ((part->offset + part->size) <= part->offset) {
+ printf("%s%d: partition (%s) size too big\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ if (part->offset + part->size > id->size) {
+ printf("%s: partitioning exceeds flash size\n", id->mtd_id);
+ return 1;
+ }
+
+ /*
+ * Now we need to check if the partition starts and ends on
+ * sector (eraseblock) regions
+ */
+ return part_validate_eraseblock(id, part);
+}
+
+/**
+ * Delete selected partition from the partion list of the specified device.
+ *
+ * @param dev device to delete partition from
+ * @param part partition to delete
+ * @return 0 on success, 1 otherwise
+ */
+static int part_del(struct mtd_device *dev, struct part_info *part)
+{
+ u8 current_save_needed = 0;
+
+ /* if there is only one partition, remove whole device */
+ if (dev->num_parts == 1)
+ return device_del(dev);
+
+ /* otherwise just delete this partition */
+
+ if (dev == current_mtd_dev) {
+ /* we are modyfing partitions for the current device,
+ * update current */
+ struct part_info *curr_pi;
+ curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum);
+
+ if (curr_pi) {
+ if (curr_pi == part) {
+ printf("current partition deleted, resetting current to 0\n");
+ current_mtd_partnum = 0;
+ } else if (part->offset <= curr_pi->offset) {
+ current_mtd_partnum--;
+ }
+ current_save_needed = 1;
+ }
+ }
+
+ list_del(&part->link);
+ free(part);
+ dev->num_parts--;
+
+ if (current_save_needed > 0)
+ current_save();
+ else
+ index_partitions();
+
+ return 0;
+}
+
+/**
+ * Delete all partitions from parts head list, free memory.
+ *
+ * @param head list of partitions to delete
+ */
+static void part_delall(struct list_head *head)
+{
+ struct list_head *entry, *n;
+ struct part_info *part_tmp;
+
+ /* clean tmp_list and free allocated memory */
+ list_for_each_safe(entry, n, head) {
+ part_tmp = list_entry(entry, struct part_info, link);
+
+ list_del(entry);
+ free(part_tmp);
+ }
+}
+
+/**
+ * Add new partition to the supplied partition list. Make sure partitions are
+ * sorted by offset in ascending order.
+ *
+ * @param head list this partition is to be added to
+ * @param new partition to be added
+ */
+static int part_sort_add(struct mtd_device *dev, struct part_info *part)
+{
+ struct list_head *entry;
+ struct part_info *new_pi, *curr_pi;
+
+ /* link partition to parrent dev */
+ part->dev = dev;
+
+ if (list_empty(&dev->parts)) {
+ debug("part_sort_add: list empty\n");
+ list_add(&part->link, &dev->parts);
+ dev->num_parts++;
+ index_partitions();
+ return 0;
+ }
+
+ new_pi = list_entry(&part->link, struct part_info, link);
+
+ /* get current partition info if we are updating current device */
+ curr_pi = NULL;
+ if (dev == current_mtd_dev)
+ curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum);
+
+ list_for_each(entry, &dev->parts) {
+ struct part_info *pi;
+
+ pi = list_entry(entry, struct part_info, link);
+
+ /* be compliant with kernel cmdline, allow only one partition at offset zero */
+ if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
+ printf("cannot add second partition at offset 0\n");
+ return 1;
+ }
+
+ if (new_pi->offset <= pi->offset) {
+ list_add_tail(&part->link, entry);
+ dev->num_parts++;
+
+ if (curr_pi && (pi->offset <= curr_pi->offset)) {
+ /* we are modyfing partitions for the current
+ * device, update current */
+ current_mtd_partnum++;
+ current_save();
+ } else {
+ index_partitions();
+ }
+ return 0;
+ }
+ }
+
+ list_add_tail(&part->link, &dev->parts);
+ dev->num_parts++;
+ index_partitions();
+ return 0;
+}
+
+/**
+ * Add provided partition to the partition list of a given device.
+ *
+ * @param dev device to which partition is added
+ * @param part partition to be added
+ * @return 0 on success, 1 otherwise
+ */
+static int part_add(struct mtd_device *dev, struct part_info *part)
+{
+ /* verify alignment and size */
+ if (part_validate(dev->id, part) != 0)
+ return 1;
+
+ /* partition is ok, add it to the list */
+ if (part_sort_add(dev, part) != 0)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Parse one partition definition, allocate memory and return pointer to this
+ * location in retpart.
+ *
+ * @param partdef pointer to the partition definition string i.e. <part-def>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retpart pointer to the allocated partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
+{
+ struct part_info *part;
+ unsigned long size;
+ unsigned long offset;
+ const char *name;
+ int name_len;
+ unsigned int mask_flags;
+ const char *p;
+
+ p = partdef;
+ *retpart = NULL;
+ *ret = NULL;
+
+ /* fetch the partition size */
+ if (*p == '-') {
+ /* assign all remaining space to this partition */
+ debug("'-': remaining size assigned\n");
+ size = SIZE_REMAINING;
+ p++;
+ } else {
+ size = memsize_parse(p, &p);
+ if (size < MIN_PART_SIZE) {
+ printf("partition size too small (%lx)\n", size);
+ return 1;
+ }
+ }
+
+ /* check for offset */
+ offset = OFFSET_NOT_SPECIFIED;
+ if (*p == '@') {
+ p++;
+ offset = memsize_parse(p, &p);
+ }
+
+ /* now look for the name */
+ if (*p == '(') {
+ name = ++p;
+ if ((p = strchr(name, ')')) == NULL) {
+ printf("no closing ) found in partition name\n");
+ return 1;
+ }
+ name_len = p - name + 1;
+ if ((name_len - 1) == 0) {
+ printf("empty partition name\n");
+ return 1;
+ }
+ p++;
+ } else {
+ /* 0x00000000@0x00000000 */
+ name_len = 22;
+ name = NULL;
+ }
+
+ /* test for options */
+ mask_flags = 0;
+ if (strncmp(p, "ro", 2) == 0) {
+ mask_flags |= MTD_WRITEABLE_CMD;
+ p += 2;
+ }
+
+ /* check for next partition definition */
+ if (*p == ',') {
+ if (size == SIZE_REMAINING) {
+ *ret = NULL;
+ printf("no partitions allowed after a fill-up partition\n");
+ return 1;
+ }
+ *ret = ++p;
+ } else if ((*p == ';') || (*p == '\0')) {
+ *ret = p;
+ } else {
+ printf("unexpected character '%c' at the end of partition\n", *p);
+ *ret = NULL;
+ return 1;
+ }
+
+ /* allocate memory */
+ part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
+ if (!part) {
+ printf("out of memory\n");
+ return 1;
+ }
+ memset(part, 0, sizeof(struct part_info) + name_len);
+ part->size = size;
+ part->offset = offset;
+ part->mask_flags = mask_flags;
+ part->name = (char *)(part + 1);
+
+ if (name) {
+ /* copy user provided name */
+ strncpy(part->name, name, name_len - 1);
+ part->auto_name = 0;
+ } else {
+ /* auto generated name in form of size@offset */
+ sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
+ part->auto_name = 1;
+ }
+
+ part->name[name_len - 1] = '\0';
+ INIT_LIST_HEAD(&part->link);
+
+ debug("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
+ part->name, part->size,
+ part->offset, part->mask_flags);
+
+ *retpart = part;
+ return 0;
+}
+
+/**
+ * Check device number to be within valid range for given device type.
+ *
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+int mtd_device_validate(u8 type, u8 num, u32 *size)
+{
+ struct mtd_info *mtd = NULL;
+
+ if (get_mtd_info(type, num, &mtd))
+ return 1;
+
+ *size = mtd->size;
+
+ return 0;
+}
+
+/**
+ * Delete all mtd devices from a supplied devices list, free memory allocated for
+ * each device and delete all device partitions.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int device_delall(struct list_head *head)
+{
+ struct list_head *entry, *n;
+ struct mtd_device *dev_tmp;
+
+ /* clean devices list */
+ list_for_each_safe(entry, n, head) {
+ dev_tmp = list_entry(entry, struct mtd_device, link);
+ list_del(entry);
+ part_delall(&dev_tmp->parts);
+ free(dev_tmp);
+ }
+ INIT_LIST_HEAD(&devices);
+
+ return 0;
+}
+
+/**
+ * If provided device exists it's partitions are deleted, device is removed
+ * from device list and device memory is freed.
+ *
+ * @param dev device to be deleted
+ * @return 0 on success, 1 otherwise
+ */
+static int device_del(struct mtd_device *dev)
+{
+ part_delall(&dev->parts);
+ list_del(&dev->link);
+ free(dev);
+
+ if (dev == current_mtd_dev) {
+ /* we just deleted current device */
+ if (list_empty(&devices)) {
+ current_mtd_dev = NULL;
+ } else {
+ /* reset first partition from first dev from the
+ * devices list as current */
+ current_mtd_dev = list_entry(devices.next, struct mtd_device, link);
+ current_mtd_partnum = 0;
+ }
+ current_save();
+ return 0;
+ }
+
+ index_partitions();
+ return 0;
+}
+
+/**
+ * Search global device list and return pointer to the device of type and num
+ * specified.
+ *
+ * @param type device type
+ * @param num device number
+ * @return NULL if requested device does not exist
+ */
+struct mtd_device *device_find(u8 type, u8 num)
+{
+ struct list_head *entry;
+ struct mtd_device *dev_tmp;
+
+ list_for_each(entry, &devices) {
+ dev_tmp = list_entry(entry, struct mtd_device, link);
+
+ if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
+ return dev_tmp;
+ }
+
+ return NULL;
+}
+
+/**
+ * Add specified device to the global device list.
+ *
+ * @param dev device to be added
+ */
+static void device_add(struct mtd_device *dev)
+{
+ u8 current_save_needed = 0;
+
+ if (list_empty(&devices)) {
+ current_mtd_dev = dev;
+ current_mtd_partnum = 0;
+ current_save_needed = 1;
+ }
+
+ list_add_tail(&dev->link, &devices);
+
+ if (current_save_needed > 0)
+ current_save();
+ else
+ index_partitions();
+}
+
+/**
+ * Parse device type, name and mtd-id. If syntax is ok allocate memory and
+ * return pointer to the device structure.
+ *
+ * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retdev pointer to the allocated device (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
+{
+ struct mtd_device *dev;
+ struct part_info *part;
+ struct mtdids *id;
+ const char *mtd_id;
+ unsigned int mtd_id_len;
+ const char *p, *pend;
+ LIST_HEAD(tmp_list);
+ struct list_head *entry, *n;
+ u16 num_parts;
+ u32 offset;
+ int err = 1;
+
+ debug("===device_parse===\n");
+
+ assert(retdev);
+ *retdev = NULL;
+
+ if (ret)
+ *ret = NULL;
+
+ /* fetch <mtd-id> */
+ mtd_id = p = mtd_dev;
+ if (!(p = strchr(mtd_id, ':'))) {
+ printf("no <mtd-id> identifier\n");
+ return 1;
+ }
+ mtd_id_len = p - mtd_id + 1;
+ p++;
+
+ /* verify if we have a valid device specified */
+ if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
+ printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
+ return 1;
+ }
+
+ debug("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
+ id->type, MTD_DEV_TYPE(id->type),
+ id->num, id->mtd_id);
+ pend = strchr(p, ';');
+ debug("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
+
+
+ /* parse partitions */
+ num_parts = 0;
+
+ offset = 0;
+ if ((dev = device_find(id->type, id->num)) != NULL) {
+ /* if device already exists start at the end of the last partition */
+ part = list_entry(dev->parts.prev, struct part_info, link);
+ offset = part->offset + part->size;
+ }
+
+ while (p && (*p != '\0') && (*p != ';')) {
+ err = 1;
+ if ((part_parse(p, &p, &part) != 0) || (!part))
+ break;
+
+ /* calculate offset when not specified */
+ if (part->offset == OFFSET_NOT_SPECIFIED)
+ part->offset = offset;
+ else
+ offset = part->offset;
+
+ /* verify alignment and size */
+ if (part_validate(id, part) != 0)
+ break;
+
+ offset += part->size;
+
+ /* partition is ok, add it to the list */
+ list_add_tail(&part->link, &tmp_list);
+ num_parts++;
+ err = 0;
+ }
+ if (err == 1) {
+ part_delall(&tmp_list);
+ return 1;
+ }
+
+ if (num_parts == 0) {
+ printf("no partitions for device %s%d (%s)\n",
+ MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
+ return 1;
+ }
+
+ debug("\ntotal partitions: %d\n", num_parts);
+
+ /* check for next device presence */
+ if (p) {
+ if (*p == ';') {
+ if (ret)
+ *ret = ++p;
+ } else if (*p == '\0') {
+ if (ret)
+ *ret = p;
+ } else {
+ printf("unexpected character '%c' at the end of device\n", *p);
+ if (ret)
+ *ret = NULL;
+ return 1;
+ }
+ }
+
+ /* allocate memory for mtd_device structure */
+ if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
+ printf("out of memory\n");
+ return 1;
+ }
+ memset(dev, 0, sizeof(struct mtd_device));
+ dev->id = id;
+ dev->num_parts = 0; /* part_sort_add increments num_parts */
+ INIT_LIST_HEAD(&dev->parts);
+ INIT_LIST_HEAD(&dev->link);
+
+ /* move partitions from tmp_list to dev->parts */
+ list_for_each_safe(entry, n, &tmp_list) {
+ part = list_entry(entry, struct part_info, link);
+ list_del(entry);
+ if (part_sort_add(dev, part) != 0) {
+ device_del(dev);
+ return 1;
+ }
+ }
+
+ *retdev = dev;
+
+ debug("===\n\n");
+ return 0;
+}
+
+/**
+ * Initialize global device list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int mtd_devices_init(void)
+{
+ last_parts[0] = '\0';
+ current_mtd_dev = NULL;
+ current_save();
+
+ return device_delall(&devices);
+}
+
+/*
+ * Search global mtdids list and find id of requested type and number.
+ *
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find(u8 type, u8 num)
+{
+ struct list_head *entry;
+ struct mtdids *id;
+
+ list_for_each(entry, &mtdids) {
+ id = list_entry(entry, struct mtdids, link);
+
+ if ((id->type == type) && (id->num == num))
+ return id;
+ }
+
+ return NULL;
+}
+
+/**
+ * Search global mtdids list and find id of a requested mtd_id.
+ *
+ * Note: first argument is not null terminated.
+ *
+ * @param mtd_id string containing requested mtd_id
+ * @param mtd_id_len length of supplied mtd_id
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
+{
+ struct list_head *entry;
+ struct mtdids *id;
+
+ debug("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
+ mtd_id_len, mtd_id, mtd_id_len);
+
+ list_for_each(entry, &mtdids) {
+ id = list_entry(entry, struct mtdids, link);
+
+ debug("entry: '%s' (len = %d)\n",
+ id->mtd_id, strlen(id->mtd_id));
+
+ if (mtd_id_len != strlen(id->mtd_id))
+ continue;
+ if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
+ return id;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
+ * return device type and number.
+ *
+ * @param id string describing device id
+ * @param ret_id output pointer to next char after parse completes (output)
+ * @param dev_type parsed device type (output)
+ * @param dev_num parsed device number (output)
+ * @return 0 on success, 1 otherwise
+ */
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+{
+ const char *p = id;
+
+ *dev_type = 0;
+ if (strncmp(p, "nand", 4) == 0) {
+ *dev_type = MTD_DEV_TYPE_NAND;
+ p += 4;
+ } else if (strncmp(p, "nor", 3) == 0) {
+ *dev_type = MTD_DEV_TYPE_NOR;
+ p += 3;
+ } else if (strncmp(p, "onenand", 7) == 0) {
+ *dev_type = MTD_DEV_TYPE_ONENAND;
+ p += 7;
+ } else {
+ printf("incorrect device type in %s\n", id);
+ return 1;
+ }
+
+ if (!isdigit(*p)) {
+ printf("incorrect device number in %s\n", id);
+ return 1;
+ }
+
+ *dev_num = simple_strtoul(p, (char **)&p, 0);
+ if (ret_id)
+ *ret_id = p;
+ return 0;
+}
+
+/**
+ * Process all devices and generate corresponding mtdparts string describing
+ * all partitions on all devices.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts(char *buf, u32 buflen)
+{
+ struct list_head *pentry, *dentry;
+ struct mtd_device *dev;
+ struct part_info *part, *prev_part;
+ char *p = buf;
+ char tmpbuf[32];
+ u32 size, offset, len, part_cnt;
+ u32 maxlen = buflen - 1;
+
+ debug("--- generate_mtdparts ---\n");
+
+ if (list_empty(&devices)) {
+ buf[0] = '\0';
+ return 0;
+ }
+
+ sprintf(p, "mtdparts=");
+ p += 9;
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+
+ /* copy mtd_id */
+ len = strlen(dev->id->mtd_id) + 1;
+ if (len > maxlen)
+ goto cleanup;
+ memcpy(p, dev->id->mtd_id, len - 1);
+ p += len - 1;
+ *(p++) = ':';
+ maxlen -= len;
+
+ /* format partitions */
+ prev_part = NULL;
+ part_cnt = 0;
+ list_for_each(pentry, &dev->parts) {
+ part = list_entry(pentry, struct part_info, link);
+ size = part->size;
+ offset = part->offset;
+ part_cnt++;
+
+ /* partition size */
+ memsize_format(tmpbuf, size);
+ len = strlen(tmpbuf);
+ if (len > maxlen)
+ goto cleanup;
+ memcpy(p, tmpbuf, len);
+ p += len;
+ maxlen -= len;
+
+
+ /* add offset only when there is a gap between
+ * partitions */
+ if ((!prev_part && (offset != 0)) ||
+ (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
+
+ memsize_format(tmpbuf, offset);
+ len = strlen(tmpbuf) + 1;
+ if (len > maxlen)
+ goto cleanup;
+ *(p++) = '@';
+ memcpy(p, tmpbuf, len - 1);
+ p += len - 1;
+ maxlen -= len;
+ }
+
+ /* copy name only if user supplied */
+ if(!part->auto_name) {
+ len = strlen(part->name) + 2;
+ if (len > maxlen)
+ goto cleanup;
+
+ *(p++) = '(';
+ memcpy(p, part->name, len - 2);
+ p += len - 2;
+ *(p++) = ')';
+ maxlen -= len;
+ }
+
+ /* ro mask flag */
+ if (part->mask_flags && MTD_WRITEABLE_CMD) {
+ len = 2;
+ if (len > maxlen)
+ goto cleanup;
+ *(p++) = 'r';
+ *(p++) = 'o';
+ maxlen -= 2;
+ }
+
+ /* print ',' separator if there are other partitions
+ * following */
+ if (dev->num_parts > part_cnt) {
+ if (1 > maxlen)
+ goto cleanup;
+ *(p++) = ',';
+ maxlen--;
+ }
+ prev_part = part;
+ }
+ /* print ';' separator if there are other devices following */
+ if (dentry->next != &devices) {
+ if (1 > maxlen)
+ goto cleanup;
+ *(p++) = ';';
+ maxlen--;
+ }
+ }
+
+ /* we still have at least one char left, as we decremented maxlen at
+ * the begining */
+ *p = '\0';
+
+ return 0;
+
+cleanup:
+ last_parts[0] = '\0';
+ return 1;
+}
+
+/**
+ * Call generate_mtdparts to process all devices and generate corresponding
+ * mtdparts string, save it in mtdparts environment variable.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts_save(char *buf, u32 buflen)
+{
+ int ret;
+
+ ret = generate_mtdparts(buf, buflen);
+
+ if ((buf[0] != '\0') && (ret == 0))
+ setenv("mtdparts", buf);
+ else
+ setenv("mtdparts", NULL);
+
+ return ret;
+}
+
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+/**
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
+ */
+static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+ uint64_t i, net_size = 0;
+
+ if (!mtd->block_isbad)
+ return part->size;
+
+ for (i = 0; i < part->size; i += mtd->erasesize) {
+ if (!mtd->block_isbad(mtd, part->offset + i))
+ net_size += mtd->erasesize;
+ }
+
+ return net_size;
+}
+#endif
+
+static void print_partition_table(void)
+{
+ struct list_head *dentry, *pentry;
+ struct part_info *part;
+ struct mtd_device *dev;
+ int part_num;
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+ /* list partitions for given device */
+ part_num = 0;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ struct mtd_info *mtd;
+
+ if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ return;
+
+ printf("\ndevice %s%d <%s>, # parts = %d\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ dev->id->mtd_id, dev->num_parts);
+ printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+ list_for_each(pentry, &dev->parts) {
+ u32 net_size;
+ char *size_note;
+
+ part = list_entry(pentry, struct part_info, link);
+ net_size = net_part_size(mtd, part);
+ size_note = part->size == net_size ? " " : " (!)";
+ printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+ part_num, part->name, part->size,
+ net_size, size_note, part->offset,
+ part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
+ printf("\ndevice %s%d <%s>, # parts = %d\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ dev->id->mtd_id, dev->num_parts);
+ printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
+
+ list_for_each(pentry, &dev->parts) {
+ part = list_entry(pentry, struct part_info, link);
+ printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+ part_num, part->name, part->size,
+ part->offset, part->mask_flags);
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
+ part_num++;
+ }
+ }
+
+ if (list_empty(&devices))
+ printf("no partitions defined\n");
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+ struct part_info *part;
+
+ debug("\n---list_partitions---\n");
+ print_partition_table();
+
+ /* current_mtd_dev is not NULL only when we have non empty device list */
+ if (current_mtd_dev) {
+ part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
+ if (part) {
+ printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
+ MTD_DEV_TYPE(current_mtd_dev->id->type),
+ current_mtd_dev->id->num, current_mtd_partnum,
+ part->name, part->size, part->offset);
+ } else {
+ printf("could not get current partition info\n\n");
+ }
+ }
+
+ printf("\ndefaults:\n");
+ printf("mtdids : %s\n",
+ mtdids_default ? mtdids_default : "none");
+ /*
+ * Using printf() here results in printbuffer overflow
+ * if default mtdparts string is greater than console
+ * printbuffer. Use puts() to prevent system crashes.
+ */
+ puts("mtdparts: ");
+ puts(mtdparts_default ? mtdparts_default : "none");
+ puts("\n");
+}
+
+/**
+ * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
+ * corresponding device and verify partition number.
+ *
+ * @param id string describing device and partition or partition name
+ * @param dev pointer to the requested device (output)
+ * @param part_num verified partition number (output)
+ * @param part pointer to requested partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+ u8 *part_num, struct part_info **part)
+{
+ struct list_head *dentry, *pentry;
+ u8 type, dnum, pnum;
+ const char *p;
+
+ debug("--- find_dev_and_part ---\nid = %s\n", id);
+
+ list_for_each(dentry, &devices) {
+ *part_num = 0;
+ *dev = list_entry(dentry, struct mtd_device, link);
+ list_for_each(pentry, &(*dev)->parts) {
+ *part = list_entry(pentry, struct part_info, link);
+ if (strcmp((*part)->name, id) == 0)
+ return 0;
+ (*part_num)++;
+ }
+ }
+
+ p = id;
+ *dev = NULL;
+ *part = NULL;
+ *part_num = 0;
+
+ if (mtd_id_parse(p, &p, &type, &dnum) != 0)
+ return 1;
+
+ if ((*p++ != ',') || (*p == '\0')) {
+ printf("no partition number specified\n");
+ return 1;
+ }
+ pnum = simple_strtoul(p, (char **)&p, 0);
+ if (*p != '\0') {
+ printf("unexpected trailing character '%c'\n", *p);
+ return 1;
+ }
+
+ if ((*dev = device_find(type, dnum)) == NULL) {
+ printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
+ return 1;
+ }
+
+ if ((*part = mtd_part_info(*dev, pnum)) == NULL) {
+ printf("no such partition\n");
+ *dev = NULL;
+ return 1;
+ }
+
+ *part_num = pnum;
+
+ return 0;
+}
+
+/**
+ * Find and delete partition. For partition id format see find_dev_and_part().
+ *
+ * @param id string describing device and partition
+ * @return 0 on success, 1 otherwise
+ */
+static int delete_partition(const char *id)
+{
+ u8 pnum;
+ struct mtd_device *dev;
+ struct part_info *part;
+
+ if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
+
+ debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08x@0x%08x\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
+ part->name, part->size, part->offset);
+
+ if (part_del(dev, part) != 0)
+ return 1;
+
+ if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+ printf("generated mtdparts too long, reseting to null\n");
+ return 1;
+ }
+ return 0;
+ }
+
+ printf("partition %s not found\n", id);
+ return 1;
+}
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * Increase the size of the given partition so that it's net size is at least
+ * as large as the size member and such that the next partition would start on a
+ * good block if it were adjacent to this partition.
+ *
+ * @param mtd the mtd device
+ * @param part the partition
+ * @param next_offset pointer to the offset of the next partition after this
+ * partition's size has been modified (output)
+ */
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+ uint64_t *next_offset)
+{
+ uint64_t net_size, padding_size = 0;
+ int truncated;
+
+ mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size,
+ &truncated);
+
+ /*
+ * Absorb bad blocks immediately following this
+ * partition also into the partition, such that
+ * the next partition starts with a good block.
+ */
+ if (!truncated) {
+ mtd_get_len_incl_bad(mtd, part->offset + net_size,
+ mtd->erasesize, &padding_size, &truncated);
+ if (truncated)
+ padding_size = 0;
+ else
+ padding_size -= mtd->erasesize;
+ }
+
+ if (truncated) {
+ printf("truncated partition %s to %lld bytes\n", part->name,
+ (uint64_t) net_size + padding_size);
+ }
+
+ part->size = net_size + padding_size;
+ *next_offset = part->offset + part->size;
+}
+
+/**
+ * Adjust all of the partition sizes, such that all partitions are at least
+ * as big as their mtdparts environment variable sizes and they each start
+ * on a good block.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int spread_partitions(void)
+{
+ struct list_head *dentry, *pentry;
+ struct mtd_device *dev;
+ struct part_info *part;
+ struct mtd_info *mtd;
+ int part_num;
+ uint64_t cur_offs;
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+
+ if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ return 1;
+
+ part_num = 0;
+ cur_offs = 0;
+ list_for_each(pentry, &dev->parts) {
+ part = list_entry(pentry, struct part_info, link);
+
+ debug("spread_partitions: device = %s%d, partition %d ="
+ " (%s) 0x%08x@0x%08x\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ part_num, part->name, part->size,
+ part->offset);
+
+ if (cur_offs > part->offset)
+ part->offset = cur_offs;
+
+ spread_partition(mtd, part, &cur_offs);
+
+ part_num++;
+ }
+ }
+
+ index_partitions();
+
+ if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+ printf("generated mtdparts too long, reseting to null\n");
+ return 1;
+ }
+ return 0;
+}
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
+
+/**
+ * Accept character string describing mtd partitions and call device_parse()
+ * for each entry. Add created devices to the global devices list.
+ *
+ * @param mtdparts string specifing mtd partitions
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdparts(const char *const mtdparts)
+{
+ const char *p = mtdparts;
+ struct mtd_device *dev;
+ int err = 1;
+
+ debug("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
+
+ /* delete all devices and partitions */
+ if (mtd_devices_init() != 0) {
+ printf("could not initialise device list\n");
+ return err;
+ }
+
+ /* re-read 'mtdparts' variable, mtd_devices_init may be updating env */
+ p = getenv("mtdparts");
+
+ if (strncmp(p, "mtdparts=", 9) != 0) {
+ printf("mtdparts variable doesn't start with 'mtdparts='\n");
+ return err;
+ }
+ p += 9;
+
+ while (p && (*p != '\0')) {
+ err = 1;
+ if ((device_parse(p, &p, &dev) != 0) || (!dev))
+ break;
+
+ debug("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ /* check if parsed device is already on the list */
+ if (device_find(dev->id->type, dev->id->num) != NULL) {
+ printf("device %s%d redefined, please correct mtdparts variable\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num);
+ break;
+ }
+
+ list_add_tail(&dev->link, &devices);
+ err = 0;
+ }
+ if (err == 1) {
+ device_delall(&devices);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse provided string describing mtdids mapping (see file header for mtdids
+ * variable format). Allocate memory for each entry and add all found entries
+ * to the global mtdids list.
+ *
+ * @param ids mapping string
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdids(const char *const ids)
+{
+ const char *p = ids;
+ const char *mtd_id;
+ int mtd_id_len;
+ struct mtdids *id;
+ struct list_head *entry, *n;
+ struct mtdids *id_tmp;
+ u8 type, num;
+ u32 size;
+ int ret = 1;
+
+ debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
+
+ /* clean global mtdids list */
+ list_for_each_safe(entry, n, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ debug("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
+ list_del(entry);
+ free(id_tmp);
+ }
+ last_ids[0] = '\0';
+ INIT_LIST_HEAD(&mtdids);
+
+ while(p && (*p != '\0')) {
+
+ ret = 1;
+ /* parse 'nor'|'nand'|'onenand'<dev-num> */
+ if (mtd_id_parse(p, &p, &type, &num) != 0)
+ break;
+
+ if (*p != '=') {
+ printf("mtdids: incorrect <dev-num>\n");
+ break;
+ }
+ p++;
+
+ /* check if requested device exists */
+ if (mtd_device_validate(type, num, &size) != 0)
+ return 1;
+
+ /* locate <mtd-id> */
+ mtd_id = p;
+ if ((p = strchr(mtd_id, ',')) != NULL) {
+ mtd_id_len = p - mtd_id + 1;
+ p++;
+ } else {
+ mtd_id_len = strlen(mtd_id) + 1;
+ }
+ if (mtd_id_len == 0) {
+ printf("mtdids: no <mtd-id> identifier\n");
+ break;
+ }
+
+ /* check if this id is already on the list */
+ int double_entry = 0;
+ list_for_each(entry, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ if ((id_tmp->type == type) && (id_tmp->num == num)) {
+ double_entry = 1;
+ break;
+ }
+ }
+ if (double_entry) {
+ printf("device id %s%d redefined, please correct mtdids variable\n",
+ MTD_DEV_TYPE(type), num);
+ break;
+ }
+
+ /* allocate mtdids structure */
+ if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
+ printf("out of memory\n");
+ break;
+ }
+ memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
+ id->num = num;
+ id->type = type;
+ id->size = size;
+ id->mtd_id = (char *)(id + 1);
+ strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
+ id->mtd_id[mtd_id_len - 1] = '\0';
+ INIT_LIST_HEAD(&id->link);
+
+ debug("+ id %s%d\t%16d bytes\t%s\n",
+ MTD_DEV_TYPE(id->type), id->num,
+ id->size, id->mtd_id);
+
+ list_add_tail(&id->link, &mtdids);
+ ret = 0;
+ }
+ if (ret == 1) {
+ /* clean mtdids list and free allocated memory */
+ list_for_each_safe(entry, n, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ list_del(entry);
+ free(id_tmp);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse and initialize global mtdids mapping and create global
+ * device/partition list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+int mtdparts_init(void)
+{
+ static int initialized = 0;
+ const char *ids, *parts;
+ const char *current_partition;
+ int ids_changed;
+ char tmp_ep[PARTITION_MAXLEN];
+
+ debug("\n---mtdparts_init---\n");
+ if (!initialized) {
+ INIT_LIST_HEAD(&mtdids);
+ INIT_LIST_HEAD(&devices);
+ memset(last_ids, 0, MTDIDS_MAXLEN);
+ memset(last_parts, 0, MTDPARTS_MAXLEN);
+ memset(last_partition, 0, PARTITION_MAXLEN);
+ initialized = 1;
+ }
+
+ /* get variables */
+ ids = getenv("mtdids");
+ parts = getenv("mtdparts");
+ current_partition = getenv("partition");
+
+ /* save it for later parsing, cannot rely on current partition pointer
+ * as 'partition' variable may be updated during init */
+ tmp_ep[0] = '\0';
+ if (current_partition)
+ strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
+
+ debug("last_ids : %s\n", last_ids);
+ debug("env_ids : %s\n", ids);
+ debug("last_parts: %s\n", last_parts);
+ debug("env_parts : %s\n\n", parts);
+
+ debug("last_partition : %s\n", last_partition);
+ debug("env_partition : %s\n", current_partition);
+
+ /* if mtdids varible is empty try to use defaults */
+ if (!ids) {
+ if (mtdids_default) {
+ debug("mtdids variable not defined, using default\n");
+ ids = mtdids_default;
+ setenv("mtdids", (char *)ids);
+ } else {
+ printf("mtdids not defined, no default present\n");
+ return 1;
+ }
+ }
+ if (strlen(ids) > MTDIDS_MAXLEN - 1) {
+ printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
+ return 1;
+ }
+
+ /* do no try to use defaults when mtdparts variable is not defined,
+ * just check the length */
+ if (!parts)
+ printf("mtdparts variable not set, see 'help mtdparts'\n");
+
+ if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
+ printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
+ return 1;
+ }
+
+ /* check if we have already parsed those mtdids */
+ if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
+ ids_changed = 0;
+ } else {
+ ids_changed = 1;
+
+ if (parse_mtdids(ids) != 0) {
+ mtd_devices_init();
+ return 1;
+ }
+
+ /* ok it's good, save new ids */
+ strncpy(last_ids, ids, MTDIDS_MAXLEN);
+ }
+
+ /* parse partitions if either mtdparts or mtdids were updated */
+ if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
+ if (parse_mtdparts(parts) != 0)
+ return 1;
+
+ if (list_empty(&devices)) {
+ printf("mtdparts_init: no valid partitions\n");
+ return 1;
+ }
+
+ /* ok it's good, save new parts */
+ strncpy(last_parts, parts, MTDPARTS_MAXLEN);
+
+ /* reset first partition from first dev from the list as current */
+ current_mtd_dev = list_entry(devices.next, struct mtd_device, link);
+ current_mtd_partnum = 0;
+ current_save();
+
+ debug("mtdparts_init: current_mtd_dev = %s%d, current_mtd_partnum = %d\n",
+ MTD_DEV_TYPE(current_mtd_dev->id->type),
+ current_mtd_dev->id->num, current_mtd_partnum);
+ }
+
+ /* mtdparts variable was reset to NULL, delete all devices/partitions */
+ if (!parts && (last_parts[0] != '\0'))
+ return mtd_devices_init();
+
+ /* do not process current partition if mtdparts variable is null */
+ if (!parts)
+ return 0;
+
+ /* is current partition set in environment? if so, use it */
+ if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
+ struct part_info *p;
+ struct mtd_device *cdev;
+ u8 pnum;
+
+ debug("--- getting current partition: %s\n", tmp_ep);
+
+ if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
+ current_mtd_dev = cdev;
+ current_mtd_partnum = pnum;
+ current_save();
+ }
+ } else if (getenv("partition") == NULL) {
+ debug("no partition variable set, setting...\n");
+ current_save();
+ }
+
+ return 0;
+}
+
+/**
+ * Return pointer to the partition of a requested number from a requested
+ * device.
+ *
+ * @param dev device that is to be searched for a partition
+ * @param part_num requested partition number
+ * @return pointer to the part_info, NULL otherwise
+ */
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num)
+{
+ struct list_head *entry;
+ struct part_info *part;
+ int num;
+
+ if (!dev)
+ return NULL;
+
+ debug("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ if (part_num >= dev->num_parts) {
+ printf("invalid partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+ return NULL;
+ }
+
+ /* locate partition number, return it */
+ num = 0;
+ list_for_each(entry, &dev->parts) {
+ part = list_entry(entry, struct part_info, link);
+
+ if (part_num == num++) {
+ return part;
+ }
+ }
+
+ return NULL;
+}
+
+/***************************************************/
+/* U-boot commands */
+/***************************************************/
+/* command line only */
+/**
+ * Routine implementing u-boot chpart command. Sets new current partition based
+ * on the user supplied partition id. For partition id format see find_dev_and_part().
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+/* command line only */
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 pnum;
+
+ if (mtdparts_init() !=0)
+ return 1;
+
+ if (argc < 2) {
+ printf("no partition id specified\n");
+ return 1;
+ }
+
+ if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
+ return 1;
+
+ current_mtd_dev = dev;
+ current_mtd_partnum = pnum;
+ current_save();
+
+ printf("partition changed to %s%d,%d\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
+
+ return 0;
+}
+
+/**
+ * Routine implementing u-boot mtdparts command. Initialize/update default global
+ * partition list and process user partition request (list, add, del).
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc == 2) {
+ if (strcmp(argv[1], "default") == 0) {
+ setenv("mtdids", (char *)mtdids_default);
+ setenv("mtdparts", (char *)mtdparts_default);
+ setenv("partition", NULL);
+
+ mtdparts_init();
+ return 0;
+ } else if (strcmp(argv[1], "delall") == 0) {
+ /* this may be the first run, initialize lists if needed */
+ mtdparts_init();
+
+ setenv("mtdparts", NULL);
+
+ /* mtd_devices_init() calls current_save() */
+ return mtd_devices_init();
+ }
+ }
+
+ /* make sure we are in sync with env variables */
+ if (mtdparts_init() != 0)
+ return 1;
+
+ if (argc == 1) {
+ list_partitions();
+ return 0;
+ }
+
+ /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
+ if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
+#define PART_ADD_DESC_MAXLEN 64
+ char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ struct mtd_info *mtd;
+ uint64_t next_offset;
+#endif
+ u8 type, num, len;
+ struct mtd_device *dev;
+ struct mtd_device *dev_tmp;
+ struct mtdids *id;
+ struct part_info *p;
+
+ if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
+ return 1;
+
+ if ((id = id_find(type, num)) == NULL) {
+ printf("no such device %s defined in mtdids variable\n", argv[2]);
+ return 1;
+ }
+
+ len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */
+ len += strlen(argv[3]); /* size@offset */
+ len += strlen(argv[4]) + 2; /* '(' name ')' */
+ if (argv[5] && (strlen(argv[5]) == 2))
+ len += 2; /* 'ro' */
+
+ if (len >= PART_ADD_DESC_MAXLEN) {
+ printf("too long partition description\n");
+ return 1;
+ }
+ sprintf(tmpbuf, "%s:%s(%s)%s",
+ id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
+ debug("add tmpbuf: %s\n", tmpbuf);
+
+ if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
+ return 1;
+
+ debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ p = list_entry(dev->parts.next, struct part_info, link);
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ return 1;
+
+ if (!strcmp(&argv[1][3], ".spread")) {
+ spread_partition(mtd, p, &next_offset);
+ debug("increased %s to %d bytes\n", p->name, p->size);
+ }
+#endif
+
+ dev_tmp = device_find(dev->id->type, dev->id->num);
+ if (dev_tmp == NULL) {
+ device_add(dev);
+ } else if (part_add(dev_tmp, p) != 0) {
+ /* merge new partition with existing ones*/
+ device_del(dev);
+ return 1;
+ }
+
+ if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+ printf("generated mtdparts too long, reseting to null\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* mtdparts del part-id */
+ if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
+ debug("del: part-id = %s\n", argv[2]);
+
+ return delete_partition(argv[2]);
+ }
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ if ((argc == 2) && (strcmp(argv[1], "spread") == 0))
+ return spread_partitions();
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
+
+ return cmd_usage(cmdtp);
+}
+
+/***************************************************/
+U_BOOT_CMD(
+ chpart, 2, 0, do_chpart,
+ "change active partition",
+ "part-id\n"
+ " - change active partition (e.g. part-id = nand0,1)"
+);
+
+U_BOOT_CMD(
+ mtdparts, 6, 0, do_mtdparts,
+ "define flash/nand partitions",
+ "\n"
+ " - list partition table\n"
+ "mtdparts delall\n"
+ " - delete all partitions\n"
+ "mtdparts del part-id\n"
+ " - delete partition (e.g. part-id = nand0,1)\n"
+ "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+ " - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+ " - add partition, padding size by skipping bad blocks\n"
+#endif
+ "mtdparts default\n"
+ " - reset partition table to defaults\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ "mtdparts spread\n"
+ " - adjust the sizes of the partitions so they are\n"
+ " at least as big as the mtdparts variable specifies\n"
+ " and they each start on a good block\n\n"
+#else
+ "\n"
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
+ "-----\n\n"
+ "this command uses three environment variables:\n\n"
+ "'partition' - keeps current partition identifier\n\n"
+ "partition := <part-id>\n"
+ "<part-id> := <dev-id>,part_num\n\n"
+ "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
+ "mtdids=<idmap>[,<idmap>,...]\n\n"
+ "<idmap> := <dev-id>=<mtd-id>\n"
+ "<dev-id> := 'nand'|'nor'|'onenand'<dev-num>\n"
+ "<dev-num> := mtd device number, 0...\n"
+ "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
+ "'mtdparts' - partition list\n\n"
+ "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
+ "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n"
+ "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
+ "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
+ "<size> := standard linux memsize OR '-' to denote all remaining space\n"
+ "<offset> := partition start offset within the device\n"
+ "<name> := '(' NAME ')'\n"
+ "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"
+);
+/***************************************************/
diff --git a/u-boot/common/cmd_nand.c b/u-boot/common/cmd_nand.c
new file mode 100644
index 0000000..7bd37de
--- /dev/null
+++ b/u-boot/common/cmd_nand.c
@@ -0,0 +1,897 @@
+/*
+ * Driver for NAND support, Rick Bronson
+ * borrowed heavily from:
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Ported 'dynenv' to 'nand env.oob' command
+ * (C) 2010 Nanometrics, Inc.
+ * 'dynenv' -- Dynamic environment offset in NAND OOB
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Added 16-bit nand support
+ * (C) 2004 Texas Instruments
+ *
+ * Copyright 2010 Freescale Semiconductor
+ * The portions of this file whose copyright is held by Freescale and which
+ * are not considered a derived work of GPL v2-only code may be distributed
+ * and/or modified 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.
+ */
+
+#include <common.h>
+#include <linux/mtd/mtd.h>
+#include <command.h>
+#include <watchdog.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <jffs2/jffs2.h>
+#include <nand.h>
+
+#if defined(CONFIG_CMD_MTDPARTS)
+
+/* partition handling routines */
+int mtdparts_init(void);
+int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+ u8 *part_num, struct part_info **part);
+#endif
+
+static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
+{
+ int i;
+ u_char *datbuf, *oobbuf, *p;
+ static loff_t last;
+
+ if (repeat)
+ off = last + nand->writesize;
+
+ last = off;
+
+ datbuf = malloc(nand->writesize + nand->oobsize);
+ oobbuf = malloc(nand->oobsize);
+ if (!datbuf || !oobbuf) {
+ puts("No memory for page buffer\n");
+ return 1;
+ }
+ off &= ~(nand->writesize - 1);
+ loff_t addr = (loff_t) off;
+ struct mtd_oob_ops ops;
+ memset(&ops, 0, sizeof(ops));
+ ops.datbuf = datbuf;
+ ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
+ ops.len = nand->writesize;
+ ops.ooblen = nand->oobsize;
+ ops.mode = MTD_OOB_RAW;
+ i = nand->read_oob(nand, addr, &ops);
+ if (i < 0) {
+ printf("Error (%d) reading page %08lx\n", i, off);
+ free(datbuf);
+ free(oobbuf);
+ return 1;
+ }
+ printf("Page %08lx dump:\n", off);
+ i = nand->writesize >> 4;
+ p = datbuf;
+
+ while (i--) {
+ if (!only_oob)
+ printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14],
+ p[15]);
+ p += 16;
+ }
+ puts("OOB:\n");
+ i = nand->oobsize >> 3;
+ while (i--) {
+ printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ free(datbuf);
+ free(oobbuf);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int set_dev(int dev)
+{
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[dev].name) {
+ puts("No such device\n");
+ return -1;
+ }
+
+ if (nand_curr_device == dev)
+ return 0;
+
+ printf("Device %d: %s", dev, nand_info[dev].name);
+ puts("... is now current device\n");
+ nand_curr_device = dev;
+
+#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
+ board_nand_select_device(nand_info[dev].priv, dev);
+#endif
+
+ return 0;
+}
+
+static inline int str2off(const char *p, loff_t *num)
+{
+ char *endptr;
+
+ *num = simple_strtoull(p, &endptr, 16);
+ return *p != '\0' && *endptr == '\0';
+}
+
+static inline int str2long(const char *p, ulong *num)
+{
+ char *endptr;
+
+ *num = simple_strtoul(p, &endptr, 16);
+ return *p != '\0' && *endptr == '\0';
+}
+
+static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
+{
+#ifdef CONFIG_CMD_MTDPARTS
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 pnum;
+ int ret;
+
+ ret = mtdparts_init();
+ if (ret)
+ return ret;
+
+ ret = find_dev_and_part(partname, &dev, &pnum, &part);
+ if (ret)
+ return ret;
+
+ if (dev->id->type != MTD_DEV_TYPE_NAND) {
+ puts("not a NAND device\n");
+ return -1;
+ }
+
+ *off = part->offset;
+ *size = part->size;
+ *idx = dev->id->num;
+
+ ret = set_dev(*idx);
+ if (ret)
+ return ret;
+
+ return 0;
+#else
+ puts("offset is not a number\n");
+ return -1;
+#endif
+}
+
+static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize)
+{
+ if (!str2off(arg, off))
+ return get_part(arg, idx, off, maxsize);
+
+ if (*off >= nand_info[*idx].size) {
+ puts("Offset exceeds device limit\n");
+ return -1;
+ }
+
+ *maxsize = nand_info[*idx].size - *off;
+ return 0;
+}
+
+static int arg_off_size(int argc, char *const argv[], int *idx,
+ loff_t *off, loff_t *size)
+{
+ int ret;
+ loff_t maxsize;
+
+ if (argc == 0) {
+ *off = 0;
+ *size = nand_info[*idx].size;
+ goto print;
+ }
+
+ ret = arg_off(argv[0], idx, off, &maxsize);
+ if (ret)
+ return ret;
+
+ if (argc == 1) {
+ *size = maxsize;
+ goto print;
+ }
+
+ if (!str2off(argv[1], size)) {
+ printf("'%s' is not a number\n", argv[1]);
+ return -1;
+ }
+
+ if (*size > maxsize) {
+ puts("Size exceeds partition or device limit\n");
+ return -1;
+ }
+
+print:
+ printf("device %d ", *idx);
+ if (*size == nand_info[*idx].size)
+ puts("whole chip\n");
+ else
+ printf("offset 0x%llx, size 0x%llx\n",
+ (unsigned long long)*off, (unsigned long long)*size);
+ return 0;
+}
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+static void print_status(ulong start, ulong end, ulong erasesize, int status)
+{
+ printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
+ start,
+ end - 1,
+ (end - start) / erasesize,
+ ((status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
+ ((status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
+ ((status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
+}
+
+static void do_nand_status(nand_info_t *nand)
+{
+ ulong block_start = 0;
+ ulong off;
+ int last_status = -1;
+
+ struct nand_chip *nand_chip = nand->priv;
+ /* check the WP bit */
+ nand_chip->cmdfunc(nand, NAND_CMD_STATUS, -1, -1);
+ printf("device is %swrite protected\n",
+ (nand_chip->read_byte(nand) & 0x80 ?
+ "NOT " : ""));
+
+ for (off = 0; off < nand->size; off += nand->erasesize) {
+ int s = nand_get_lock_status(nand, off);
+
+ /* print message only if status has changed */
+ if (s != last_status && off != 0) {
+ print_status(block_start, off, nand->erasesize,
+ last_status);
+ block_start = off;
+ }
+ last_status = s;
+ }
+ /* Print the last block info */
+ print_status(block_start, off, nand->erasesize, last_status);
+}
+#endif
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;
+
+int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
+{
+ int ret;
+ uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+ nand_info_t *nand = &nand_info[0];
+ char *cmd = argv[1];
+
+ if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) {
+ puts("no devices available\n");
+ return 1;
+ }
+
+ set_dev(0);
+
+ if (!strcmp(cmd, "get")) {
+ ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+ if (ret)
+ return 1;
+
+ printf("0x%08lx\n", nand_env_oob_offset);
+ } else if (!strcmp(cmd, "set")) {
+ loff_t addr;
+ loff_t maxsize;
+ struct mtd_oob_ops ops;
+ int idx = 0;
+
+ if (argc < 3)
+ goto usage;
+
+ if (arg_off(argv[2], &idx, &addr, &maxsize)) {
+ puts("Offset or partition name expected\n");
+ return 1;
+ }
+
+ if (idx != 0) {
+ puts("Partition not on first NAND device\n");
+ return 1;
+ }
+
+ if (nand->oobavail < ENV_OFFSET_SIZE) {
+ printf("Insufficient available OOB bytes:\n"
+ "%d OOB bytes available but %d required for "
+ "env.oob support\n",
+ nand->oobavail, ENV_OFFSET_SIZE);
+ return 1;
+ }
+
+ if ((addr & (nand->erasesize - 1)) != 0) {
+ printf("Environment offset must be block-aligned\n");
+ return 1;
+ }
+
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooboffs = 0;
+ ops.ooblen = ENV_OFFSET_SIZE;
+ ops.oobbuf = (void *) oob_buf;
+
+ oob_buf[0] = ENV_OOB_MARKER;
+ oob_buf[1] = addr / nand->erasesize;
+
+ ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
+ if (ret) {
+ printf("Error writing OOB block 0\n");
+ return ret;
+ }
+
+ ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+ if (ret) {
+ printf("Error reading env offset in OOB\n");
+ return ret;
+ }
+
+ if (addr != nand_env_oob_offset) {
+ printf("Verification of env offset in OOB failed: "
+ "0x%08llx expected but got 0x%08lx\n",
+ (unsigned long long)addr, nand_env_oob_offset);
+ return 1;
+ }
+ } else {
+ goto usage;
+ }
+
+ return ret;
+
+usage:
+ return cmd_usage(cmdtp);
+}
+
+#endif
+
+static void nand_print_info(int idx)
+{
+ nand_info_t *nand = &nand_info[idx];
+ struct nand_chip *chip = nand->priv;
+ printf("Device %d: ", idx);
+ if (chip->numchips > 1)
+ printf("%dx ", chip->numchips);
+ printf("%s, sector size %u KiB\n",
+ nand->name, nand->erasesize >> 10);
+}
+
+int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int i, ret = 0;
+ ulong addr;
+ loff_t off, size;
+ char *cmd, *s;
+ nand_info_t *nand;
+#ifdef CONFIG_SYS_NAND_QUIET
+ int quiet = CONFIG_SYS_NAND_QUIET;
+#else
+ int quiet = 0;
+#endif
+ const char *quiet_str = getenv("quiet");
+ int dev = nand_curr_device;
+ int repeat = flag & CMD_FLAG_REPEAT;
+
+ /* at least two arguments please */
+ if (argc < 2)
+ goto usage;
+
+ if (quiet_str)
+ quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
+
+ cmd = argv[1];
+
+ /* Only "dump" is repeatable. */
+ if (repeat && strcmp(cmd, "dump"))
+ return 0;
+
+ if (strcmp(cmd, "info") == 0) {
+
+ putc('\n');
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
+ if (nand_info[i].name)
+ nand_print_info(i);
+ }
+ return 0;
+ }
+
+ if (strcmp(cmd, "device") == 0) {
+ if (argc < 3) {
+ putc('\n');
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
+ puts("no devices available\n");
+ else
+ nand_print_info(dev);
+ return 0;
+ }
+
+ dev = (int)simple_strtoul(argv[2], NULL, 10);
+ set_dev(dev);
+
+ return 0;
+ }
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+ /* this command operates only on the first nand device */
+ if (strcmp(cmd, "env.oob") == 0)
+ return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
+#endif
+
+ /* The following commands operate on the current device, unless
+ * overridden by a partition specifier. Note that if somehow the
+ * current device is invalid, it will have to be changed to a valid
+ * one before these commands can run, even if a partition specifier
+ * for another device is to be used.
+ */
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[dev].name) {
+ puts("\nno devices available\n");
+ return 1;
+ }
+ nand = &nand_info[dev];
+
+ if (strcmp(cmd, "bad") == 0) {
+ printf("\nDevice %d bad blocks:\n", dev);
+ for (off = 0; off < nand->size; off += nand->erasesize)
+ if (nand_block_isbad(nand, off))
+ printf(" %08llx\n", (unsigned long long)off);
+ return 0;
+ }
+
+ /*
+ * Syntax is:
+ * 0 1 2 3 4
+ * nand erase [clean] [off size]
+ */
+ if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
+ nand_erase_options_t opts;
+ /* "clean" at index 2 means request to write cleanmarker */
+ int clean = argc > 2 && !strcmp("clean", argv[2]);
+ int o = clean ? 3 : 2;
+ int scrub = !strncmp(cmd, "scrub", 5);
+ int part = 0;
+ int chip = 0;
+ int spread = 0;
+ int args = 2;
+
+ if (cmd[5] != 0) {
+ if (!strcmp(&cmd[5], ".spread")) {
+ spread = 1;
+ } else if (!strcmp(&cmd[5], ".part")) {
+ part = 1;
+ args = 1;
+ } else if (!strcmp(&cmd[5], ".chip")) {
+ chip = 1;
+ args = 0;
+ } else {
+ goto usage;
+ }
+ }
+
+ /*
+ * Don't allow missing arguments to cause full chip/partition
+ * erases -- easy to do accidentally, e.g. with a misspelled
+ * variable name.
+ */
+ if (argc != o + args)
+ goto usage;
+
+ printf("\nNAND %s: ", cmd);
+ /* skip first two or three arguments, look for offset and size */
+ if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0)
+ return 1;
+
+ nand = &nand_info[dev];
+
+ memset(&opts, 0, sizeof(opts));
+ opts.offset = off;
+ opts.length = size;
+ opts.jffs2 = clean;
+ opts.quiet = quiet;
+ opts.spread = spread;
+
+ if (scrub) {
+ puts("Warning: "
+ "scrub option will erase all factory set "
+ "bad blocks!\n"
+ " "
+ "There is no reliable way to recover them.\n"
+ " "
+ "Use this command only for testing purposes "
+ "if you\n"
+ " "
+ "are sure of what you are doing!\n"
+ "\nReally scrub this NAND flash? <y/N>\n");
+
+ if (getc() == 'y') {
+ puts("y");
+ if (getc() == '\r')
+ opts.scrub = 1;
+ else {
+ puts("scrub aborted\n");
+ return -1;
+ }
+ } else {
+ puts("scrub aborted\n");
+ return -1;
+ }
+ }
+ ret = nand_erase_opts(nand, &opts);
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+ }
+
+ if (strncmp(cmd, "dump", 4) == 0) {
+ if (argc < 3)
+ goto usage;
+
+ off = (int)simple_strtoul(argv[2], NULL, 16);
+ ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);
+
+ return ret == 0 ? 1 : 0;
+ }
+
+ if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
+ size_t rwsize;
+ int read;
+
+ if (argc < 4)
+ goto usage;
+
+ addr = (ulong)simple_strtoul(argv[2], NULL, 16);
+
+ read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
+ printf("\nNAND %s: ", read ? "read" : "write");
+ if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size) != 0)
+ return 1;
+
+ nand = &nand_info[dev];
+ rwsize = size;
+
+ s = strchr(cmd, '.');
+ if (!s || !strcmp(s, ".jffs2") ||
+ !strcmp(s, ".e") || !strcmp(s, ".i")) {
+ if (read)
+ ret = nand_read_skip_bad(nand, off, &rwsize,
+ (u_char *)addr);
+ else
+ ret = nand_write_skip_bad(nand, off, &rwsize,
+ (u_char *)addr, 0);
+#ifdef CONFIG_CMD_NAND_YAFFS
+ } else if (!strcmp(s, ".yaffs")) {
+ if (read) {
+ printf("Unknown nand command suffix '%s'.\n", s);
+ return 1;
+ }
+ ret = nand_write_skip_bad(nand, off, &rwsize, (u_char *)addr, 1);
+#endif
+ } else if (!strcmp(s, ".oob")) {
+ /* out-of-band data */
+ mtd_oob_ops_t ops = {
+ .oobbuf = (u8 *)addr,
+ .ooblen = rwsize,
+ .mode = MTD_OOB_RAW
+ };
+
+ if (read)
+ ret = nand->read_oob(nand, off, &ops);
+ else
+ ret = nand->write_oob(nand, off, &ops);
+ } else {
+ printf("Unknown nand command suffix '%s'.\n", s);
+ return 1;
+ }
+
+ printf(" %zu bytes %s: %s\n", rwsize,
+ read ? "read" : "written", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+ }
+
+ if (strcmp(cmd, "markbad") == 0) {
+ argc -= 2;
+ argv += 2;
+
+ if (argc <= 0)
+ goto usage;
+
+ while (argc > 0) {
+ addr = simple_strtoul(*argv, NULL, 16);
+
+ if (nand->block_markbad(nand, addr)) {
+ printf("block 0x%08lx NOT marked "
+ "as bad! ERROR %d\n",
+ addr, ret);
+ ret = 1;
+ } else {
+ printf("block 0x%08lx successfully "
+ "marked as bad\n",
+ addr);
+ }
+ --argc;
+ ++argv;
+ }
+ return ret;
+ }
+
+ if (strcmp(cmd, "biterr") == 0) {
+ /* todo */
+ return 1;
+ }
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ if (strcmp(cmd, "lock") == 0) {
+ int tight = 0;
+ int status = 0;
+ if (argc == 3) {
+ if (!strcmp("tight", argv[2]))
+ tight = 1;
+ if (!strcmp("status", argv[2]))
+ status = 1;
+ }
+ if (status) {
+ do_nand_status(nand);
+ } else {
+ if (!nand_lock(nand, tight)) {
+ puts("NAND flash successfully locked\n");
+ } else {
+ puts("Error locking NAND flash\n");
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if (strcmp(cmd, "unlock") == 0) {
+ if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0)
+ return 1;
+
+ if (!nand_unlock(&nand_info[dev], off, size)) {
+ puts("NAND flash successfully unlocked\n");
+ } else {
+ puts("Error unlocking NAND flash, "
+ "write and erase will probably fail\n");
+ return 1;
+ }
+ return 0;
+ }
+#endif
+
+usage:
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ nand, CONFIG_SYS_MAXARGS, 1, do_nand,
+ "NAND sub-system",
+ "info - show available NAND devices\n"
+ "nand device [dev] - show or set current device\n"
+ "nand read - addr off|partition size\n"
+ "nand write - addr off|partition size\n"
+ " read/write 'size' bytes starting at offset 'off'\n"
+ " to/from memory address 'addr', skipping bad blocks.\n"
+#ifdef CONFIG_CMD_NAND_YAFFS
+ "nand write.yaffs - addr off|partition size\n"
+ " write 'size' bytes starting at offset 'off' with yaffs format\n"
+ " from memory address 'addr', skipping bad blocks.\n"
+#endif
+ "nand erase[.spread] [clean] [off [size]] - erase 'size' bytes "
+ "from offset 'off'\n"
+ " With '.spread', erase enough for given file size, otherwise,\n"
+ " 'size' includes skipped bad blocks.\n"
+ "nand erase.part [clean] partition - erase entire mtd partition'\n"
+ "nand erase.chip [clean] - erase entire chip'\n"
+ "nand bad - show bad blocks\n"
+ "nand dump[.oob] off - dump page\n"
+ "nand scrub off size | scrub.part partition | scrub.chip\n"
+ " really clean NAND erasing bad blocks (UNSAFE)\n"
+ "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
+ "nand biterr off - make a bit error at offset (UNSAFE)"
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ "\n"
+ "nand lock [tight] [status]\n"
+ " bring nand to lock state or display locked pages\n"
+ "nand unlock [offset] [size] - unlock section"
+#endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+ "\n"
+ "nand env.oob - environment offset in OOB of block 0 of"
+ " first device.\n"
+ "nand env.oob set off|partition - set enviromnent offset\n"
+ "nand env.oob get - get environment offset"
+#endif
+);
+
+static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
+ ulong offset, ulong addr, char *cmd)
+{
+ int r;
+ char *ep, *s;
+ size_t cnt;
+ image_header_t *hdr;
+#if defined(CONFIG_FIT)
+ const void *fit_hdr = NULL;
+#endif
+
+ s = strchr(cmd, '.');
+ if (s != NULL &&
+ (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
+ printf("Unknown nand load suffix '%s'\n", s);
+ show_boot_progress(-53);
+ return 1;
+ }
+
+ printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
+
+ cnt = nand->writesize;
+ r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
+ if (r) {
+ puts("** Read error\n");
+ show_boot_progress (-56);
+ return 1;
+ }
+ show_boot_progress (56);
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+
+ show_boot_progress (57);
+ image_print_contents (hdr);
+
+ cnt = image_get_image_size (hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (const void *)addr;
+ puts ("Fit image detected...\n");
+
+ cnt = fit_get_size (fit_hdr);
+ break;
+#endif
+ default:
+ show_boot_progress (-57);
+ puts ("** Unknown image type\n");
+ return 1;
+ }
+ show_boot_progress (57);
+
+ r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
+ if (r) {
+ puts("** Read error\n");
+ show_boot_progress (-58);
+ return 1;
+ }
+ show_boot_progress (58);
+
+#if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+ if (!fit_check_format (fit_hdr)) {
+ show_boot_progress (-150);
+ puts ("** Bad FIT image format\n");
+ return 1;
+ }
+ show_boot_progress (151);
+ fit_print_contents (fit_hdr);
+ }
+#endif
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
+ char *local_args[2];
+
+ local_args[0] = cmd;
+ local_args[1] = NULL;
+
+ printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
+
+ do_bootm(cmdtp, 0, 1, local_args);
+ return 1;
+ }
+ return 0;
+}
+
+int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ char *boot_device = NULL;
+ int idx;
+ ulong addr, offset = 0;
+#if defined(CONFIG_CMD_MTDPARTS)
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 pnum;
+
+ if (argc >= 2) {
+ char *p = (argc == 2) ? argv[1] : argv[2];
+ if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
+ (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
+ if (dev->id->type != MTD_DEV_TYPE_NAND) {
+ puts("Not a NAND device\n");
+ return 1;
+ }
+ if (argc > 3)
+ goto usage;
+ if (argc == 3)
+ addr = simple_strtoul(argv[1], NULL, 16);
+ else
+ addr = CONFIG_SYS_LOAD_ADDR;
+ return nand_load_image(cmdtp, &nand_info[dev->id->num],
+ part->offset, addr, argv[0]);
+ }
+ }
+#endif
+
+ show_boot_progress(52);
+ switch (argc) {
+ case 1:
+ addr = CONFIG_SYS_LOAD_ADDR;
+ boot_device = getenv("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ case 4:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ offset = simple_strtoul(argv[3], NULL, 16);
+ break;
+ default:
+#if defined(CONFIG_CMD_MTDPARTS)
+usage:
+#endif
+ show_boot_progress(-53);
+ return cmd_usage(cmdtp);
+ }
+
+ show_boot_progress(53);
+ if (!boot_device) {
+ puts("\n** No boot device **\n");
+ show_boot_progress(-54);
+ return 1;
+ }
+ show_boot_progress(54);
+
+ idx = simple_strtoul(boot_device, NULL, 16);
+
+ if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx].name) {
+ printf("\n** Device %d not available\n", idx);
+ show_boot_progress(-55);
+ return 1;
+ }
+ show_boot_progress(55);
+
+ return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
+}
+
+U_BOOT_CMD(nboot, 4, 1, do_nandboot,
+ "boot from NAND device",
+ "[partition] | [[[loadAddr] dev] offset]"
+);
diff --git a/u-boot/common/cmd_net.c b/u-boot/common/cmd_net.c
new file mode 100644
index 0000000..8c6f5c8
--- /dev/null
+++ b/u-boot/common/cmd_net.c
@@ -0,0 +1,385 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+
+static int netboot_common (proto_t, cmd_tbl_t *, int , char * const []);
+
+int do_bootp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return netboot_common (BOOTP, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+ bootp, 3, 1, do_bootp,
+ "boot image via network using BOOTP/TFTP protocol",
+ "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+
+int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return netboot_common (TFTP, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+ tftpboot, 3, 1, do_tftpb,
+ "boot image via network using TFTP protocol",
+ "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+
+#ifdef CONFIG_CMD_RARP
+int do_rarpb (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return netboot_common (RARP, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+ rarpboot, 3, 1, do_rarpb,
+ "boot image via network using RARP/TFTP protocol",
+ "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+#endif
+
+#if defined(CONFIG_CMD_DHCP)
+int do_dhcp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return netboot_common(DHCP, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+ dhcp, 3, 1, do_dhcp,
+ "boot image via network using DHCP/TFTP protocol",
+ "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+#endif
+
+#if defined(CONFIG_CMD_NFS)
+int do_nfs (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return netboot_common(NFS, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+ nfs, 3, 1, do_nfs,
+ "boot image via network using NFS protocol",
+ "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+#endif
+
+static void netboot_update_env (void)
+{
+ char tmp[22];
+
+ if (NetOurGatewayIP) {
+ ip_to_string (NetOurGatewayIP, tmp);
+ setenv ("gatewayip", tmp);
+ }
+
+ if (NetOurSubnetMask) {
+ ip_to_string (NetOurSubnetMask, tmp);
+ setenv ("netmask", tmp);
+ }
+
+ if (NetOurHostName[0])
+ setenv ("hostname", NetOurHostName);
+
+ if (NetOurRootPath[0])
+ setenv ("rootpath", NetOurRootPath);
+
+ if (NetOurIP) {
+ ip_to_string (NetOurIP, tmp);
+ setenv ("ipaddr", tmp);
+ }
+
+ if (NetServerIP) {
+ ip_to_string (NetServerIP, tmp);
+ setenv ("serverip", tmp);
+ }
+
+ if (NetOurDNSIP) {
+ ip_to_string (NetOurDNSIP, tmp);
+ setenv ("dnsip", tmp);
+ }
+#if defined(CONFIG_BOOTP_DNS2)
+ if (NetOurDNS2IP) {
+ ip_to_string (NetOurDNS2IP, tmp);
+ setenv ("dnsip2", tmp);
+ }
+#endif
+ if (NetOurNISDomain[0])
+ setenv ("domain", NetOurNISDomain);
+
+#if defined(CONFIG_CMD_SNTP) \
+ && defined(CONFIG_BOOTP_TIMEOFFSET)
+ if (NetTimeOffset) {
+ sprintf (tmp, "%d", NetTimeOffset);
+ setenv ("timeoffset", tmp);
+ }
+#endif
+#if defined(CONFIG_CMD_SNTP) \
+ && defined(CONFIG_BOOTP_NTPSERVER)
+ if (NetNtpServerIP) {
+ ip_to_string (NetNtpServerIP, tmp);
+ setenv ("ntpserverip", tmp);
+ }
+#endif
+}
+
+static int
+netboot_common (proto_t proto, cmd_tbl_t *cmdtp, int argc, char * const argv[])
+{
+ char *s;
+ char *end;
+ int rcode = 0;
+ int size;
+ ulong addr;
+
+ /* pre-set load_addr */
+ if ((s = getenv("loadaddr")) != NULL) {
+ load_addr = simple_strtoul(s, NULL, 16);
+ }
+
+ switch (argc) {
+ case 1:
+ break;
+
+ case 2: /*
+ * Only one arg - accept two forms:
+ * Just load address, or just boot file name. The latter
+ * form must be written in a format which can not be
+ * mis-interpreted as a valid number.
+ */
+ addr = simple_strtoul(argv[1], &end, 16);
+ if (end == (argv[1] + strlen(argv[1])))
+ load_addr = addr;
+ else
+ copy_filename(BootFile, argv[1], sizeof(BootFile));
+ break;
+
+ case 3: load_addr = simple_strtoul(argv[1], NULL, 16);
+ copy_filename (BootFile, argv[2], sizeof(BootFile));
+
+ break;
+
+ default:
+ show_boot_progress (-80);
+ return cmd_usage(cmdtp);
+ }
+
+ show_boot_progress (80);
+ if ((size = NetLoop(proto)) < 0) {
+ show_boot_progress (-81);
+ return 1;
+ }
+
+ show_boot_progress (81);
+ /* NetLoop ok, update environment */
+ netboot_update_env();
+
+ /* done if no file was loaded (no errors though) */
+ if (size == 0) {
+ show_boot_progress (-82);
+ return 0;
+ }
+
+ /* flush cache */
+ flush_cache(load_addr, size);
+
+ /* Loading ok, check if we should attempt an auto-start */
+ if (((s = getenv("autostart")) != NULL) && (strcmp(s,"yes") == 0)) {
+ char *local_args[2];
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+
+ printf ("Automatic boot of image at addr 0x%08lX ...\n",
+ load_addr);
+ show_boot_progress (82);
+ rcode = do_bootm (cmdtp, 0, 1, local_args);
+ }
+
+ if (rcode < 0)
+ show_boot_progress (-83);
+ else
+ show_boot_progress (84);
+ return rcode;
+}
+
+#if defined(CONFIG_CMD_PING)
+int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc < 2)
+ return -1;
+
+ NetPingIP = string_to_ip(argv[1]);
+ if (NetPingIP == 0)
+ return cmd_usage(cmdtp);
+
+ if (NetLoop(PING) < 0) {
+ printf("ping failed; host %s is not alive\n", argv[1]);
+ return 1;
+ }
+
+ printf("host %s is alive\n", argv[1]);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ ping, 2, 1, do_ping,
+ "send ICMP ECHO_REQUEST to network host",
+ "pingAddress"
+);
+#endif
+
+#if defined(CONFIG_CMD_CDP)
+
+static void cdp_update_env(void)
+{
+ char tmp[16];
+
+ if (CDPApplianceVLAN != htons(-1)) {
+ printf("CDP offered appliance VLAN %d\n", ntohs(CDPApplianceVLAN));
+ VLAN_to_string(CDPApplianceVLAN, tmp);
+ setenv("vlan", tmp);
+ NetOurVLAN = CDPApplianceVLAN;
+ }
+
+ if (CDPNativeVLAN != htons(-1)) {
+ printf("CDP offered native VLAN %d\n", ntohs(CDPNativeVLAN));
+ VLAN_to_string(CDPNativeVLAN, tmp);
+ setenv("nvlan", tmp);
+ NetOurNativeVLAN = CDPNativeVLAN;
+ }
+
+}
+
+int do_cdp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int r;
+
+ r = NetLoop(CDP);
+ if (r < 0) {
+ printf("cdp failed; perhaps not a CISCO switch?\n");
+ return 1;
+ }
+
+ cdp_update_env();
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ cdp, 1, 1, do_cdp,
+ "Perform CDP network configuration",
+ "\n"
+);
+#endif
+
+#if defined(CONFIG_CMD_SNTP)
+int do_sntp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *toff;
+
+ if (argc < 2) {
+ NetNtpServerIP = getenv_IPaddr ("ntpserverip");
+ if (NetNtpServerIP == 0) {
+ printf ("ntpserverip not set\n");
+ return (1);
+ }
+ } else {
+ NetNtpServerIP = string_to_ip(argv[1]);
+ if (NetNtpServerIP == 0) {
+ printf ("Bad NTP server IP address\n");
+ return (1);
+ }
+ }
+
+ toff = getenv ("timeoffset");
+ if (toff == NULL) NetTimeOffset = 0;
+ else NetTimeOffset = simple_strtol (toff, NULL, 10);
+
+ if (NetLoop(SNTP) < 0) {
+ printf("SNTP failed: host %s not responding\n", argv[1]);
+ return 1;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ sntp, 2, 1, do_sntp,
+ "synchronize RTC via network",
+ "[NTP server IP]\n"
+);
+#endif
+
+#if defined(CONFIG_CMD_DNS)
+int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc == 1)
+ return cmd_usage(cmdtp);
+
+ /*
+ * We should check for a valid hostname:
+ * - Each label must be between 1 and 63 characters long
+ * - the entire hostname has a maximum of 255 characters
+ * - only the ASCII letters 'a' through 'z' (case-insensitive),
+ * the digits '0' through '9', and the hyphen
+ * - cannot begin or end with a hyphen
+ * - no other symbols, punctuation characters, or blank spaces are
+ * permitted
+ * but hey - this is a minimalist implmentation, so only check length
+ * and let the name server deal with things.
+ */
+ if (strlen(argv[1]) >= 255) {
+ printf("dns error: hostname too long\n");
+ return 1;
+ }
+
+ NetDNSResolve = argv[1];
+
+ if (argc == 3)
+ NetDNSenvvar = argv[2];
+ else
+ NetDNSenvvar = NULL;
+
+ if (NetLoop(DNS) < 0) {
+ printf("dns lookup of %s failed, check setup\n", argv[1]);
+ return 1;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ dns, 3, 1, do_dns,
+ "lookup the IP of a hostname",
+ "hostname [envvar]"
+);
+
+#endif /* CONFIG_CMD_DNS */
diff --git a/u-boot/common/cmd_nvedit.c b/u-boot/common/cmd_nvedit.c
new file mode 100644
index 0000000..fb69c24
--- /dev/null
+++ b/u-boot/common/cmd_nvedit.c
@@ -0,0 +1,941 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+
+ * 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
+ */
+
+/*
+ * Support for persistent environment data
+ *
+ * The "environment" is stored on external storage as a list of '\0'
+ * terminated "name=value" strings. The end of the list is marked by
+ * a double '\0'. The environment is preceeded by a 32 bit CRC over
+ * the data part and, in case of redundant environment, a byte of
+ * flags.
+ *
+ * This linearized representation will also be used before
+ * relocation, i. e. as long as we don't have a full C runtime
+ * environment. After that, we use a hash table.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <search.h>
+#include <errno.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <serial.h>
+#include <linux/stddef.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_CMD_NET)
+#include <net.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \
+ !defined(CONFIG_ENV_IS_IN_FLASH) && \
+ !defined(CONFIG_ENV_IS_IN_DATAFLASH) && \
+ !defined(CONFIG_ENV_IS_IN_MG_DISK) && \
+ !defined(CONFIG_ENV_IS_IN_MMC) && \
+ !defined(CONFIG_ENV_IS_IN_NAND) && \
+ !defined(CONFIG_ENV_IS_IN_NVRAM) && \
+ !defined(CONFIG_ENV_IS_IN_ONENAND) && \
+ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \
+ !defined(CONFIG_ENV_IS_NOWHERE)
+# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\
+SPI_FLASH|MG_DISK|NVRAM|MMC|NOWHERE}
+#endif
+
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+
+/*
+ * Maximum expected input data size for import command
+ */
+#define MAX_ENV_SIZE (1 << 20) /* 1 MiB */
+
+ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */
+
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
+
+/*
+ * This variable is incremented on each do_env_set(), so it can
+ * be used via get_env_id() as an indication, if the environment
+ * has changed or not. So it is possible to reread an environment
+ * variable only if the environment was changed ... done so for
+ * example in NetInitLoop()
+ */
+static int env_id = 1;
+
+int get_env_id (void)
+{
+ return env_id;
+}
+
+/*
+ * Command interface: print one or all environment variables
+ *
+ * Returns 0 in case of error, or length of printed string
+ */
+static int env_print(char *name)
+{
+ char *res = NULL;
+ size_t len;
+
+ if (name) { /* print a single name */
+ ENTRY e, *ep;
+
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab);
+ if (ep == NULL)
+ return 0;
+ len = printf ("%s=%s\n", ep->key, ep->data);
+ return len;
+ }
+
+ /* print whole list */
+ len = hexport_r(&env_htab, '\n', &res, 0);
+
+ if (len > 0) {
+ puts(res);
+ free(res);
+ return len;
+ }
+
+ /* should never happen */
+ return 0;
+}
+
+int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ int rcode = 0;
+
+ if (argc == 1) {
+ /* print all env vars */
+ rcode = env_print(NULL);
+ if (!rcode)
+ return 1;
+ printf("\nEnvironment size: %d/%ld bytes\n",
+ rcode, (ulong)ENV_SIZE);
+ return 0;
+ }
+
+ /* print selected env vars */
+ for (i = 1; i < argc; ++i) {
+ int rc = env_print(argv[i]);
+ if (!rc) {
+ printf("## Error: \"%s\" not defined\n", argv[i]);
+ ++rcode;
+ }
+ }
+
+ return rcode;
+}
+
+/*
+ * Set a new environment variable,
+ * or replace or delete an existing one.
+ */
+
+int _do_env_set (int flag, int argc, char * const argv[])
+{
+ bd_t *bd = gd->bd;
+ int i, len;
+ int console = -1;
+ char *name, *value, *s;
+ ENTRY e, *ep;
+
+ name = argv[1];
+
+ if (strchr(name, '=')) {
+ printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
+ return 1;
+ }
+
+ env_id++;
+ /*
+ * search if variable with this name already exists
+ */
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab);
+
+ /* Check for console redirection */
+ if (strcmp(name,"stdin") == 0) {
+ console = stdin;
+ } else if (strcmp(name,"stdout") == 0) {
+ console = stdout;
+ } else if (strcmp(name,"stderr") == 0) {
+ console = stderr;
+ }
+
+ if (console != -1) {
+ if (argc < 3) { /* Cannot delete it! */
+ printf("Can't delete \"%s\"\n", name);
+ return 1;
+ }
+
+#ifdef CONFIG_CONSOLE_MUX
+ i = iomux_doenv(console, argv[2]);
+ if (i)
+ return i;
+#else
+ /* Try assigning specified device */
+ if (console_assign (console, argv[2]) < 0)
+ return 1;
+
+#ifdef CONFIG_SERIAL_MULTI
+ if (serial_assign (argv[2]) < 0)
+ return 1;
+#endif
+#endif /* CONFIG_CONSOLE_MUX */
+ }
+
+ /*
+ * Some variables like "ethaddr" and "serial#" can be set only
+ * once and cannot be deleted; also, "ver" is readonly.
+ */
+ if (ep) { /* variable exists */
+#ifndef CONFIG_ENV_OVERWRITE
+ if ((strcmp (name, "serial#") == 0) ||
+ ((strcmp (name, "ethaddr") == 0)
+#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
+ && (strcmp (ep->data,MK_STR(CONFIG_ETHADDR)) != 0)
+#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
+ ) ) {
+ printf ("Can't overwrite \"%s\"\n", name);
+ return 1;
+ }
+#endif
+ /*
+ * Switch to new baudrate if new baudrate is supported
+ */
+ if (strcmp(name,"baudrate") == 0) {
+ int baudrate = simple_strtoul(argv[2], NULL, 10);
+ int i;
+ for (i=0; i<N_BAUDRATES; ++i) {
+ if (baudrate == baudrate_table[i])
+ break;
+ }
+ if (i == N_BAUDRATES) {
+ printf ("## Baudrate %d bps not supported\n",
+ baudrate);
+ return 1;
+ }
+ printf ("## Switch baudrate to %d bps and press ENTER ...\n",
+ baudrate);
+ udelay(50000);
+ gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+ gd->bd->bi_baudrate = baudrate;
+#endif
+
+ serial_setbrg ();
+ udelay(50000);
+ for (;;) {
+ if (getc() == '\r')
+ break;
+ }
+ }
+ }
+
+ /* Delete only ? */
+ if ((argc < 3) || argv[2] == NULL) {
+ int rc = hdelete_r(name, &env_htab);
+ return !rc;
+ }
+
+ /*
+ * Insert / replace new value
+ */
+ for (i=2,len=0; i<argc; ++i) {
+ len += strlen(argv[i]) + 1;
+ }
+ if ((value = malloc(len)) == NULL) {
+ printf("## Can't malloc %d bytes\n", len);
+ return 1;
+ }
+ for (i=2,s=value; i<argc; ++i) {
+ char *v = argv[i];
+
+ while ((*s++ = *v++) != '\0')
+ ;
+ *(s-1) = ' ';
+ }
+ if (s != value)
+ *--s = '\0';
+
+ e.key = name;
+ e.data = value;
+ hsearch_r(e, ENTER, &ep, &env_htab);
+ free(value);
+ if (!ep) {
+ printf("## Error inserting \"%s\" variable, errno=%d\n",
+ name, errno);
+ return 1;
+ }
+
+ /*
+ * Some variables should be updated when the corresponding
+ * entry in the environment is changed
+ */
+
+ if (strcmp(name,"ipaddr") == 0) {
+ char *s = argv[2]; /* always use only one arg */
+ char *e;
+ unsigned long addr;
+ bd->bi_ip_addr = 0;
+ for (addr=0, i=0; i<4; ++i) {
+ ulong val = s ? simple_strtoul(s, &e, 10) : 0;
+ addr <<= 8;
+ addr |= (val & 0xFF);
+ if (s) s = (*e) ? e+1 : e;
+ }
+ bd->bi_ip_addr = htonl(addr);
+ return 0;
+ } else if (strcmp(argv[1],"loadaddr") == 0) {
+ load_addr = simple_strtoul(argv[2], NULL, 16);
+ return 0;
+ }
+#if defined(CONFIG_CMD_NET)
+ else if (strcmp(argv[1],"bootfile") == 0) {
+ copy_filename (BootFile, argv[2], sizeof(BootFile));
+ return 0;
+ }
+#endif
+ return 0;
+}
+
+int setenv (char *varname, char *varvalue)
+{
+ char * const argv[4] = { "setenv", varname, varvalue, NULL };
+ if ((varvalue == NULL) || (varvalue[0] == '\0'))
+ return _do_env_set(0, 2, argv);
+ else
+ return _do_env_set(0, 3, argv);
+}
+
+int do_env_set (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ return _do_env_set(flag, argc, argv);
+}
+
+/*
+ * Prompt for environment variable
+ */
+#if defined(CONFIG_CMD_ASKENV)
+int do_env_ask ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ extern char console_buffer[CONFIG_SYS_CBSIZE];
+ char message[CONFIG_SYS_CBSIZE];
+ int size = CONFIG_SYS_CBSIZE - 1;
+ int i, len, pos;
+ char *local_args[4];
+
+ local_args[0] = argv[0];
+ local_args[1] = argv[1];
+ local_args[2] = NULL;
+ local_args[3] = NULL;
+
+ /* Check the syntax */
+ switch (argc) {
+ case 1:
+ return cmd_usage(cmdtp);
+
+ case 2: /* env_ask envname */
+ sprintf(message, "Please enter '%s':", argv[1]);
+ break;
+
+ case 3: /* env_ask envname size */
+ sprintf(message, "Please enter '%s':", argv[1]);
+ size = simple_strtoul(argv[2], NULL, 10);
+ break;
+
+ default: /* env_ask envname message1 ... messagen size */
+ for (i=2,pos=0; i < argc - 1; i++) {
+ if (pos) {
+ message[pos++] = ' ';
+ }
+ strcpy(message+pos, argv[i]);
+ pos += strlen(argv[i]);
+ }
+ message[pos] = '\0';
+ size = simple_strtoul(argv[argc - 1], NULL, 10);
+ break;
+ }
+
+ if (size >= CONFIG_SYS_CBSIZE)
+ size = CONFIG_SYS_CBSIZE - 1;
+
+ if (size <= 0)
+ return 1;
+
+ /* prompt for input */
+ len = readline(message);
+
+ if (size < len)
+ console_buffer[size] = '\0';
+
+ len = 2;
+ if (console_buffer[0] != '\0') {
+ local_args[2] = console_buffer;
+ len = 3;
+ }
+
+ /* Continue calling setenv code */
+ return _do_env_set(flag, len, local_args);
+}
+#endif
+
+/*
+ * Interactively edit an environment variable
+ */
+#if defined(CONFIG_CMD_EDITENV)
+int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char buffer[CONFIG_SYS_CBSIZE];
+ char *init_val;
+ int len;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /* Set read buffer to initial value or empty sting */
+ init_val = getenv(argv[1]);
+ if (init_val)
+ len = sprintf(buffer, "%s", init_val);
+ else
+ buffer[0] = '\0';
+
+ readline_into_buffer("edit: ", buffer);
+
+ return setenv(argv[1], buffer);
+}
+#endif /* CONFIG_CMD_EDITENV */
+
+/*
+ * Look up variable from environment,
+ * return address of storage for that variable,
+ * or NULL if not found
+ */
+char *getenv (char *name)
+{
+ if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
+ ENTRY e, *ep;
+
+ WATCHDOG_RESET();
+
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab);
+
+ return (ep ? ep->data : NULL);
+ }
+
+ /* restricted capabilities before import */
+
+ if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
+ return (char *)(gd->env_buf);
+
+ return NULL;
+}
+
+/*
+ * Look up variable from environment for restricted C runtime env.
+ */
+int getenv_f (char *name, char *buf, unsigned len)
+{
+ int i, nxt;
+
+ for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
+ int val, n;
+
+ for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
+ if (nxt >= CONFIG_ENV_SIZE) {
+ return (-1);
+ }
+ }
+ if ((val=envmatch((uchar *)name, i)) < 0)
+ continue;
+
+ /* found; copy out */
+ for (n=0; n<len; ++n, ++buf) {
+ if ((*buf = env_get_char(val++)) == '\0')
+ return n;
+ }
+
+ if (n)
+ *--buf = '\0';
+
+ printf("env_buf too small [%d]\n", len);
+
+ return n;
+ }
+ return (-1);
+}
+
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+
+int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ extern char * env_name_spec;
+
+ printf ("Saving Environment to %s...\n", env_name_spec);
+
+ return (saveenv() ? 1 : 0);
+}
+
+U_BOOT_CMD(
+ saveenv, 1, 0, do_env_save,
+ "save environment variables to persistent storage",
+ ""
+);
+
+#endif
+
+
+/*
+ * Match a name / name=value pair
+ *
+ * s1 is either a simple 'name', or a 'name=value' pair.
+ * i2 is the environment index for a 'name2=value2' pair.
+ * If the names match, return the index for the value2, else NULL.
+ */
+
+int envmatch (uchar *s1, int i2)
+{
+
+ while (*s1 == env_get_char(i2++))
+ if (*s1++ == '=')
+ return(i2);
+ if (*s1 == '\0' && env_get_char(i2-1) == '=')
+ return(i2);
+ return(-1);
+}
+
+static int do_env_default(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ if ((argc != 2) || (strcmp(argv[1], "-f") != 0)) {
+ return cmd_usage(cmdtp);
+ }
+ set_default_env("## Resetting to default environment\n");
+ return 0;
+}
+
+static int do_env_delete(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("Not implemented yet\n");
+ return 0;
+}
+
+/*
+ * env export [-t | -b | -c] addr [size]
+ * -t: export as text format; if size is given, data will be
+ * padded with '\0' bytes; if not, one terminating '\0'
+ * will be added (which is included in the "filesize"
+ * setting so you can for exmple copy this to flash and
+ * keep the termination).
+ * -b: export as binary format (name=value pairs separated by
+ * '\0', list end marked by double "\0\0")
+ * -c: export as checksum protected environment format as
+ * used for example by "saveenv" command
+ * addr: memory address where environment gets stored
+ * size: size of output buffer
+ *
+ * With "-c" and size is NOT given, then the export command will
+ * format the data as currently used for the persistent storage,
+ * i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
+ * prepend a valid CRC32 checksum and, in case of resundant
+ * environment, a "current" redundancy flag. If size is given, this
+ * value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
+ * checksum and redundancy flag will be inserted.
+ *
+ * With "-b" and "-t", always only the real data (including a
+ * terminating '\0' byte) will be written; here the optional size
+ * argument will be used to make sure not to overflow the user
+ * provided buffer; the command will abort if the size is not
+ * sufficient. Any remainign space will be '\0' padded.
+ *
+ * On successful return, the variable "filesize" will be set.
+ * Note that filesize includes the trailing/terminating '\0' byte(s).
+ *
+ * Usage szenario: create a text snapshot/backup of the current settings:
+ *
+ * => env export -t 100000
+ * => era ${backup_addr} +${filesize}
+ * => cp.b 100000 ${backup_addr} ${filesize}
+ *
+ * Re-import this snapshot, deleting all other settings:
+ *
+ * => env import -d -t ${backup_addr}
+ */
+static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char buf[32];
+ char *addr, *cmd, *res;
+ size_t size;
+ ssize_t len;
+ env_t *envp;
+ char sep = '\n';
+ int chk = 0;
+ int fmt = 0;
+
+ cmd = *argv;
+
+ while (--argc > 0 && **++argv == '-') {
+ char *arg = *argv;
+ while (*++arg) {
+ switch (*arg) {
+ case 'b': /* raw binary format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\0';
+ break;
+ case 'c': /* external checksum format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\0';
+ chk = 1;
+ break;
+ case 't': /* text format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\n';
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ }
+ }
+
+ if (argc < 1) {
+ return cmd_usage(cmdtp);
+ }
+
+ addr = (char *)simple_strtoul(argv[0], NULL, 16);
+
+ if (argc == 2) {
+ size = simple_strtoul(argv[1], NULL, 16);
+ memset(addr, '\0', size);
+ } else {
+ size = 0;
+ }
+
+ if (sep) { /* export as text file */
+ len = hexport_r(&env_htab, sep, &addr, size);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n",
+ errno);
+ return 1;
+ }
+ sprintf(buf, "%zX", len);
+ setenv("filesize", buf);
+
+ return 0;
+ }
+
+ envp = (env_t *)addr;
+
+ if (chk) /* export as checksum protected block */
+ res = (char *)envp->data;
+ else /* export as raw binary data */
+ res = addr;
+
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n",
+ errno);
+ return 1;
+ }
+
+ if (chk) {
+ envp->crc = crc32(0, envp->data, ENV_SIZE);
+#ifdef CONFIG_ENV_ADDR_REDUND
+ envp->flags = ACTIVE_FLAG;
+#endif
+ }
+ sprintf(buf, "%zX", len + offsetof(env_t,data));
+ setenv("filesize", buf);
+
+ return 0;
+
+sep_err:
+ printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+ cmd);
+ return 1;
+}
+
+/*
+ * env import [-d] [-t | -b | -c] addr [size]
+ * -d: delete existing environment before importing;
+ * otherwise overwrite / append to existion definitions
+ * -t: assume text format; either "size" must be given or the
+ * text data must be '\0' terminated
+ * -b: assume binary format ('\0' separated, "\0\0" terminated)
+ * -c: assume checksum protected environment format
+ * addr: memory address to read from
+ * size: length of input data; if missing, proper '\0'
+ * termination is mandatory
+ */
+static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ char *cmd, *addr;
+ char sep = '\n';
+ int chk = 0;
+ int fmt = 0;
+ int del = 0;
+ size_t size;
+
+ cmd = *argv;
+
+ while (--argc > 0 && **++argv == '-') {
+ char *arg = *argv;
+ while (*++arg) {
+ switch (*arg) {
+ case 'b': /* raw binary format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\0';
+ break;
+ case 'c': /* external checksum format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\0';
+ chk = 1;
+ break;
+ case 't': /* text format */
+ if (fmt++)
+ goto sep_err;
+ sep = '\n';
+ break;
+ case 'd':
+ del = 1;
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ }
+ }
+
+ if (argc < 1) {
+ return cmd_usage(cmdtp);
+ }
+
+ if (!fmt)
+ printf("## Warning: defaulting to text format\n");
+
+ addr = (char *)simple_strtoul(argv[0], NULL, 16);
+
+ if (argc == 2) {
+ size = simple_strtoul(argv[1], NULL, 16);
+ } else {
+ char *s = addr;
+
+ size = 0;
+
+ while (size < MAX_ENV_SIZE) {
+ if ((*s == sep) && (*(s+1) == '\0'))
+ break;
+ ++s;
+ ++size;
+ }
+ if (size == MAX_ENV_SIZE) {
+ printf("## Warning: Input data exceeds %d bytes"
+ " - truncated\n", MAX_ENV_SIZE);
+ }
+ ++size;
+ printf("## Info: input data size = %zd = 0x%zX\n", size, size);
+ }
+
+ if (chk) {
+ uint32_t crc;
+ env_t *ep = (env_t *)addr;
+
+ size -= offsetof(env_t, data);
+ memcpy(&crc, &ep->crc, sizeof(crc));
+
+ if (crc32(0, ep->data, size) != crc) {
+ puts("## Error: bad CRC, import failed\n");
+ return 1;
+ }
+ addr = (char *)ep->data;
+ }
+
+ if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR) == 0) {
+ error("Environment import failed: errno = %d\n", errno);
+ return 1;
+ }
+ gd->flags |= GD_FLG_ENV_READY;
+
+ return 0;
+
+sep_err:
+ printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+ cmd);
+ return 1;
+}
+
+#if defined(CONFIG_CMD_RUN)
+extern int do_run (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+
+/*
+ * New command line interface: "env" command with subcommands
+ */
+static cmd_tbl_t cmd_env_sub[] = {
+#if defined(CONFIG_CMD_ASKENV)
+ U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
+ U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+#if defined(CONFIG_CMD_EDITENV)
+ U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
+ U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""),
+ U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""),
+#if defined(CONFIG_CMD_RUN)
+ U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""),
+#endif
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+ U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""),
+};
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+void env_reloc(void)
+{
+ fixup_cmdtable(cmd_env_sub, ARRAY_SIZE(cmd_env_sub));
+}
+#endif
+
+static int do_env (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *cp;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ /* drop initial "env" arg */
+ argc--;
+ argv++;
+
+ cp = find_cmd_tbl(argv[0], cmd_env_sub, ARRAY_SIZE(cmd_env_sub));
+
+ if (cp)
+ return cp->cmd(cmdtp, flag, argc, argv);
+
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ env, CONFIG_SYS_MAXARGS, 1, do_env,
+ "environment handling commands",
+#if defined(CONFIG_CMD_ASKENV)
+ "ask name [message] [size] - ask for environment variable\nenv "
+#endif
+ "default -f - reset default environment\n"
+#if defined(CONFIG_CMD_EDITENV)
+ "env edit name - edit environment variable\n"
+#endif
+ "env export [-t | -b | -c] addr [size] - export environmnt\n"
+ "env import [-d] [-t | -b | -c] addr [size] - import environmnt\n"
+ "env print [name ...] - print environment\n"
+#if defined(CONFIG_CMD_RUN)
+ "env run var [...] - run commands in an environment variable\n"
+#endif
+ "env save - save environment\n"
+ "env set [-f] name [arg ...]\n"
+);
+
+/*
+ * Old command line interface, kept for compatibility
+ */
+
+#if defined(CONFIG_CMD_EDITENV)
+U_BOOT_CMD_COMPLETE(
+ editenv, 2, 0, do_env_edit,
+ "edit environment variable",
+ "name\n"
+ " - edit environment variable 'name'",
+ var_complete
+);
+#endif
+
+U_BOOT_CMD_COMPLETE(
+ printenv, CONFIG_SYS_MAXARGS, 1, do_env_print,
+ "print environment variables",
+ "\n - print values of all environment variables\n"
+ "printenv name ...\n"
+ " - print value of environment variable 'name'",
+ var_complete
+);
+
+U_BOOT_CMD_COMPLETE(
+ setenv, CONFIG_SYS_MAXARGS, 0, do_env_set,
+ "set environment variables",
+ "name value ...\n"
+ " - set environment variable 'name' to 'value ...'\n"
+ "setenv name\n"
+ " - delete environment variable 'name'",
+ var_complete
+);
+
+#if defined(CONFIG_CMD_ASKENV)
+
+U_BOOT_CMD(
+ askenv, CONFIG_SYS_MAXARGS, 1, do_env_ask,
+ "get environment variables from stdin",
+ "name [message] [size]\n"
+ " - get environment variable 'name' from stdin (max 'size' chars)\n"
+ "askenv name\n"
+ " - get environment variable 'name' from stdin\n"
+ "askenv name size\n"
+ " - get environment variable 'name' from stdin (max 'size' chars)\n"
+ "askenv name [message] size\n"
+ " - display 'message' string and get environment variable 'name'"
+ "from stdin (max 'size' chars)"
+);
+#endif
+
+#if defined(CONFIG_CMD_RUN)
+U_BOOT_CMD_COMPLETE(
+ run, CONFIG_SYS_MAXARGS, 1, do_run,
+ "run commands in an environment variable",
+ "var [...]\n"
+ " - run the commands in the environment variable(s) 'var'",
+ var_complete
+);
+#endif
diff --git a/u-boot/common/cmd_onenand.c b/u-boot/common/cmd_onenand.c
new file mode 100644
index 0000000..a27adaa
--- /dev/null
+++ b/u-boot/common/cmd_onenand.c
@@ -0,0 +1,602 @@
+/*
+ * U-Boot command for OneNAND support
+ *
+ * Copyright (C) 2005-2008 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <asm/io.h>
+
+static struct mtd_info *mtd;
+
+static loff_t next_ofs;
+static loff_t skip_ofs;
+
+static inline int str2long(char *p, ulong *num)
+{
+ char *endptr;
+
+ *num = simple_strtoul(p, &endptr, 16);
+ return (*p != '\0' && *endptr == '\0') ? 1 : 0;
+}
+
+static int arg_off_size(int argc, char * const argv[], ulong *off, size_t *size)
+{
+ if (argc >= 1) {
+ if (!(str2long(argv[0], off))) {
+ printf("'%s' is not a number\n", argv[0]);
+ return -1;
+ }
+ } else {
+ *off = 0;
+ }
+
+ if (argc >= 2) {
+ if (!(str2long(argv[1], (ulong *)size))) {
+ printf("'%s' is not a number\n", argv[1]);
+ return -1;
+ }
+ } else {
+ *size = mtd->size - *off;
+ }
+
+ if ((*off + *size) > mtd->size) {
+ printf("total chip size (0x%llx) exceeded!\n", mtd->size);
+ return -1;
+ }
+
+ if (*size == mtd->size)
+ puts("whole chip\n");
+ else
+ printf("offset 0x%lx, size 0x%x\n", *off, *size);
+
+ return 0;
+}
+
+static int onenand_block_read(loff_t from, size_t len,
+ size_t *retlen, u_char *buf, int oob)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blocks = (int) len >> this->erase_shift;
+ int blocksize = (1 << this->erase_shift);
+ loff_t ofs = from;
+ struct mtd_oob_ops ops = {
+ .retlen = 0,
+ };
+ int ret;
+
+ if (oob)
+ ops.ooblen = blocksize;
+ else
+ ops.len = blocksize;
+
+ while (blocks) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ printk("Bad blocks %d at 0x%x\n",
+ (u32)(ofs >> this->erase_shift), (u32)ofs);
+ ofs += blocksize;
+ continue;
+ }
+
+ if (oob)
+ ops.oobbuf = buf;
+ else
+ ops.datbuf = buf;
+
+ ops.retlen = 0;
+ ret = mtd->read_oob(mtd, ofs, &ops);
+ if (ret) {
+ printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
+ ofs += blocksize;
+ continue;
+ }
+ ofs += blocksize;
+ buf += blocksize;
+ blocks--;
+ *retlen += ops.retlen;
+ }
+
+ return 0;
+}
+
+static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
+ size_t *retlen)
+{
+ struct mtd_oob_ops ops = {
+ .len = mtd->writesize,
+ .ooblen = mtd->oobsize,
+ .mode = MTD_OOB_AUTO,
+ };
+ int page, ret = 0;
+ for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) {
+ ops.datbuf = (u_char *)buf;
+ buf += mtd->writesize;
+ ops.oobbuf = (u_char *)buf;
+ buf += mtd->oobsize;
+ ret = mtd->write_oob(mtd, to, &ops);
+ if (ret)
+ break;
+ to += mtd->writesize;
+ }
+
+ *retlen = (ret) ? 0 : mtd->erasesize;
+ return ret;
+}
+
+static int onenand_block_write(loff_t to, size_t len,
+ size_t *retlen, const u_char * buf, int withoob)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blocks = len >> this->erase_shift;
+ int blocksize = (1 << this->erase_shift);
+ loff_t ofs;
+ size_t _retlen = 0;
+ int ret;
+
+ if (to == next_ofs) {
+ next_ofs = to + len;
+ to += skip_ofs;
+ } else {
+ next_ofs = to + len;
+ skip_ofs = 0;
+ }
+ ofs = to;
+
+ while (blocks) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ printk("Bad blocks %d at 0x%x\n",
+ (u32)(ofs >> this->erase_shift), (u32)ofs);
+ skip_ofs += blocksize;
+ goto next;
+ }
+
+ if (!withoob)
+ ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
+ else
+ ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
+ if (ret) {
+ printk("Write failed 0x%x, %d", (u32)ofs, ret);
+ skip_ofs += blocksize;
+ goto next;
+ }
+
+ buf += blocksize;
+ blocks--;
+ *retlen += _retlen;
+next:
+ ofs += blocksize;
+ }
+
+ return 0;
+}
+
+static int onenand_block_erase(u32 start, u32 size, int force)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct erase_info instr = {
+ .callback = NULL,
+ };
+ loff_t ofs;
+ int ret;
+ int blocksize = 1 << this->erase_shift;
+
+ for (ofs = start; ofs < (start + size); ofs += blocksize) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret && !force) {
+ printf("Skip erase bad block %d at 0x%x\n",
+ (u32)(ofs >> this->erase_shift), (u32)ofs);
+ continue;
+ }
+
+ instr.addr = ofs;
+ instr.len = blocksize;
+ instr.priv = force;
+ instr.mtd = mtd;
+ ret = mtd->erase(mtd, &instr);
+ if (ret) {
+ printf("erase failed block %d at 0x%x\n",
+ (u32)(ofs >> this->erase_shift), (u32)ofs);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+static int onenand_block_test(u32 start, u32 size)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct erase_info instr = {
+ .callback = NULL,
+ .priv = 0,
+ };
+
+ int blocks;
+ loff_t ofs;
+ int blocksize = 1 << this->erase_shift;
+ int start_block, end_block;
+ size_t retlen;
+ u_char *buf;
+ u_char *verify_buf;
+ int ret;
+
+ buf = malloc(blocksize);
+ if (!buf) {
+ printf("Not enough malloc space available!\n");
+ return -1;
+ }
+
+ verify_buf = malloc(blocksize);
+ if (!verify_buf) {
+ printf("Not enough malloc space available!\n");
+ return -1;
+ }
+
+ start_block = start >> this->erase_shift;
+ end_block = (start + size) >> this->erase_shift;
+
+ /* Protect boot-loader from badblock testing */
+ if (start_block < 2)
+ start_block = 2;
+
+ if (end_block > (mtd->size >> this->erase_shift))
+ end_block = mtd->size >> this->erase_shift;
+
+ blocks = start_block;
+ ofs = start;
+ while (blocks < end_block) {
+ printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
+
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ printf("Skip erase bad block %d at 0x%x\n",
+ (u32)(ofs >> this->erase_shift), (u32)ofs);
+ goto next;
+ }
+
+ instr.addr = ofs;
+ instr.len = blocksize;
+ ret = mtd->erase(mtd, &instr);
+ if (ret) {
+ printk("Erase failed 0x%x, %d\n", (u32)ofs, ret);
+ goto next;
+ }
+
+ ret = mtd->write(mtd, ofs, blocksize, &retlen, buf);
+ if (ret) {
+ printk("Write failed 0x%x, %d\n", (u32)ofs, ret);
+ goto next;
+ }
+
+ ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf);
+ if (ret) {
+ printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
+ goto next;
+ }
+
+ if (memcmp(buf, verify_buf, blocksize))
+ printk("\nRead/Write test failed at 0x%x\n", (u32)ofs);
+
+next:
+ ofs += blocksize;
+ blocks++;
+ }
+ printf("...Done\n");
+
+ free(buf);
+ free(verify_buf);
+
+ return 0;
+}
+
+static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
+{
+ int i;
+ u_char *datbuf, *oobbuf, *p;
+ struct mtd_oob_ops ops;
+ loff_t addr;
+
+ datbuf = malloc(mtd->writesize + mtd->oobsize);
+ oobbuf = malloc(mtd->oobsize);
+ if (!datbuf || !oobbuf) {
+ puts("No memory for page buffer\n");
+ return 1;
+ }
+ off &= ~(mtd->writesize - 1);
+ addr = (loff_t) off;
+ memset(&ops, 0, sizeof(ops));
+ ops.datbuf = datbuf;
+ ops.oobbuf = oobbuf;
+ ops.len = mtd->writesize;
+ ops.ooblen = mtd->oobsize;
+ ops.retlen = 0;
+ i = mtd->read_oob(mtd, addr, &ops);
+ if (i < 0) {
+ printf("Error (%d) reading page %08lx\n", i, off);
+ free(datbuf);
+ free(oobbuf);
+ return 1;
+ }
+ printf("Page %08lx dump:\n", off);
+ i = mtd->writesize >> 4;
+ p = datbuf;
+
+ while (i--) {
+ if (!only_oob)
+ printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14],
+ p[15]);
+ p += 16;
+ }
+ puts("OOB:\n");
+ i = mtd->oobsize >> 3;
+ p = oobbuf;
+
+ while (i--) {
+ printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ free(datbuf);
+ free(oobbuf);
+
+ return 0;
+}
+
+static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("%s\n", mtd->name);
+ return 0;
+}
+
+static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong ofs;
+
+ mtd = &onenand_mtd;
+ /* Currently only one OneNAND device is supported */
+ printf("\nDevice %d bad blocks:\n", 0);
+ for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) {
+ if (mtd->block_isbad(mtd, ofs))
+ printf(" %08x\n", (u32)ofs);
+ }
+
+ return 0;
+}
+
+static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ char *s;
+ int oob = 0;
+ ulong addr, ofs;
+ size_t len;
+ int ret = 0;
+ size_t retlen = 0;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ s = strchr(argv[0], '.');
+ if ((s != NULL) && (!strcmp(s, ".oob")))
+ oob = 1;
+
+ addr = (ulong)simple_strtoul(argv[1], NULL, 16);
+
+ printf("\nOneNAND read: ");
+ if (arg_off_size(argc - 2, argv + 2, &ofs, &len) != 0)
+ return 1;
+
+ ret = onenand_block_read(ofs, len, &retlen, (u8 *)addr, oob);
+
+ printf(" %d bytes read: %s\n", retlen, ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr, ofs;
+ size_t len;
+ int ret = 0, withoob = 0;
+ size_t retlen = 0;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ if (strncmp(argv[0] + 6, "yaffs", 5) == 0)
+ withoob = 1;
+
+ addr = (ulong)simple_strtoul(argv[1], NULL, 16);
+
+ printf("\nOneNAND write: ");
+ if (arg_off_size(argc - 2, argv + 2, &ofs, &len) != 0)
+ return 1;
+
+ ret = onenand_block_write(ofs, len, &retlen, (u8 *)addr, withoob);
+
+ printf(" %d bytes written: %s\n", retlen, ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong ofs;
+ int ret = 0;
+ size_t len;
+ int force;
+
+ /*
+ * Syntax is:
+ * 0 1 2 3 4
+ * onenand erase [force] [off size]
+ */
+ argc--;
+ argv++;
+ if (argc)
+ {
+ if (!strcmp("force", argv[0]))
+ {
+ force = 1;
+ argc--;
+ argv++;
+ }
+ }
+ printf("\nOneNAND erase: ");
+
+ /* skip first two or three arguments, look for offset and size */
+ if (arg_off_size(argc, argv, &ofs, &len) != 0)
+ return 1;
+
+ ret = onenand_block_erase(ofs, len, force);
+
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong ofs;
+ int ret = 0;
+ size_t len;
+
+ /*
+ * Syntax is:
+ * 0 1 2 3 4
+ * onenand test [force] [off size]
+ */
+
+ printf("\nOneNAND test: ");
+
+ /* skip first two or three arguments, look for offset and size */
+ if (arg_off_size(argc - 1, argv + 1, &ofs, &len) != 0)
+ return 1;
+
+ ret = onenand_block_test(ofs, len);
+
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+}
+
+static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong ofs;
+ int ret = 0;
+ char *s;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ s = strchr(argv[0], '.');
+ ofs = (int)simple_strtoul(argv[1], NULL, 16);
+
+ if (s != NULL && strcmp(s, ".oob") == 0)
+ ret = onenand_dump(mtd, ofs, 1);
+ else
+ ret = onenand_dump(mtd, ofs, 0);
+
+ return ret == 0 ? 1 : 0;
+}
+
+static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int ret = 0;
+ ulong addr;
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc <= 0)
+ return cmd_usage(cmdtp);
+
+ while (argc > 0) {
+ addr = simple_strtoul(*argv, NULL, 16);
+
+ if (mtd->block_markbad(mtd, addr)) {
+ printf("block 0x%08lx NOT marked "
+ "as bad! ERROR %d\n",
+ addr, ret);
+ ret = 1;
+ } else {
+ printf("block 0x%08lx successfully "
+ "marked as bad\n",
+ addr);
+ }
+ --argc;
+ ++argv;
+ }
+ return ret;
+}
+
+static cmd_tbl_t cmd_onenand_sub[] = {
+ U_BOOT_CMD_MKENT(info, 1, 0, do_onenand_info, "", ""),
+ U_BOOT_CMD_MKENT(bad, 1, 0, do_onenand_bad, "", ""),
+ U_BOOT_CMD_MKENT(read, 4, 0, do_onenand_read, "", ""),
+ U_BOOT_CMD_MKENT(write, 4, 0, do_onenand_write, "", ""),
+ U_BOOT_CMD_MKENT(write.yaffs, 4, 0, do_onenand_write, "", ""),
+ U_BOOT_CMD_MKENT(erase, 3, 0, do_onenand_erase, "", ""),
+ U_BOOT_CMD_MKENT(test, 3, 0, do_onenand_test, "", ""),
+ U_BOOT_CMD_MKENT(dump, 2, 0, do_onenand_dump, "", ""),
+ U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 0, do_onenand_markbad, "", ""),
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+void onenand_reloc(void) {
+ fixup_cmdtable(cmd_onenand_sub, ARRAY_SIZE(cmd_onenand_sub));
+}
+#endif
+
+static int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ mtd = &onenand_mtd;
+
+ /* Strip off leading 'onenand' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_onenand_sub[0], ARRAY_SIZE(cmd_onenand_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ onenand, CONFIG_SYS_MAXARGS, 1, do_onenand,
+ "OneNAND sub-system",
+ "info - show available OneNAND devices\n"
+ "onenand bad - show bad blocks\n"
+ "onenand read[.oob] addr off size\n"
+ "onenand write[.yaffs] addr off size\n"
+ " read/write 'size' bytes starting at offset 'off'\n"
+ " to/from memory address 'addr', skipping bad blocks.\n"
+ "onenand erase [force] [off size] - erase 'size' bytes from\n"
+ "onenand test [off size] - test 'size' bytes from\n"
+ " offset 'off' (entire device if not specified)\n"
+ "onenand dump[.oob] off - dump page\n"
+ "onenand markbad off [...] - mark bad block(s) at offset (UNSAFE)"
+);
diff --git a/u-boot/common/cmd_otp.c b/u-boot/common/cmd_otp.c
new file mode 100644
index 0000000..eb93eb2
--- /dev/null
+++ b/u-boot/common/cmd_otp.c
@@ -0,0 +1,238 @@
+/*
+ * cmd_otp.c - interface to Blackfin on-chip One-Time-Programmable memory
+ *
+ * Copyright (c) 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* There are 512 128-bit "pages" (0x000 through 0x1FF).
+ * The pages are accessable as 64-bit "halfpages" (an upper and lower half).
+ * The pages are not part of the memory map. There is an OTP controller which
+ * handles scanning in/out of bits. While access is done through OTP MMRs,
+ * the bootrom provides C-callable helper functions to handle the interaction.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/otp.h>
+
+static const char *otp_strerror(uint32_t err)
+{
+ switch (err) {
+ case 0: return "no error";
+ case OTP_WRITE_ERROR: return "OTP fuse write error";
+ case OTP_READ_ERROR: return "OTP fuse read error";
+ case OTP_ACC_VIO_ERROR: return "invalid OTP address";
+ case OTP_DATA_MULT_ERROR: return "multiple bad bits detected";
+ case OTP_ECC_MULT_ERROR: return "error in ECC bits";
+ case OTP_PREV_WR_ERROR: return "space already written";
+ case OTP_DATA_SB_WARN: return "single bad bit in half page";
+ case OTP_ECC_SB_WARN: return "single bad bit in ECC";
+ default: return "unknown error";
+ }
+}
+
+#define lowup(x) ((x) % 2 ? "upper" : "lower")
+
+static int check_voltage(void)
+{
+ /* Make sure voltage limits are within datasheet spec */
+ uint16_t vr_ctl = bfin_read_VR_CTL();
+
+#ifdef __ADSPBF54x__
+ /* 0.9V <= VDDINT <= 1.1V */
+ if ((vr_ctl & 0xc) && (vr_ctl & 0xc0) == 0xc0)
+ return 1;
+#else
+ /* for the parts w/out qualification yet */
+ (void)vr_ctl;
+#endif
+
+ return 0;
+}
+
+static void set_otp_timing(bool write)
+{
+ static uint32_t timing;
+ if (!timing) {
+ uint32_t tp1, tp2, tp3;
+ /* OTP_TP1 = 1000 / sclk_period (in nanoseconds)
+ * OTP_TP1 = 1000 / (1 / get_sclk() * 10^9)
+ * OTP_TP1 = (1000 * get_sclk()) / 10^9
+ * OTP_TP1 = get_sclk() / 10^6
+ */
+ tp1 = get_sclk() / 1000000;
+ /* OTP_TP2 = 400 / (2 * sclk_period)
+ * OTP_TP2 = 400 / (2 * 1 / get_sclk() * 10^9)
+ * OTP_TP2 = (400 * get_sclk()) / (2 * 10^9)
+ * OTP_TP2 = (2 * get_sclk()) / 10^7
+ */
+ tp2 = (2 * get_sclk() / 10000000) << 8;
+ /* OTP_TP3 = magic constant */
+ tp3 = (0x1401) << 15;
+ timing = tp1 | tp2 | tp3;
+ }
+
+ bfrom_OtpCommand(OTP_INIT, write ? timing : timing & ~(-1 << 15));
+}
+
+int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *cmd;
+ uint32_t ret, base_flags;
+ bool prompt_user, force_read;
+ uint32_t (*otp_func)(uint32_t page, uint32_t flags, uint64_t *page_content);
+
+ if (argc < 4) {
+ usage:
+ return cmd_usage(cmdtp);
+ }
+
+ prompt_user = false;
+ base_flags = 0;
+ cmd = argv[1];
+ if (!strcmp(cmd, "read"))
+ otp_func = bfrom_OtpRead;
+ else if (!strcmp(cmd, "dump")) {
+ otp_func = bfrom_OtpRead;
+ force_read = true;
+ } else if (!strcmp(cmd, "write")) {
+ otp_func = bfrom_OtpWrite;
+ base_flags = OTP_CHECK_FOR_PREV_WRITE;
+ if (!strcmp(argv[2], "--force")) {
+ argv++;
+ --argc;
+ } else
+ prompt_user = false;
+ } else if (!strcmp(cmd, "lock")) {
+ if (argc != 4)
+ goto usage;
+ otp_func = bfrom_OtpWrite;
+ base_flags = OTP_LOCK;
+ } else
+ goto usage;
+
+ uint64_t *addr = (uint64_t *)simple_strtoul(argv[2], NULL, 16);
+ uint32_t page = simple_strtoul(argv[3], NULL, 16);
+ uint32_t flags;
+ size_t i, count;
+ ulong half;
+
+ if (argc > 4)
+ count = simple_strtoul(argv[4], NULL, 16);
+ else
+ count = 2;
+
+ if (argc > 5) {
+ half = simple_strtoul(argv[5], NULL, 16);
+ if (half != 0 && half != 1) {
+ puts("Error: 'half' can only be '0' or '1'\n");
+ goto usage;
+ }
+ } else
+ half = 0;
+
+ /* "otp lock" has slightly different semantics */
+ if (base_flags & OTP_LOCK) {
+ count = page;
+ page = (uint32_t)addr;
+ addr = NULL;
+ }
+
+ /* do to the nature of OTP, make sure users are sure */
+ if (prompt_user) {
+ printf(
+ "Writing one time programmable memory\n"
+ "Make sure your operating voltages and temperature are within spec\n"
+ " source address: 0x%p\n"
+ " OTP destination: %s page 0x%03X - %s page 0x%03lX\n"
+ " number to write: %lu halfpages\n"
+ " type \"YES\" (no quotes) to confirm: ",
+ addr,
+ lowup(half), page,
+ lowup(half + count - 1), page + (half + count - 1) / 2,
+ half + count
+ );
+
+ i = 0;
+ while (1) {
+ if (tstc()) {
+ const char exp_ans[] = "YES\r";
+ char c;
+ putc(c = getc());
+ if (exp_ans[i++] != c) {
+ printf(" Aborting\n");
+ return 1;
+ } else if (!exp_ans[i]) {
+ puts("\n");
+ break;
+ }
+ }
+ }
+ }
+
+ printf("OTP memory %s: addr 0x%p page 0x%03X count %zu ... ",
+ cmd, addr, page, count);
+
+ set_otp_timing(otp_func == bfrom_OtpWrite);
+ if (otp_func == bfrom_OtpWrite && check_voltage()) {
+ puts("ERROR: VDDINT voltage is out of spec for writing\n");
+ return -1;
+ }
+
+ /* Do the actual reading/writing stuff */
+ ret = 0;
+ for (i = half; i < count + half; ++i) {
+ flags = base_flags | (i % 2 ? OTP_UPPER_HALF : OTP_LOWER_HALF);
+ try_again:
+ ret = otp_func(page, flags, addr);
+ if (ret & OTP_MASTER_ERROR) {
+ if (force_read) {
+ if (flags & OTP_NO_ECC)
+ break;
+ else
+ flags |= OTP_NO_ECC;
+ puts("E");
+ goto try_again;
+ } else
+ break;
+ } else if (ret)
+ puts("W");
+ else
+ puts(".");
+ if (!(base_flags & OTP_LOCK)) {
+ ++addr;
+ if (i % 2)
+ ++page;
+ } else
+ ++page;
+ }
+ if (ret & 0x1)
+ printf("\nERROR at page 0x%03X (%s-halfpage): 0x%03X: %s\n",
+ page, lowup(i), ret, otp_strerror(ret));
+ else
+ puts(" done\n");
+
+ /* Make sure we disable writing */
+ set_otp_timing(false);
+ bfrom_OtpCommand(OTP_CLOSE, 0);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ otp, 7, 0, do_otp,
+ "One-Time-Programmable sub-system",
+ "read <addr> <page> [count] [half]\n"
+ " - read 'count' half-pages starting at 'page' (offset 'half') to 'addr'\n"
+ "otp dump <addr> <page> [count] [half]\n"
+ " - like 'otp read', but skip read errors\n"
+ "otp write [--force] <addr> <page> [count] [half]\n"
+ " - write 'count' half-pages starting at 'page' (offset 'half') from 'addr'\n"
+ "otp lock <page> <count>\n"
+ " - lock 'count' pages starting at 'page'"
+);
diff --git a/u-boot/common/cmd_pci.c b/u-boot/common/cmd_pci.c
new file mode 100644
index 0000000..92631ea
--- /dev/null
+++ b/u-boot/common/cmd_pci.c
@@ -0,0 +1,509 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+unsigned char ShortPCIListing = 1;
+
+/*
+ * Follows routines for the output of infos about devices on PCI bus.
+ */
+
+void pci_header_show(pci_dev_t dev);
+void pci_header_show_brief(pci_dev_t dev);
+
+/*
+ * Subroutine: pciinfo
+ *
+ * Description: Show information about devices on PCI bus.
+ * Depending on the define CONFIG_SYS_SHORT_PCI_LISTING
+ * the output will be more or less exhaustive.
+ *
+ * Inputs: bus_no the number of the bus to be scanned.
+ *
+ * Return: None
+ *
+ */
+void pciinfo(int BusNum, int ShortPCIListing)
+{
+ int Device;
+ int Function;
+ unsigned char HeaderType;
+ unsigned short VendorID;
+ pci_dev_t dev;
+
+ printf("Scanning PCI devices on bus %d\n", BusNum);
+
+ if (ShortPCIListing) {
+ printf("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
+ printf("_____________________________________________________________\n");
+ }
+
+ for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+ HeaderType = 0;
+ VendorID = 0;
+ for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
+ /*
+ * If this is not a multi-function device, we skip the rest.
+ */
+ if (Function && !(HeaderType & 0x80))
+ break;
+
+ dev = PCI_BDF(BusNum, Device, Function);
+
+ pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
+ if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+ continue;
+
+ if (!Function) pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
+
+ if (ShortPCIListing)
+ {
+ printf("%02x.%02x.%02x ", BusNum, Device, Function);
+ pci_header_show_brief(dev);
+ }
+ else
+ {
+ printf("\nFound PCI device %02x.%02x.%02x:\n",
+ BusNum, Device, Function);
+ pci_header_show(dev);
+ }
+ }
+ }
+}
+
+
+/*
+ * Subroutine: pci_header_show_brief
+ *
+ * Description: Reads and prints the header of the
+ * specified PCI device in short form.
+ *
+ * Inputs: dev Bus+Device+Function number
+ *
+ * Return: None
+ *
+ */
+void pci_header_show_brief(pci_dev_t dev)
+{
+ u16 vendor, device;
+ u8 class, subclass;
+
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+ pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
+ pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
+
+ printf("0x%.4x 0x%.4x %-23s 0x%.2x\n",
+ vendor, device,
+ pci_class_str(class), subclass);
+}
+
+/*
+ * Subroutine: PCI_Header_Show
+ *
+ * Description: Reads the header of the specified PCI device.
+ *
+ * Inputs: BusDevFunc Bus+Device+Function number
+ *
+ * Return: None
+ *
+ */
+void pci_header_show(pci_dev_t dev)
+{
+ u8 _byte, header_type;
+ u16 _word;
+ u32 _dword;
+
+#define PRINT(msg, type, reg) \
+ pci_read_config_##type(dev, reg, &_##type); \
+ printf(msg, _##type)
+
+#define PRINT2(msg, type, reg, func) \
+ pci_read_config_##type(dev, reg, &_##type); \
+ printf(msg, _##type, func(_##type))
+
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ PRINT (" vendor ID = 0x%.4x\n", word, PCI_VENDOR_ID);
+ PRINT (" device ID = 0x%.4x\n", word, PCI_DEVICE_ID);
+ PRINT (" command register = 0x%.4x\n", word, PCI_COMMAND);
+ PRINT (" status register = 0x%.4x\n", word, PCI_STATUS);
+ PRINT (" revision ID = 0x%.2x\n", byte, PCI_REVISION_ID);
+ PRINT2(" class code = 0x%.2x (%s)\n", byte, PCI_CLASS_CODE,
+ pci_class_str);
+ PRINT (" sub class code = 0x%.2x\n", byte, PCI_CLASS_SUB_CODE);
+ PRINT (" programming interface = 0x%.2x\n", byte, PCI_CLASS_PROG);
+ PRINT (" cache line = 0x%.2x\n", byte, PCI_CACHE_LINE_SIZE);
+ PRINT (" latency time = 0x%.2x\n", byte, PCI_LATENCY_TIMER);
+ PRINT (" header type = 0x%.2x\n", byte, PCI_HEADER_TYPE);
+ PRINT (" BIST = 0x%.2x\n", byte, PCI_BIST);
+ PRINT (" base address 0 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_0);
+
+ switch (header_type & 0x03) {
+ case PCI_HEADER_TYPE_NORMAL: /* "normal" PCI device */
+ PRINT (" base address 1 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
+ PRINT (" base address 2 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_2);
+ PRINT (" base address 3 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_3);
+ PRINT (" base address 4 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_4);
+ PRINT (" base address 5 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_5);
+ PRINT (" cardBus CIS pointer = 0x%.8x\n", dword, PCI_CARDBUS_CIS);
+ PRINT (" sub system vendor ID = 0x%.4x\n", word, PCI_SUBSYSTEM_VENDOR_ID);
+ PRINT (" sub system ID = 0x%.4x\n", word, PCI_SUBSYSTEM_ID);
+ PRINT (" expansion ROM base address = 0x%.8x\n", dword, PCI_ROM_ADDRESS);
+ PRINT (" interrupt line = 0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+ PRINT (" interrupt pin = 0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+ PRINT (" min Grant = 0x%.2x\n", byte, PCI_MIN_GNT);
+ PRINT (" max Latency = 0x%.2x\n", byte, PCI_MAX_LAT);
+ break;
+
+ case PCI_HEADER_TYPE_BRIDGE: /* PCI-to-PCI bridge */
+
+ PRINT (" base address 1 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
+ PRINT (" primary bus number = 0x%.2x\n", byte, PCI_PRIMARY_BUS);
+ PRINT (" secondary bus number = 0x%.2x\n", byte, PCI_SECONDARY_BUS);
+ PRINT (" subordinate bus number = 0x%.2x\n", byte, PCI_SUBORDINATE_BUS);
+ PRINT (" secondary latency timer = 0x%.2x\n", byte, PCI_SEC_LATENCY_TIMER);
+ PRINT (" IO base = 0x%.2x\n", byte, PCI_IO_BASE);
+ PRINT (" IO limit = 0x%.2x\n", byte, PCI_IO_LIMIT);
+ PRINT (" secondary status = 0x%.4x\n", word, PCI_SEC_STATUS);
+ PRINT (" memory base = 0x%.4x\n", word, PCI_MEMORY_BASE);
+ PRINT (" memory limit = 0x%.4x\n", word, PCI_MEMORY_LIMIT);
+ PRINT (" prefetch memory base = 0x%.4x\n", word, PCI_PREF_MEMORY_BASE);
+ PRINT (" prefetch memory limit = 0x%.4x\n", word, PCI_PREF_MEMORY_LIMIT);
+ PRINT (" prefetch memory base upper = 0x%.8x\n", dword, PCI_PREF_BASE_UPPER32);
+ PRINT (" prefetch memory limit upper = 0x%.8x\n", dword, PCI_PREF_LIMIT_UPPER32);
+ PRINT (" IO base upper 16 bits = 0x%.4x\n", word, PCI_IO_BASE_UPPER16);
+ PRINT (" IO limit upper 16 bits = 0x%.4x\n", word, PCI_IO_LIMIT_UPPER16);
+ PRINT (" expansion ROM base address = 0x%.8x\n", dword, PCI_ROM_ADDRESS1);
+ PRINT (" interrupt line = 0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+ PRINT (" interrupt pin = 0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+ PRINT (" bridge control = 0x%.4x\n", word, PCI_BRIDGE_CONTROL);
+ break;
+
+ case PCI_HEADER_TYPE_CARDBUS: /* PCI-to-CardBus bridge */
+
+ PRINT (" capabilities = 0x%.2x\n", byte, PCI_CB_CAPABILITY_LIST);
+ PRINT (" secondary status = 0x%.4x\n", word, PCI_CB_SEC_STATUS);
+ PRINT (" primary bus number = 0x%.2x\n", byte, PCI_CB_PRIMARY_BUS);
+ PRINT (" CardBus number = 0x%.2x\n", byte, PCI_CB_CARD_BUS);
+ PRINT (" subordinate bus number = 0x%.2x\n", byte, PCI_CB_SUBORDINATE_BUS);
+ PRINT (" CardBus latency timer = 0x%.2x\n", byte, PCI_CB_LATENCY_TIMER);
+ PRINT (" CardBus memory base 0 = 0x%.8x\n", dword, PCI_CB_MEMORY_BASE_0);
+ PRINT (" CardBus memory limit 0 = 0x%.8x\n", dword, PCI_CB_MEMORY_LIMIT_0);
+ PRINT (" CardBus memory base 1 = 0x%.8x\n", dword, PCI_CB_MEMORY_BASE_1);
+ PRINT (" CardBus memory limit 1 = 0x%.8x\n", dword, PCI_CB_MEMORY_LIMIT_1);
+ PRINT (" CardBus IO base 0 = 0x%.4x\n", word, PCI_CB_IO_BASE_0);
+ PRINT (" CardBus IO base high 0 = 0x%.4x\n", word, PCI_CB_IO_BASE_0_HI);
+ PRINT (" CardBus IO limit 0 = 0x%.4x\n", word, PCI_CB_IO_LIMIT_0);
+ PRINT (" CardBus IO limit high 0 = 0x%.4x\n", word, PCI_CB_IO_LIMIT_0_HI);
+ PRINT (" CardBus IO base 1 = 0x%.4x\n", word, PCI_CB_IO_BASE_1);
+ PRINT (" CardBus IO base high 1 = 0x%.4x\n", word, PCI_CB_IO_BASE_1_HI);
+ PRINT (" CardBus IO limit 1 = 0x%.4x\n", word, PCI_CB_IO_LIMIT_1);
+ PRINT (" CardBus IO limit high 1 = 0x%.4x\n", word, PCI_CB_IO_LIMIT_1_HI);
+ PRINT (" interrupt line = 0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+ PRINT (" interrupt pin = 0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+ PRINT (" bridge control = 0x%.4x\n", word, PCI_CB_BRIDGE_CONTROL);
+ PRINT (" subvendor ID = 0x%.4x\n", word, PCI_CB_SUBSYSTEM_VENDOR_ID);
+ PRINT (" subdevice ID = 0x%.4x\n", word, PCI_CB_SUBSYSTEM_ID);
+ PRINT (" PC Card 16bit base address = 0x%.8x\n", dword, PCI_CB_LEGACY_MODE_BASE);
+ break;
+
+ default:
+ printf("unknown header\n");
+ break;
+ }
+
+#undef PRINT
+#undef PRINT2
+}
+
+/* Convert the "bus.device.function" identifier into a number.
+ */
+static pci_dev_t get_pci_dev(char* name)
+{
+ char cnum[12];
+ int len, i, iold, n;
+ int bdfs[3] = {0,0,0};
+
+ len = strlen(name);
+ if (len > 8)
+ return -1;
+ for (i = 0, iold = 0, n = 0; i < len; i++) {
+ if (name[i] == '.') {
+ memcpy(cnum, &name[iold], i - iold);
+ cnum[i - iold] = '\0';
+ bdfs[n++] = simple_strtoul(cnum, NULL, 16);
+ iold = i + 1;
+ }
+ }
+ strcpy(cnum, &name[iold]);
+ if (n == 0)
+ n = 1;
+ bdfs[n] = simple_strtoul(cnum, NULL, 16);
+ return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
+}
+
+static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
+{
+#define DISP_LINE_LEN 16
+ ulong i, nbytes, linebytes;
+ int rc = 0;
+
+ if (length == 0)
+ length = 0x40 / size; /* Standard PCI configuration space */
+
+ /* Print the lines.
+ * once, and all accesses are with the specified bus width.
+ */
+ nbytes = length * size;
+ do {
+ uint val4;
+ ushort val2;
+ u_char val1;
+
+ printf("%08lx:", addr);
+ linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+ for (i=0; i<linebytes; i+= size) {
+ if (size == 4) {
+ pci_read_config_dword(bdf, addr, &val4);
+ printf(" %08x", val4);
+ } else if (size == 2) {
+ pci_read_config_word(bdf, addr, &val2);
+ printf(" %04x", val2);
+ } else {
+ pci_read_config_byte(bdf, addr, &val1);
+ printf(" %02x", val1);
+ }
+ addr += size;
+ }
+ printf("\n");
+ nbytes -= linebytes;
+ if (ctrlc()) {
+ rc = 1;
+ break;
+ }
+ } while (nbytes > 0);
+
+ return (rc);
+}
+
+static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
+{
+ if (size == 4) {
+ pci_write_config_dword(bdf, addr, value);
+ }
+ else if (size == 2) {
+ ushort val = value & 0xffff;
+ pci_write_config_word(bdf, addr, val);
+ }
+ else {
+ u_char val = value & 0xff;
+ pci_write_config_byte(bdf, addr, val);
+ }
+ return 0;
+}
+
+static int
+pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
+{
+ ulong i;
+ int nbytes;
+ extern char console_buffer[];
+ uint val4;
+ ushort val2;
+ u_char val1;
+
+ /* Print the address, followed by value. Then accept input for
+ * the next value. A non-converted value exits.
+ */
+ do {
+ printf("%08lx:", addr);
+ if (size == 4) {
+ pci_read_config_dword(bdf, addr, &val4);
+ printf(" %08x", val4);
+ }
+ else if (size == 2) {
+ pci_read_config_word(bdf, addr, &val2);
+ printf(" %04x", val2);
+ }
+ else {
+ pci_read_config_byte(bdf, addr, &val1);
+ printf(" %02x", val1);
+ }
+
+ nbytes = readline (" ? ");
+ if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+ /* <CR> pressed as only input, don't modify current
+ * location and move to next. "-" pressed will go back.
+ */
+ if (incrflag)
+ addr += nbytes ? -size : size;
+ nbytes = 1;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ reset_cmd_timeout(); /* good enough to not time out */
+#endif
+ }
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (nbytes == -2) {
+ break; /* timed out, exit the command */
+ }
+#endif
+ else {
+ char *endp;
+ i = simple_strtoul(console_buffer, &endp, 16);
+ nbytes = endp - console_buffer;
+ if (nbytes) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ /* good enough to not time out
+ */
+ reset_cmd_timeout();
+#endif
+ pci_cfg_write (bdf, addr, size, i);
+ if (incrflag)
+ addr += size;
+ }
+ }
+ } while (nbytes);
+
+ return 0;
+}
+
+/* PCI Configuration Space access commands
+ *
+ * Syntax:
+ * pci display[.b, .w, .l] bus.device.function} [addr] [len]
+ * pci next[.b, .w, .l] bus.device.function [addr]
+ * pci modify[.b, .w, .l] bus.device.function [addr]
+ * pci write[.b, .w, .l] bus.device.function addr value
+ */
+int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr = 0, value = 0, size = 0;
+ pci_dev_t bdf = 0;
+ char cmd = 's';
+
+ if (argc > 1)
+ cmd = argv[1][0];
+
+ switch (cmd) {
+ case 'd': /* display */
+ case 'n': /* next */
+ case 'm': /* modify */
+ case 'w': /* write */
+ /* Check for a size specification. */
+ size = cmd_get_data_size(argv[1], 4);
+ if (argc > 3)
+ addr = simple_strtoul(argv[3], NULL, 16);
+ if (argc > 4)
+ value = simple_strtoul(argv[4], NULL, 16);
+ case 'h': /* header */
+ if (argc < 3)
+ goto usage;
+ if ((bdf = get_pci_dev(argv[2])) == -1)
+ return 1;
+ break;
+#ifdef CONFIG_CMD_PCI_ENUM
+ case 'e':
+ break;
+#endif
+ default: /* scan bus */
+ value = 1; /* short listing */
+ bdf = 0; /* bus number */
+ if (argc > 1) {
+ if (argv[argc-1][0] == 'l') {
+ value = 0;
+ argc--;
+ }
+ if (argc > 1)
+ bdf = simple_strtoul(argv[1], NULL, 16);
+ }
+ pciinfo(bdf, value);
+ return 0;
+ }
+
+ switch (argv[1][0]) {
+ case 'h': /* header */
+ pci_header_show(bdf);
+ return 0;
+ case 'd': /* display */
+ return pci_cfg_display(bdf, addr, size, value);
+#ifdef CONFIG_CMD_PCI_ENUM
+ case 'e':
+ pci_init();
+ return 0;
+#endif
+ case 'n': /* next */
+ if (argc < 4)
+ goto usage;
+ return pci_cfg_modify(bdf, addr, size, value, 0);
+ case 'm': /* modify */
+ if (argc < 4)
+ goto usage;
+ return pci_cfg_modify(bdf, addr, size, value, 1);
+ case 'w': /* write */
+ if (argc < 5)
+ goto usage;
+ return pci_cfg_write(bdf, addr, size, value);
+ }
+
+ return 1;
+ usage:
+ return cmd_usage(cmdtp);
+}
+
+/***************************************************/
+
+
+U_BOOT_CMD(
+ pci, 5, 1, do_pci,
+ "list and access PCI Configuration Space",
+ "[bus] [long]\n"
+ " - short or long list of PCI devices on bus 'bus'\n"
+#ifdef CONFIG_CMD_PCI_ENUM
+ "pci enum\n"
+ " - re-enumerate PCI buses\n"
+#endif
+ "pci header b.d.f\n"
+ " - show header of PCI device 'bus.device.function'\n"
+ "pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
+ " - display PCI configuration space (CFG)\n"
+ "pci next[.b, .w, .l] b.d.f address\n"
+ " - modify, read and keep CFG address\n"
+ "pci modify[.b, .w, .l] b.d.f address\n"
+ " - modify, auto increment CFG address\n"
+ "pci write[.b, .w, .l] b.d.f address value\n"
+ " - write to CFG address"
+);
diff --git a/u-boot/common/cmd_pcmcia.c b/u-boot/common/cmd_pcmcia.c
new file mode 100644
index 0000000..70e5210
--- /dev/null
+++ b/u-boot/common/cmd_pcmcia.c
@@ -0,0 +1,365 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ *
+ ********************************************************************
+ *
+ * Lots of code copied from:
+ *
+ * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
+ * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
+ *
+ * "The ExCA standard specifies that socket controllers should provide
+ * two IO and five memory windows per socket, which can be independently
+ * configured and positioned in the host address space and mapped to
+ * arbitrary segments of card address space. " - David A Hinds. 1999
+ *
+ * This controller does _not_ meet the ExCA standard.
+ *
+ * m8xx pcmcia controller brief info:
+ * + 8 windows (attrib, mem, i/o)
+ * + up to two slots (SLOT_A and SLOT_B)
+ * + inputpins, outputpins, event and mask registers.
+ * - no offset register. sigh.
+ *
+ * Because of the lacking offset register we must map the whole card.
+ * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
+ * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
+ * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
+ * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
+ * They are maximum 64KByte each...
+ */
+
+/* #define DEBUG 1 */
+
+/*
+ * PCMCIA support
+ */
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <pcmcia.h>
+#include <asm/io.h>
+
+/* -------------------------------------------------------------------- */
+
+#if defined(CONFIG_CMD_PCMCIA)
+
+extern int pcmcia_on (void);
+extern int pcmcia_off (void);
+
+int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int rcode = 0;
+
+ if (argc != 2) {
+ printf ("Usage: pinit {on | off}\n");
+ return 1;
+ }
+ if (strcmp(argv[1],"on") == 0) {
+ rcode = pcmcia_on ();
+ } else if (strcmp(argv[1],"off") == 0) {
+ rcode = pcmcia_off ();
+ } else {
+ printf ("Usage: pinit {on | off}\n");
+ return 1;
+ }
+
+ return rcode;
+}
+
+U_BOOT_CMD(
+ pinit, 2, 0, do_pinit,
+ "PCMCIA sub-system",
+ "on - power on PCMCIA socket\n"
+ "pinit off - power off PCMCIA socket"
+);
+
+#endif
+
+/* -------------------------------------------------------------------- */
+
+#undef CHECK_IDE_DEVICE
+
+#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define CHECK_IDE_DEVICE
+#endif
+
+#if defined(CONFIG_PXA_PCMCIA)
+#define CHECK_IDE_DEVICE
+#endif
+
+#ifdef CHECK_IDE_DEVICE
+
+int ide_devices_found;
+static uchar *known_cards[] = {
+ (uchar *)"ARGOSY PnPIDE D5",
+ NULL
+};
+
+#define MAX_TUPEL_SZ 512
+#define MAX_FEATURES 4
+
+#define MAX_IDENT_CHARS 64
+#define MAX_IDENT_FIELDS 4
+
+#define indent "\t "
+
+static void print_funcid (int func)
+{
+ puts (indent);
+ switch (func) {
+ case CISTPL_FUNCID_MULTI:
+ puts (" Multi-Function");
+ break;
+ case CISTPL_FUNCID_MEMORY:
+ puts (" Memory");
+ break;
+ case CISTPL_FUNCID_SERIAL:
+ puts (" Serial Port");
+ break;
+ case CISTPL_FUNCID_PARALLEL:
+ puts (" Parallel Port");
+ break;
+ case CISTPL_FUNCID_FIXED:
+ puts (" Fixed Disk");
+ break;
+ case CISTPL_FUNCID_VIDEO:
+ puts (" Video Adapter");
+ break;
+ case CISTPL_FUNCID_NETWORK:
+ puts (" Network Adapter");
+ break;
+ case CISTPL_FUNCID_AIMS:
+ puts (" AIMS Card");
+ break;
+ case CISTPL_FUNCID_SCSI:
+ puts (" SCSI Adapter");
+ break;
+ default:
+ puts (" Unknown");
+ break;
+ }
+ puts (" Card\n");
+}
+
+static void print_fixed (volatile uchar *p)
+{
+ if (p == NULL)
+ return;
+
+ puts(indent);
+
+ switch (*p) {
+ case CISTPL_FUNCE_IDE_IFACE:
+ { uchar iface = *(p+2);
+
+ puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+ puts (" interface ");
+ break;
+ }
+ case CISTPL_FUNCE_IDE_MASTER:
+ case CISTPL_FUNCE_IDE_SLAVE:
+ { uchar f1 = *(p+2);
+ uchar f2 = *(p+4);
+
+ puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+ if (f1 & CISTPL_IDE_UNIQUE)
+ puts (" [unique]");
+
+ puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+ if (f2 & CISTPL_IDE_HAS_SLEEP)
+ puts (" [sleep]");
+
+ if (f2 & CISTPL_IDE_HAS_STANDBY)
+ puts (" [standby]");
+
+ if (f2 & CISTPL_IDE_HAS_IDLE)
+ puts (" [idle]");
+
+ if (f2 & CISTPL_IDE_LOW_POWER)
+ puts (" [low power]");
+
+ if (f2 & CISTPL_IDE_REG_INHIBIT)
+ puts (" [reg inhibit]");
+
+ if (f2 & CISTPL_IDE_HAS_INDEX)
+ puts (" [index]");
+
+ if (f2 & CISTPL_IDE_IOIS16)
+ puts (" [IOis16]");
+
+ break;
+ }
+ }
+ putc ('\n');
+}
+
+static int identify (volatile uchar *p)
+{
+ uchar id_str[MAX_IDENT_CHARS];
+ uchar data;
+ uchar *t;
+ uchar **card;
+ int i, done;
+
+ if (p == NULL)
+ return (0); /* Don't know */
+
+ t = id_str;
+ done =0;
+
+ for (i=0; i<=4 && !done; ++i, p+=2) {
+ while ((data = *p) != '\0') {
+ if (data == 0xFF) {
+ done = 1;
+ break;
+ }
+ *t++ = data;
+ if (t == &id_str[MAX_IDENT_CHARS-1]) {
+ done = 1;
+ break;
+ }
+ p += 2;
+ }
+ if (!done)
+ *t++ = ' ';
+ }
+ *t = '\0';
+ while (--t > id_str) {
+ if (*t == ' ')
+ *t = '\0';
+ else
+ break;
+ }
+ puts ((char *)id_str);
+ putc ('\n');
+
+ for (card=known_cards; *card; ++card) {
+ debug ("## Compare against \"%s\"\n", *card);
+ if (strcmp((char *)*card, (char *)id_str) == 0) { /* found! */
+ debug ("## CARD FOUND ##\n");
+ return (1);
+ }
+ }
+
+ return (0); /* don't know */
+}
+
+int check_ide_device (int slot)
+{
+ volatile uchar *ident = NULL;
+ volatile uchar *feature_p[MAX_FEATURES];
+ volatile uchar *p, *start, *addr;
+ int n_features = 0;
+ uchar func_id = ~0;
+ uchar code, len;
+ ushort config_base = 0;
+ int found = 0;
+ int i;
+
+ addr = (volatile uchar *)(CONFIG_SYS_PCMCIA_MEM_ADDR +
+ CONFIG_SYS_PCMCIA_MEM_SIZE * (slot * 4));
+ debug ("PCMCIA MEM: %08lX\n", (ulong)addr);
+
+ start = p = (volatile uchar *) addr;
+
+ while ((p - start) < MAX_TUPEL_SZ) {
+
+ code = *p; p += 2;
+
+ if (code == 0xFF) { /* End of chain */
+ break;
+ }
+
+ len = *p; p += 2;
+#if defined(DEBUG) && (DEBUG > 1)
+ { volatile uchar *q = p;
+ printf ("\nTuple code %02x length %d\n\tData:",
+ code, len);
+
+ for (i = 0; i < len; ++i) {
+ printf (" %02x", *q);
+ q+= 2;
+ }
+ }
+#endif /* DEBUG */
+ switch (code) {
+ case CISTPL_VERS_1:
+ ident = p + 4;
+ break;
+ case CISTPL_FUNCID:
+ /* Fix for broken SanDisk which may have 0x80 bit set */
+ func_id = *p & 0x7F;
+ break;
+ case CISTPL_FUNCE:
+ if (n_features < MAX_FEATURES)
+ feature_p[n_features++] = p;
+ break;
+ case CISTPL_CONFIG:
+ config_base = (*(p+6) << 8) + (*(p+4));
+ debug ("\n## Config_base = %04x ###\n", config_base);
+ default:
+ break;
+ }
+ p += 2 * len;
+ }
+
+ found = identify (ident);
+
+ if (func_id != ((uchar)~0)) {
+ print_funcid (func_id);
+
+ if (func_id == CISTPL_FUNCID_FIXED)
+ found = 1;
+ else
+ return (1); /* no disk drive */
+ }
+
+ for (i=0; i<n_features; ++i) {
+ print_fixed (feature_p[i]);
+ }
+
+ if (!found) {
+ printf ("unknown card type\n");
+ return (1);
+ }
+
+ ide_devices_found |= (1 << slot);
+
+#if CONFIG_CPC45
+#else
+ /* set I/O area in config reg -> only valid for ARGOSY D5!!! */
+ *((uchar *)(addr + config_base)) = 1;
+#endif
+#if 0
+ printf("\n## Config_base = %04x ###\n", config_base);
+ printf("Configuration Option Register: %02x @ %x\n", readb(addr + config_base), addr + config_base);
+ printf("Card Configuration and Status Register: %02x\n", readb(addr + config_base + 2));
+ printf("Pin Replacement Register Register: %02x\n", readb(addr + config_base + 4));
+ printf("Socket and Copy Register: %02x\n", readb(addr + config_base + 6));
+#endif
+ return (0);
+}
+
+#endif /* CHECK_IDE_DEVICE */
diff --git a/u-boot/common/cmd_portio.c b/u-boot/common/cmd_portio.c
new file mode 100644
index 0000000..4f2f499
--- /dev/null
+++ b/u-boot/common/cmd_portio.c
@@ -0,0 +1,161 @@
+/*
+ * (C) Copyright 2003
+ * Marc Singer, elf@buici.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Port I/O Functions
+ *
+ * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
+ */
+
+#include <common.h>
+#include <command.h>
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+static uint in_last_addr, in_last_size;
+static uint out_last_addr, out_last_size, out_last_value;
+
+
+int do_portio_out (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ uint addr = out_last_addr;
+ uint size = out_last_size;
+ uint value = out_last_value;
+
+ if (argc != 3)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /*
+ * New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ size = cmd_get_data_size (argv[0], 1);
+ addr = simple_strtoul (argv[1], NULL, 16);
+ value = simple_strtoul (argv[2], NULL, 16);
+ }
+#if defined (CONFIG_X86)
+
+ {
+ unsigned short port = addr;
+
+ switch (size) {
+ default:
+ case 1:
+ {
+ unsigned char ch = value;
+ __asm__ volatile ("out %0, %%dx"::"a" (ch), "d" (port));
+ }
+ break;
+ case 2:
+ {
+ unsigned short w = value;
+ __asm__ volatile ("out %0, %%dx"::"a" (w), "d" (port));
+ }
+ break;
+ case 4:
+ __asm__ volatile ("out %0, %%dx"::"a" (value), "d" (port));
+
+ break;
+ }
+ }
+
+#endif /* CONFIG_X86 */
+
+ out_last_addr = addr;
+ out_last_size = size;
+ out_last_value = value;
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ out, 3, 1, do_portio_out,
+ "write datum to IO port",
+ "[.b, .w, .l] port value\n - output to IO port"
+);
+
+int do_portio_in (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ uint addr = in_last_addr;
+ uint size = in_last_size;
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /*
+ * New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ size = cmd_get_data_size (argv[0], 1);
+ addr = simple_strtoul (argv[1], NULL, 16);
+ }
+#if defined (CONFIG_X86)
+
+ {
+ unsigned short port = addr;
+
+ switch (size) {
+ default:
+ case 1:
+ {
+ unsigned char ch;
+ __asm__ volatile ("in %%dx, %0":"=a" (ch):"d" (port));
+
+ printf (" %02x\n", ch);
+ }
+ break;
+ case 2:
+ {
+ unsigned short w;
+ __asm__ volatile ("in %%dx, %0":"=a" (w):"d" (port));
+
+ printf (" %04x\n", w);
+ }
+ break;
+ case 4:
+ {
+ unsigned long l;
+ __asm__ volatile ("in %%dx, %0":"=a" (l):"d" (port));
+
+ printf (" %08lx\n", l);
+ }
+ break;
+ }
+ }
+#endif /* CONFIG_X86 */
+
+ in_last_addr = addr;
+ in_last_size = size;
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ in, 2, 1, do_portio_in,
+ "read data from an IO port",
+ "[.b, .w, .l] port\n"
+ " - read datum from IO port"
+);
diff --git a/u-boot/common/cmd_reginfo.c b/u-boot/common/cmd_reginfo.c
new file mode 100644
index 0000000..908876c
--- /dev/null
+++ b/u-boot/common/cmd_reginfo.c
@@ -0,0 +1,243 @@
+/*
+ * (C) Copyright 2000
+ * Subodh Nijsure, SkyStream Networks, snijsure@skystream.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#if defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#elif defined (CONFIG_4xx)
+extern void ppc4xx_reginfo(void);
+#elif defined (CONFIG_5xx)
+#include <mpc5xx.h>
+#elif defined (CONFIG_MPC5200)
+#include <mpc5xxx.h>
+#elif defined (CONFIG_MPC86xx)
+extern void mpc86xx_reginfo(void);
+#elif defined(CONFIG_MPC85xx)
+extern void mpc85xx_reginfo(void);
+#endif
+
+int do_reginfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#if defined(CONFIG_8xx)
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ volatile sysconf8xx_t *sysconf = &immap->im_siu_conf;
+ volatile sit8xx_t *timers = &immap->im_sit;
+
+ /* Hopefully more PowerPC knowledgable people will add code to display
+ * other useful registers
+ */
+
+ printf ("\nSystem Configuration registers\n"
+
+ "\tIMMR\t0x%08X\n", get_immr(0));
+
+ printf("\tSIUMCR\t0x%08X", sysconf->sc_siumcr);
+ printf("\tSYPCR\t0x%08X\n",sysconf->sc_sypcr);
+
+ printf("\tSWT\t0x%08X", sysconf->sc_swt);
+ printf("\tSWSR\t0x%04X\n", sysconf->sc_swsr);
+
+ printf("\tSIPEND\t0x%08X\tSIMASK\t0x%08X\n",
+ sysconf->sc_sipend, sysconf->sc_simask);
+ printf("\tSIEL\t0x%08X\tSIVEC\t0x%08X\n",
+ sysconf->sc_siel, sysconf->sc_sivec);
+ printf("\tTESR\t0x%08X\tSDCR\t0x%08X\n",
+ sysconf->sc_tesr, sysconf->sc_sdcr);
+
+ printf ("Memory Controller Registers\n"
+
+ "\tBR0\t0x%08X\tOR0\t0x%08X \n", memctl->memc_br0, memctl->memc_or0);
+ printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", memctl->memc_br1, memctl->memc_or1);
+ printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", memctl->memc_br2, memctl->memc_or2);
+ printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", memctl->memc_br3, memctl->memc_or3);
+ printf("\tBR4\t0x%08X\tOR4\t0x%08X \n", memctl->memc_br4, memctl->memc_or4);
+ printf("\tBR5\t0x%08X\tOR5\t0x%08X \n", memctl->memc_br5, memctl->memc_or5);
+ printf("\tBR6\t0x%08X\tOR6\t0x%08X \n", memctl->memc_br6, memctl->memc_or6);
+ printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", memctl->memc_br7, memctl->memc_or7);
+ printf ("\n"
+ "\tmamr\t0x%08X\tmbmr\t0x%08X \n",
+ memctl->memc_mamr, memctl->memc_mbmr );
+ printf("\tmstat\t0x%08X\tmptpr\t0x%08X \n",
+ memctl->memc_mstat, memctl->memc_mptpr );
+ printf("\tmdr\t0x%08X \n", memctl->memc_mdr);
+
+ printf ("\nSystem Integration Timers\n"
+ "\tTBSCR\t0x%08X\tRTCSC\t0x%08X \n",
+ timers->sit_tbscr, timers->sit_rtcsc);
+ printf("\tPISCR\t0x%08X \n", timers->sit_piscr);
+
+ /*
+ * May be some CPM info here?
+ */
+
+#elif defined (CONFIG_4xx)
+ ppc4xx_reginfo();
+#elif defined(CONFIG_5xx)
+
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile memctl5xx_t *memctl = &immap->im_memctl;
+ volatile sysconf5xx_t *sysconf = &immap->im_siu_conf;
+ volatile sit5xx_t *timers = &immap->im_sit;
+ volatile car5xx_t *car = &immap->im_clkrst;
+ volatile uimb5xx_t *uimb = &immap->im_uimb;
+
+ puts ("\nSystem Configuration registers\n");
+ printf("\tIMMR\t0x%08X\tSIUMCR\t0x%08X \n", get_immr(0), sysconf->sc_siumcr);
+ printf("\tSYPCR\t0x%08X\tSWSR\t0x%04X \n" ,sysconf->sc_sypcr, sysconf->sc_swsr);
+ printf("\tSIPEND\t0x%08X\tSIMASK\t0x%08X \n", sysconf->sc_sipend, sysconf->sc_simask);
+ printf("\tSIEL\t0x%08X\tSIVEC\t0x%08X \n", sysconf->sc_siel, sysconf->sc_sivec);
+ printf("\tTESR\t0x%08X\n", sysconf->sc_tesr);
+
+ puts ("\nMemory Controller Registers\n");
+ printf("\tBR0\t0x%08X\tOR0\t0x%08X \n", memctl->memc_br0, memctl->memc_or0);
+ printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", memctl->memc_br1, memctl->memc_or1);
+ printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", memctl->memc_br2, memctl->memc_or2);
+ printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", memctl->memc_br3, memctl->memc_or3);
+ printf("\tDMBR\t0x%08X\tDMOR\t0x%08X \n", memctl->memc_dmbr, memctl->memc_dmor );
+ printf("\tMSTAT\t0x%08X\n", memctl->memc_mstat);
+
+ puts ("\nSystem Integration Timers\n");
+ printf("\tTBSCR\t0x%08X\tRTCSC\t0x%08X \n", timers->sit_tbscr, timers->sit_rtcsc);
+ printf("\tPISCR\t0x%08X \n", timers->sit_piscr);
+
+ puts ("\nClocks and Reset\n");
+ printf("\tSCCR\t0x%08X\tPLPRCR\t0x%08X \n", car->car_sccr, car->car_plprcr);
+
+ puts ("\nU-Bus to IMB3 Bus Interface\n");
+ printf("\tUMCR\t0x%08X\tUIPEND\t0x%08X \n", uimb->uimb_umcr, uimb->uimb_uipend);
+ puts ("\n\n");
+
+#elif defined(CONFIG_MPC5200)
+ puts ("\nMPC5200 registers\n");
+ printf ("MBAR=%08x\n", CONFIG_SYS_MBAR);
+ puts ("Memory map registers\n");
+ printf ("\tCS0: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS0_START,
+ *(volatile ulong*)MPC5XXX_CS0_STOP,
+ *(volatile ulong*)MPC5XXX_CS0_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00010000) ? 1 : 0);
+ printf ("\tCS1: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS1_START,
+ *(volatile ulong*)MPC5XXX_CS1_STOP,
+ *(volatile ulong*)MPC5XXX_CS1_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00020000) ? 1 : 0);
+ printf ("\tCS2: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS2_START,
+ *(volatile ulong*)MPC5XXX_CS2_STOP,
+ *(volatile ulong*)MPC5XXX_CS2_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00040000) ? 1 : 0);
+ printf ("\tCS3: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS3_START,
+ *(volatile ulong*)MPC5XXX_CS3_STOP,
+ *(volatile ulong*)MPC5XXX_CS3_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00080000) ? 1 : 0);
+ printf ("\tCS4: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS4_START,
+ *(volatile ulong*)MPC5XXX_CS4_STOP,
+ *(volatile ulong*)MPC5XXX_CS4_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00100000) ? 1 : 0);
+ printf ("\tCS5: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS5_START,
+ *(volatile ulong*)MPC5XXX_CS5_STOP,
+ *(volatile ulong*)MPC5XXX_CS5_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x00200000) ? 1 : 0);
+ printf ("\tCS6: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS6_START,
+ *(volatile ulong*)MPC5XXX_CS6_STOP,
+ *(volatile ulong*)MPC5XXX_CS6_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x04000000) ? 1 : 0);
+ printf ("\tCS7: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_CS7_START,
+ *(volatile ulong*)MPC5XXX_CS7_STOP,
+ *(volatile ulong*)MPC5XXX_CS7_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x08000000) ? 1 : 0);
+ printf ("\tBOOTCS: start %08lX\tstop %08lX\tconfig %08lX\ten %d\n",
+ *(volatile ulong*)MPC5XXX_BOOTCS_START,
+ *(volatile ulong*)MPC5XXX_BOOTCS_STOP,
+ *(volatile ulong*)MPC5XXX_BOOTCS_CFG,
+ (*(volatile ulong*)MPC5XXX_ADDECR & 0x02000000) ? 1 : 0);
+ printf ("\tSDRAMCS0: %08lX\n",
+ *(volatile ulong*)MPC5XXX_SDRAM_CS0CFG);
+ printf ("\tSDRAMCS1: %08lX\n",
+ *(volatile ulong*)MPC5XXX_SDRAM_CS1CFG);
+#elif defined(CONFIG_MPC86xx)
+ mpc86xx_reginfo();
+
+#elif defined(CONFIG_MPC85xx)
+ mpc85xx_reginfo();
+
+#elif defined(CONFIG_BLACKFIN)
+ puts("\nSystem Configuration registers\n");
+
+ puts("\nPLL Registers\n");
+ printf("\tPLL_DIV: 0x%04x PLL_CTL: 0x%04x\n",
+ bfin_read_PLL_DIV(), bfin_read_PLL_CTL());
+ printf("\tPLL_STAT: 0x%04x PLL_LOCKCNT: 0x%04x\n",
+ bfin_read_PLL_STAT(), bfin_read_PLL_LOCKCNT());
+ printf("\tVR_CTL: 0x%04x\n", bfin_read_VR_CTL());
+
+ puts("\nEBIU AMC Registers\n");
+ printf("\tEBIU_AMGCTL: 0x%04x\n", bfin_read_EBIU_AMGCTL());
+ printf("\tEBIU_AMBCTL0: 0x%08x EBIU_AMBCTL1: 0x%08x\n",
+ bfin_read_EBIU_AMBCTL0(), bfin_read_EBIU_AMBCTL1());
+# ifdef EBIU_MODE
+ printf("\tEBIU_MBSCTL: 0x%08x EBIU_ARBSTAT: 0x%08x\n",
+ bfin_read_EBIU_MBSCTL(), bfin_read_EBIU_ARBSTAT());
+ printf("\tEBIU_MODE: 0x%08x EBIU_FCTL: 0x%08x\n",
+ bfin_read_EBIU_MODE(), bfin_read_EBIU_FCTL());
+# endif
+
+# ifdef EBIU_RSTCTL
+ puts("\nEBIU DDR Registers\n");
+ printf("\tEBIU_DDRCTL0: 0x%08x EBIU_DDRCTL1: 0x%08x\n",
+ bfin_read_EBIU_DDRCTL0(), bfin_read_EBIU_DDRCTL1());
+ printf("\tEBIU_DDRCTL2: 0x%08x EBIU_DDRCTL3: 0x%08x\n",
+ bfin_read_EBIU_DDRCTL2(), bfin_read_EBIU_DDRCTL3());
+ printf("\tEBIU_DDRQUE: 0x%08x EBIU_RSTCTL 0x%04x\n",
+ bfin_read_EBIU_DDRQUE(), bfin_read_EBIU_RSTCTL());
+ printf("\tEBIU_ERRADD: 0x%08x EBIU_ERRMST: 0x%04x\n",
+ bfin_read_EBIU_ERRADD(), bfin_read_EBIU_ERRMST());
+# else
+ puts("\nEBIU SDC Registers\n");
+ printf("\tEBIU_SDRRC: 0x%04x EBIU_SDBCTL: 0x%04x\n",
+ bfin_read_EBIU_SDRRC(), bfin_read_EBIU_SDBCTL());
+ printf("\tEBIU_SDSTAT: 0x%04x EBIU_SDGCTL: 0x%08x\n",
+ bfin_read_EBIU_SDSTAT(), bfin_read_EBIU_SDGCTL());
+# endif
+
+#endif /* CONFIG_BLACKFIN */
+
+ return 0;
+}
+
+ /**************************************************/
+
+#if defined(CONFIG_CMD_REGINFO)
+U_BOOT_CMD(
+ reginfo, 2, 1, do_reginfo,
+ "print register information",
+ ""
+);
+#endif
diff --git a/u-boot/common/cmd_reiser.c b/u-boot/common/cmd_reiser.c
new file mode 100644
index 0000000..ced1d40
--- /dev/null
+++ b/u-boot/common/cmd_reiser.c
@@ -0,0 +1,237 @@
+/*
+ * (C) Copyright 2003 - 2004
+ * Sysgo Real-Time Solutions, AG <www.elinos.com>
+ * Pavel Bartusek <pba@sysgo.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Reiserfs support
+ */
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <image.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <reiserfs.h>
+#include <part.h>
+
+#ifndef CONFIG_DOS_PARTITION
+#error DOS partition support must be selected
+#endif
+
+/* #define REISER_DEBUG */
+
+#ifdef REISER_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+int do_reiserls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int dev=0;
+ int part=1;
+ char *ep;
+ block_dev_desc_t *dev_desc=NULL;
+ int part_length;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ dev = (int)simple_strtoul (argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+
+ if (dev_desc == NULL) {
+ printf ("\n** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+
+ if (argc == 4) {
+ filename = argv[3];
+ }
+
+ PRINTF("Using device %s %d:%d, directory: %s\n", argv[1], dev, part, filename);
+
+ if ((part_length = reiserfs_set_blk_dev(dev_desc, part)) == 0) {
+ printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part);
+ return 1;
+ }
+
+ if (!reiserfs_mount(part_length)) {
+ printf ("** Bad Reiserfs partition or disk - %s %d:%d **\n", argv[1], dev, part);
+ return 1;
+ }
+
+ if (reiserfs_ls (filename)) {
+ printf ("** Error reiserfs_ls() **\n");
+ return 1;
+ };
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ reiserls, 4, 1, do_reiserls,
+ "list files in a directory (default /)",
+ "<interface> <dev[:part]> [directory]\n"
+ " - list files from 'dev' on 'interface' in a 'directory'"
+);
+
+/******************************************************************************
+ * Reiserfs boot command intepreter. Derived from diskboot
+ */
+int do_reiserload (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = NULL;
+ char *ep;
+ int dev, part = 0;
+ ulong addr = 0, part_length, filelen;
+ disk_partition_t info;
+ block_dev_desc_t *dev_desc = NULL;
+ char buf [12];
+ unsigned long count;
+ char *addr_str;
+
+ switch (argc) {
+ case 3:
+ addr_str = getenv("loadaddr");
+ if (addr_str != NULL) {
+ addr = simple_strtoul (addr_str, NULL, 16);
+ } else {
+ addr = CONFIG_SYS_LOAD_ADDR;
+ }
+ filename = getenv ("bootfile");
+ count = 0;
+ break;
+ case 4:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = getenv ("bootfile");
+ count = 0;
+ break;
+ case 5:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = argv[4];
+ count = 0;
+ break;
+ case 6:
+ addr = simple_strtoul (argv[3], NULL, 16);
+ filename = argv[4];
+ count = simple_strtoul (argv[5], NULL, 16);
+ break;
+
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (!filename) {
+ puts ("\n** No boot file defined **\n");
+ return 1;
+ }
+
+ dev = (int)simple_strtoul (argv[2], &ep, 16);
+ dev_desc = get_dev(argv[1],dev);
+ if (dev_desc==NULL) {
+ printf ("\n** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = (int)simple_strtoul(++ep, NULL, 16);
+ }
+
+ PRINTF("Using device %s%d, partition %d\n", argv[1], dev, part);
+
+ if (part != 0) {
+ if (get_partition_info (dev_desc, part, &info)) {
+ printf ("** Bad partition %d **\n", part);
+ return 1;
+ }
+
+ if (strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
+ printf ("\n** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ return 1;
+ }
+ PRINTF ("\nLoading from block device %s device %d, partition %d: "
+ "Name: %.32s Type: %.32s File:%s\n",
+ argv[1], dev, part, info.name, info.type, filename);
+ } else {
+ PRINTF ("\nLoading from block device %s device %d, File:%s\n",
+ argv[1], dev, filename);
+ }
+
+
+ if ((part_length = reiserfs_set_blk_dev(dev_desc, part)) == 0) {
+ printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part);
+ return 1;
+ }
+
+ if (!reiserfs_mount(part_length)) {
+ printf ("** Bad Reiserfs partition or disk - %s %d:%d **\n", argv[1], dev, part);
+ return 1;
+ }
+
+ filelen = reiserfs_open(filename);
+ if (filelen < 0) {
+ printf("** File not found %s\n", filename);
+ return 1;
+ }
+ if ((count < filelen) && (count != 0)) {
+ filelen = count;
+ }
+
+ if (reiserfs_read((char *)addr, filelen) != filelen) {
+ printf("\n** Unable to read \"%s\" from %s %d:%d **\n", filename, argv[1], dev, part);
+ return 1;
+ }
+
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ printf ("\n%ld bytes read\n", filelen);
+ sprintf(buf, "%lX", filelen);
+ setenv("filesize", buf);
+
+ return filelen;
+}
+
+U_BOOT_CMD(
+ reiserload, 6, 0, do_reiserload,
+ "load binary file from a Reiser filesystem",
+ "<interface> <dev[:part]> [addr] [filename] [bytes]\n"
+ " - load binary file 'filename' from 'dev' on 'interface'\n"
+ " to address 'addr' from dos filesystem"
+);
diff --git a/u-boot/common/cmd_sata.c b/u-boot/common/cmd_sata.c
new file mode 100644
index 0000000..7efa859
--- /dev/null
+++ b/u-boot/common/cmd_sata.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2000-2005, DENX Software Engineering
+ * Wolfgang Denk <wd@denx.de>
+ * Copyright (C) Procsys. All rights reserved.
+ * Mushtaq Khan <mushtaq_k@procsys.com>
+ * <mushtaqk_921@yahoo.co.in>
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * 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 <part.h>
+#include <sata.h>
+
+int sata_curr_device = -1;
+block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+int __sata_initialize(void)
+{
+ int rc;
+ int i;
+
+ for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
+ memset(&sata_dev_desc[i], 0, sizeof(struct block_dev_desc));
+ sata_dev_desc[i].if_type = IF_TYPE_SATA;
+ sata_dev_desc[i].dev = i;
+ sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+ sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
+ sata_dev_desc[i].lba = 0;
+ sata_dev_desc[i].blksz = 512;
+ sata_dev_desc[i].block_read = sata_read;
+ sata_dev_desc[i].block_write = sata_write;
+
+ rc = init_sata(i);
+ rc = scan_sata(i);
+ if ((sata_dev_desc[i].lba > 0) && (sata_dev_desc[i].blksz > 0))
+ init_part(&sata_dev_desc[i]);
+ }
+ sata_curr_device = 0;
+ return rc;
+}
+int sata_initialize(void) __attribute__((weak,alias("__sata_initialize")));
+
+block_dev_desc_t *sata_get_dev(int dev)
+{
+ return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
+}
+
+int do_sata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int rc = 0;
+
+ if (argc == 2 && strcmp(argv[1], "init") == 0)
+ return sata_initialize();
+
+ /* If the user has not yet run `sata init`, do it now */
+ if (sata_curr_device == -1)
+ if (sata_initialize())
+ return 1;
+
+ switch (argc) {
+ case 0:
+ case 1:
+ return cmd_usage(cmdtp);
+ case 2:
+ if (strncmp(argv[1],"inf", 3) == 0) {
+ int i;
+ putc('\n');
+ for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; ++i) {
+ if (sata_dev_desc[i].type == DEV_TYPE_UNKNOWN)
+ continue;
+ printf ("SATA device %d: ", i);
+ dev_print(&sata_dev_desc[i]);
+ }
+ return 0;
+ } else if (strncmp(argv[1],"dev", 3) == 0) {
+ if ((sata_curr_device < 0) || (sata_curr_device >= CONFIG_SYS_SATA_MAX_DEVICE)) {
+ puts("\nno SATA devices available\n");
+ return 1;
+ }
+ printf("\nSATA device %d: ", sata_curr_device);
+ dev_print(&sata_dev_desc[sata_curr_device]);
+ return 0;
+ } else if (strncmp(argv[1],"part",4) == 0) {
+ int dev, ok;
+
+ for (ok = 0, dev = 0; dev < CONFIG_SYS_SATA_MAX_DEVICE; ++dev) {
+ if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
+ ++ok;
+ if (dev)
+ putc ('\n');
+ print_part(&sata_dev_desc[dev]);
+ }
+ }
+ if (!ok) {
+ puts("\nno SATA devices available\n");
+ rc ++;
+ }
+ return rc;
+ }
+ return cmd_usage(cmdtp);
+ case 3:
+ if (strncmp(argv[1], "dev", 3) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ printf("\nSATA device %d: ", dev);
+ if (dev >= CONFIG_SYS_SATA_MAX_DEVICE) {
+ puts ("unknown device\n");
+ return 1;
+ }
+ dev_print(&sata_dev_desc[dev]);
+
+ if (sata_dev_desc[dev].type == DEV_TYPE_UNKNOWN)
+ return 1;
+
+ sata_curr_device = dev;
+
+ puts("... is now current device\n");
+
+ return 0;
+ } else if (strncmp(argv[1], "part", 4) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
+ print_part(&sata_dev_desc[dev]);
+ } else {
+ printf("\nSATA device %d not available\n", dev);
+ rc = 1;
+ }
+ return rc;
+ }
+ return cmd_usage(cmdtp);
+
+ default: /* at least 4 args */
+ if (strcmp(argv[1], "read") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+ lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
+
+ printf("\nSATA read: device %d block # %ld, count %ld ... ",
+ sata_curr_device, blk, cnt);
+
+ n = sata_read(sata_curr_device, blk, cnt, (u32 *)addr);
+
+ /* flush cache after read */
+ flush_cache(addr, cnt * sata_dev_desc[sata_curr_device].blksz);
+
+ printf("%ld blocks read: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ return (n == cnt) ? 0 : 1;
+ } else if (strcmp(argv[1], "write") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+
+ lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
+
+ printf("\nSATA write: device %d block # %ld, count %ld ... ",
+ sata_curr_device, blk, cnt);
+
+ n = sata_write(sata_curr_device, blk, cnt, (u32 *)addr);
+
+ printf("%ld blocks written: %s\n",
+ n, (n == cnt) ? "OK" : "ERROR");
+ return (n == cnt) ? 0 : 1;
+ } else {
+ return cmd_usage(cmdtp);
+ }
+
+ return rc;
+ }
+}
+
+U_BOOT_CMD(
+ sata, 5, 1, do_sata,
+ "SATA sub system",
+ "sata init - init SATA sub system\n"
+ "sata info - show available SATA devices\n"
+ "sata device [dev] - show or set current device\n"
+ "sata part [dev] - print partition table\n"
+ "sata read addr blk# cnt\n"
+ "sata write addr blk# cnt"
+);
diff --git a/u-boot/common/cmd_scsi.c b/u-boot/common/cmd_scsi.c
new file mode 100644
index 0000000..be4fe74
--- /dev/null
+++ b/u-boot/common/cmd_scsi.c
@@ -0,0 +1,629 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * 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
+ *
+ *
+ *
+ */
+
+/*
+ * SCSI support.
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <scsi.h>
+#include <image.h>
+#include <pci.h>
+
+#ifdef CONFIG_SCSI_SYM53C8XX
+#define SCSI_VEND_ID 0x1000
+#ifndef CONFIG_SCSI_DEV_ID
+#define SCSI_DEV_ID 0x0001
+#else
+#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID
+#endif
+#elif defined CONFIG_SATA_ULI5288
+
+#define SCSI_VEND_ID 0x10b9
+#define SCSI_DEV_ID 0x5288
+
+#else
+#error no scsi device defined
+#endif
+
+
+static ccb tempccb; /* temporary scsi command buffer */
+
+static unsigned char tempbuff[512]; /* temporary data buffer */
+
+static int scsi_max_devs; /* number of highest available scsi device */
+
+static int scsi_curr_dev; /* current device */
+
+static block_dev_desc_t scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
+
+/********************************************************************************
+ * forward declerations of some Setup Routines
+ */
+void scsi_setup_test_unit_ready(ccb * pccb);
+void scsi_setup_read_capacity(ccb * pccb);
+void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);
+void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);
+void scsi_setup_inquiry(ccb * pccb);
+void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+
+
+ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer);
+
+
+/*********************************************************************************
+ * (re)-scan the scsi bus and reports scsi device info
+ * to the user if mode = 1
+ */
+void scsi_scan(int mode)
+{
+ unsigned char i,perq,modi,lun;
+ unsigned long capacity,blksz;
+ ccb* pccb=(ccb *)&tempccb;
+
+ if(mode==1) {
+ printf("scanning bus for devices...\n");
+ }
+ for(i=0;i<CONFIG_SYS_SCSI_MAX_DEVICE;i++) {
+ scsi_dev_desc[i].target=0xff;
+ scsi_dev_desc[i].lun=0xff;
+ scsi_dev_desc[i].lba=0;
+ scsi_dev_desc[i].blksz=0;
+ scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN;
+ scsi_dev_desc[i].vendor[0]=0;
+ scsi_dev_desc[i].product[0]=0;
+ scsi_dev_desc[i].revision[0]=0;
+ scsi_dev_desc[i].removable=FALSE;
+ scsi_dev_desc[i].if_type=IF_TYPE_SCSI;
+ scsi_dev_desc[i].dev=i;
+ scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+ scsi_dev_desc[i].block_read=scsi_read;
+ }
+ scsi_max_devs=0;
+ for(i=0;i<CONFIG_SYS_SCSI_MAX_SCSI_ID;i++) {
+ pccb->target=i;
+ for(lun=0;lun<CONFIG_SYS_SCSI_MAX_LUN;lun++) {
+ pccb->lun=lun;
+ pccb->pdata=(unsigned char *)&tempbuff;
+ pccb->datalen=512;
+ scsi_setup_inquiry(pccb);
+ if(scsi_exec(pccb)!=TRUE) {
+ if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
+ debug ("Selection timeout ID %d\n",pccb->target);
+ continue; /* selection timeout => assuming no device present */
+ }
+ scsi_print_error(pccb);
+ continue;
+ }
+ perq=tempbuff[0];
+ modi=tempbuff[1];
+ if((perq & 0x1f)==0x1f) {
+ continue; /* skip unknown devices */
+ }
+ if((modi&0x80)==0x80) /* drive is removable */
+ scsi_dev_desc[scsi_max_devs].removable=TRUE;
+ /* get info for this device */
+ scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0],
+ &tempbuff[8], 8);
+ scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0],
+ &tempbuff[16], 16);
+ scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0],
+ &tempbuff[32], 4);
+ scsi_dev_desc[scsi_max_devs].target=pccb->target;
+ scsi_dev_desc[scsi_max_devs].lun=pccb->lun;
+
+ pccb->datalen=0;
+ scsi_setup_test_unit_ready(pccb);
+ if(scsi_exec(pccb)!=TRUE) {
+ if(scsi_dev_desc[scsi_max_devs].removable==TRUE) {
+ scsi_dev_desc[scsi_max_devs].type=perq;
+ goto removable;
+ }
+ scsi_print_error(pccb);
+ continue;
+ }
+ pccb->datalen=8;
+ scsi_setup_read_capacity(pccb);
+ if(scsi_exec(pccb)!=TRUE) {
+ scsi_print_error(pccb);
+ continue;
+ }
+ capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)|
+ ((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]);
+ blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)|
+ ((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]);
+ scsi_dev_desc[scsi_max_devs].lba=capacity;
+ scsi_dev_desc[scsi_max_devs].blksz=blksz;
+ scsi_dev_desc[scsi_max_devs].type=perq;
+ init_part(&scsi_dev_desc[scsi_max_devs]);
+removable:
+ if(mode==1) {
+ printf (" Device %d: ", scsi_max_devs);
+ dev_print(&scsi_dev_desc[scsi_max_devs]);
+ } /* if mode */
+ scsi_max_devs++;
+ } /* next LUN */
+ }
+ if(scsi_max_devs>0)
+ scsi_curr_dev=0;
+ else
+ scsi_curr_dev = -1;
+}
+
+
+void scsi_init(void)
+{
+ int busdevfunc;
+
+ busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */
+ if(busdevfunc==-1) {
+ printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID);
+ return;
+ }
+#ifdef DEBUG
+ else {
+ printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7);
+ }
+#endif
+ scsi_low_level_init(busdevfunc);
+ scsi_scan(1);
+}
+
+block_dev_desc_t * scsi_get_dev(int dev)
+{
+ return (dev < CONFIG_SYS_SCSI_MAX_DEVICE) ? &scsi_dev_desc[dev] : NULL;
+}
+
+
+/******************************************************************************
+ * scsi boot command intepreter. Derived from diskboot
+ */
+int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev, part = 0;
+ ulong addr, cnt;
+ disk_partition_t info;
+ image_header_t *hdr;
+ int rcode = 0;
+#if defined(CONFIG_FIT)
+ const void *fit_hdr = NULL;
+#endif
+
+ switch (argc) {
+ case 1:
+ addr = CONFIG_SYS_LOAD_ADDR;
+ boot_device = getenv ("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv ("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (!boot_device) {
+ puts ("\n** No boot device **\n");
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+ printf("booting from dev %d\n",dev);
+ if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+ printf ("\n** Device %d not available\n", dev);
+ return 1;
+ }
+
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = simple_strtoul(++ep, NULL, 16);
+ }
+ if (get_partition_info (&scsi_dev_desc[dev], part, &info)) {
+ printf("error reading partinfo\n");
+ return 1;
+ }
+ if ((strncmp((char *)(info.type), BOOT_PART_TYPE, sizeof(info.type)) != 0) &&
+ (strncmp((char *)(info.type), BOOT_PART_COMP, sizeof(info.type)) != 0)) {
+ printf ("\n** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ return 1;
+ }
+
+ printf ("\nLoading from SCSI device %d, partition %d: "
+ "Name: %.32s Type: %.32s\n",
+ dev, part, info.name, info.type);
+
+ debug ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
+ info.start, info.size, info.blksz);
+
+ if (scsi_read (dev, info.start, 1, (ulong *)addr) != 1) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ return 1;
+ }
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+
+ if (!image_check_hcrc (hdr)) {
+ puts ("\n** Bad Header Checksum **\n");
+ return 1;
+ }
+
+ image_print_contents (hdr);
+ cnt = image_get_image_size (hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (const void *)addr;
+ puts ("Fit image detected...\n");
+
+ cnt = fit_get_size (fit_hdr);
+ break;
+#endif
+ default:
+ puts ("** Unknown image type\n");
+ return 1;
+ }
+
+ cnt += info.blksz - 1;
+ cnt /= info.blksz;
+ cnt -= 1;
+
+ if (scsi_read (dev, info.start+1, cnt,
+ (ulong *)(addr+info.blksz)) != cnt) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ return 1;
+ }
+
+#if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+ if (!fit_check_format (fit_hdr)) {
+ puts ("** Bad FIT image format\n");
+ return 1;
+ }
+ fit_print_contents (fit_hdr);
+ }
+#endif
+
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ flush_cache (addr, (cnt+1)*info.blksz);
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+ char *local_args[2];
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+ printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
+ rcode = do_bootm (cmdtp, 0, 1, local_args);
+ }
+ return rcode;
+}
+
+/*********************************************************************************
+ * scsi command intepreter
+ */
+int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ switch (argc) {
+ case 0:
+ case 1: return cmd_usage(cmdtp);
+
+ case 2:
+ if (strncmp(argv[1],"res",3) == 0) {
+ printf("\nReset SCSI\n");
+ scsi_bus_reset();
+ scsi_scan(1);
+ return 0;
+ }
+ if (strncmp(argv[1],"inf",3) == 0) {
+ int i;
+ for (i=0; i<CONFIG_SYS_SCSI_MAX_DEVICE; ++i) {
+ if(scsi_dev_desc[i].type==DEV_TYPE_UNKNOWN)
+ continue; /* list only known devices */
+ printf ("SCSI dev. %d: ", i);
+ dev_print(&scsi_dev_desc[i]);
+ }
+ return 0;
+ }
+ if (strncmp(argv[1],"dev",3) == 0) {
+ if ((scsi_curr_dev < 0) || (scsi_curr_dev >= CONFIG_SYS_SCSI_MAX_DEVICE)) {
+ printf("\nno SCSI devices available\n");
+ return 1;
+ }
+ printf ("\n Device %d: ", scsi_curr_dev);
+ dev_print(&scsi_dev_desc[scsi_curr_dev]);
+ return 0;
+ }
+ if (strncmp(argv[1],"scan",4) == 0) {
+ scsi_scan(1);
+ return 0;
+ }
+ if (strncmp(argv[1],"part",4) == 0) {
+ int dev, ok;
+ for (ok=0, dev=0; dev<CONFIG_SYS_SCSI_MAX_DEVICE; ++dev) {
+ if (scsi_dev_desc[dev].type!=DEV_TYPE_UNKNOWN) {
+ ok++;
+ if (dev)
+ printf("\n");
+ debug ("print_part of %x\n",dev);
+ print_part(&scsi_dev_desc[dev]);
+ }
+ }
+ if (!ok)
+ printf("\nno SCSI devices available\n");
+ return 1;
+ }
+ return cmd_usage(cmdtp);
+ case 3:
+ if (strncmp(argv[1],"dev",3) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+ printf ("\nSCSI device %d: ", dev);
+ if (dev >= CONFIG_SYS_SCSI_MAX_DEVICE) {
+ printf("unknown device\n");
+ return 1;
+ }
+ printf ("\n Device %d: ", dev);
+ dev_print(&scsi_dev_desc[dev]);
+ if(scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+ return 1;
+ }
+ scsi_curr_dev = dev;
+ printf("... is now current device\n");
+ return 0;
+ }
+ if (strncmp(argv[1],"part",4) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+ if(scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) {
+ print_part(&scsi_dev_desc[dev]);
+ }
+ else {
+ printf ("\nSCSI device %d not available\n", dev);
+ }
+ return 1;
+ }
+ return cmd_usage(cmdtp);
+ default:
+ /* at least 4 args */
+ if (strcmp(argv[1],"read") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong blk = simple_strtoul(argv[3], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+ printf ("\nSCSI read: device %d block # %ld, count %ld ... ",
+ scsi_curr_dev, blk, cnt);
+ n = scsi_read(scsi_curr_dev, blk, cnt, (ulong *)addr);
+ printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR");
+ return 0;
+ }
+ } /* switch */
+ return cmd_usage(cmdtp);
+}
+
+/****************************************************************************************
+ * scsi_read
+ */
+
+#define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */
+
+ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer)
+{
+ ulong start,blks, buf_addr;
+ unsigned short smallblks;
+ ccb* pccb=(ccb *)&tempccb;
+ device&=0xff;
+ /* Setup device
+ */
+ pccb->target=scsi_dev_desc[device].target;
+ pccb->lun=scsi_dev_desc[device].lun;
+ buf_addr=(unsigned long)buffer;
+ start=blknr;
+ blks=blkcnt;
+ debug ("\nscsi_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks,(unsigned long)buffer);
+ do {
+ pccb->pdata=(unsigned char *)buf_addr;
+ if(blks>SCSI_MAX_READ_BLK) {
+ pccb->datalen=scsi_dev_desc[device].blksz * SCSI_MAX_READ_BLK;
+ smallblks=SCSI_MAX_READ_BLK;
+ scsi_setup_read_ext(pccb,start,smallblks);
+ start+=SCSI_MAX_READ_BLK;
+ blks-=SCSI_MAX_READ_BLK;
+ }
+ else {
+ pccb->datalen=scsi_dev_desc[device].blksz * blks;
+ smallblks=(unsigned short) blks;
+ scsi_setup_read_ext(pccb,start,smallblks);
+ start+=blks;
+ blks=0;
+ }
+ debug ("scsi_read_ext: startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+ if(scsi_exec(pccb)!=TRUE) {
+ scsi_print_error(pccb);
+ blkcnt-=blks;
+ break;
+ }
+ buf_addr+=pccb->datalen;
+ } while(blks!=0);
+ debug ("scsi_read_ext: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+ return(blkcnt);
+}
+
+/* copy src to dest, skipping leading and trailing blanks
+ * and null terminate the string
+ */
+void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
+{
+ int start,end;
+
+ start=0;
+ while(start<len) {
+ if(src[start]!=' ')
+ break;
+ start++;
+ }
+ end=len-1;
+ while(end>start) {
+ if(src[end]!=' ')
+ break;
+ end--;
+ }
+ for( ; start<=end; start++) {
+ *dest++=src[start];
+ }
+ *dest='\0';
+}
+
+
+/* Trim trailing blanks, and NUL-terminate string
+ */
+void scsi_trim_trail (unsigned char *str, unsigned int len)
+{
+ unsigned char *p = str + len - 1;
+
+ while (len-- > 0) {
+ *p-- = '\0';
+ if (*p != ' ') {
+ return;
+ }
+ }
+}
+
+
+/************************************************************************************
+ * Some setup (fill-in) routines
+ */
+void scsi_setup_test_unit_ready(ccb * pccb)
+{
+ pccb->cmd[0]=SCSI_TST_U_RDY;
+ pccb->cmd[1]=pccb->lun<<5;
+ pccb->cmd[2]=0;
+ pccb->cmd[3]=0;
+ pccb->cmd[4]=0;
+ pccb->cmd[5]=0;
+ pccb->cmdlen=6;
+ pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
+}
+
+void scsi_setup_read_capacity(ccb * pccb)
+{
+ pccb->cmd[0]=SCSI_RD_CAPAC;
+ pccb->cmd[1]=pccb->lun<<5;
+ pccb->cmd[2]=0;
+ pccb->cmd[3]=0;
+ pccb->cmd[4]=0;
+ pccb->cmd[5]=0;
+ pccb->cmd[6]=0;
+ pccb->cmd[7]=0;
+ pccb->cmd[8]=0;
+ pccb->cmd[9]=0;
+ pccb->cmdlen=10;
+ pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
+
+}
+
+void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks)
+{
+ pccb->cmd[0]=SCSI_READ10;
+ pccb->cmd[1]=pccb->lun<<5;
+ pccb->cmd[2]=((unsigned char) (start>>24))&0xff;
+ pccb->cmd[3]=((unsigned char) (start>>16))&0xff;
+ pccb->cmd[4]=((unsigned char) (start>>8))&0xff;
+ pccb->cmd[5]=((unsigned char) (start))&0xff;
+ pccb->cmd[6]=0;
+ pccb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
+ pccb->cmd[8]=(unsigned char) blocks & 0xff;
+ pccb->cmd[6]=0;
+ pccb->cmdlen=10;
+ pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
+ debug ("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
+ pccb->cmd[0],pccb->cmd[1],
+ pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5],
+ pccb->cmd[7],pccb->cmd[8]);
+}
+
+void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks)
+{
+ pccb->cmd[0]=SCSI_READ6;
+ pccb->cmd[1]=pccb->lun<<5 | (((unsigned char)(start>>16))&0x1f);
+ pccb->cmd[2]=((unsigned char) (start>>8))&0xff;
+ pccb->cmd[3]=((unsigned char) (start))&0xff;
+ pccb->cmd[4]=(unsigned char) blocks & 0xff;
+ pccb->cmd[5]=0;
+ pccb->cmdlen=6;
+ pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
+ debug ("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n",
+ pccb->cmd[0],pccb->cmd[1],
+ pccb->cmd[2],pccb->cmd[3],pccb->cmd[4]);
+}
+
+
+void scsi_setup_inquiry(ccb * pccb)
+{
+ pccb->cmd[0]=SCSI_INQUIRY;
+ pccb->cmd[1]=pccb->lun<<5;
+ pccb->cmd[2]=0;
+ pccb->cmd[3]=0;
+ if(pccb->datalen>255)
+ pccb->cmd[4]=255;
+ else
+ pccb->cmd[4]=(unsigned char)pccb->datalen;
+ pccb->cmd[5]=0;
+ pccb->cmdlen=6;
+ pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
+}
+
+
+U_BOOT_CMD(
+ scsi, 5, 1, do_scsi,
+ "SCSI sub-system",
+ "reset - reset SCSI controller\n"
+ "scsi info - show available SCSI devices\n"
+ "scsi scan - (re-)scan SCSI bus\n"
+ "scsi device [dev] - show or set current device\n"
+ "scsi part [dev] - print partition table of one or all SCSI devices\n"
+ "scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
+ " to memory address `addr'"
+);
+
+U_BOOT_CMD(
+ scsiboot, 3, 1, do_scsiboot,
+ "boot from SCSI device",
+ "loadAddr dev:part"
+);
diff --git a/u-boot/common/cmd_setexpr.c b/u-boot/common/cmd_setexpr.c
new file mode 100644
index 0000000..1ff1232
--- /dev/null
+++ b/u-boot/common/cmd_setexpr.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * 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
+ */
+
+/*
+ * This file provides a shell like 'expr' function to return.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+static ulong get_arg(char *s, int w)
+{
+ ulong *p;
+
+ /*
+ * if the parameter starts with a '*' then assume
+ * it is a pointer to the value we want
+ */
+
+ if (s[0] == '*') {
+ p = (ulong *)simple_strtoul(&s[1], NULL, 16);
+ switch (w) {
+ case 1: return((ulong)(*(uchar *)p));
+ case 2: return((ulong)(*(ushort *)p));
+ case 4:
+ default: return(*p);
+ }
+ } else {
+ return simple_strtoul(s, NULL, 16);
+ }
+}
+
+int do_setexpr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong a, b;
+ char buf[16];
+ int w;
+
+ /* Validate arguments */
+ if ((argc != 5) || (strlen(argv[3]) != 1))
+ return cmd_usage(cmdtp);
+
+ w = cmd_get_data_size(argv[0], 4);
+
+ a = get_arg(argv[2], w);
+ b = get_arg(argv[4], w);
+
+ switch (argv[3][0]) {
+ case '|': sprintf(buf, "%lx", (a | b)); break;
+ case '&': sprintf(buf, "%lx", (a & b)); break;
+ case '+': sprintf(buf, "%lx", (a + b)); break;
+ case '^': sprintf(buf, "%lx", (a ^ b)); break;
+ case '-': sprintf(buf, "%lx", (a - b)); break;
+ case '*': sprintf(buf, "%lx", (a * b)); break;
+ case '/': sprintf(buf, "%lx", (a / b)); break;
+ case '%': sprintf(buf, "%lx", (a % b)); break;
+ default:
+ printf("invalid op\n");
+ return 1;
+ }
+
+ setenv(argv[1], buf);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ setexpr, 5, 0, do_setexpr,
+ "set environment variable as the result of eval expression",
+ "[.b, .w, .l] name value1 <op> value2\n"
+ " - set environment variable 'name' to the result of the evaluated\n"
+ " express specified by <op>. <op> can be &, |, ^, +, -, *, /, %\n"
+ " size argument is only meaningful if value1 and/or value2 are memory addresses"
+);
diff --git a/u-boot/common/cmd_sf.c b/u-boot/common/cmd_sf.c
new file mode 100644
index 0000000..6e7be81
--- /dev/null
+++ b/u-boot/common/cmd_sf.c
@@ -0,0 +1,193 @@
+/*
+ * Command for accessing SPI flash.
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <spi_flash.h>
+
+#include <asm/io.h>
+
+#ifndef CONFIG_SF_DEFAULT_SPEED
+# define CONFIG_SF_DEFAULT_SPEED 1000000
+#endif
+#ifndef CONFIG_SF_DEFAULT_MODE
+# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
+#endif
+
+static struct spi_flash *flash;
+
+static int do_spi_flash_probe(int argc, char * const argv[])
+{
+ unsigned int bus = 0;
+ unsigned int cs;
+ unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
+ unsigned int mode = CONFIG_SF_DEFAULT_MODE;
+ char *endp;
+ struct spi_flash *new;
+
+ if (argc < 2)
+ goto usage;
+
+ cs = simple_strtoul(argv[1], &endp, 0);
+ if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
+ goto usage;
+ if (*endp == ':') {
+ if (endp[1] == 0)
+ goto usage;
+
+ bus = cs;
+ cs = simple_strtoul(endp + 1, &endp, 0);
+ if (*endp != 0)
+ goto usage;
+ }
+
+ if (argc >= 3) {
+ speed = simple_strtoul(argv[2], &endp, 0);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (argc >= 4) {
+ mode = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+ }
+
+ new = spi_flash_probe(bus, cs, speed, mode);
+ if (!new) {
+ printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
+ return 1;
+ }
+
+ if (flash)
+ spi_flash_free(flash);
+ flash = new;
+
+ printf("%u KiB %s at %u:%u is now current device\n",
+ flash->size >> 10, flash->name, bus, cs);
+
+ return 0;
+
+usage:
+ puts("Usage: sf probe [bus:]cs [hz] [mode]\n");
+ return 1;
+}
+
+static int do_spi_flash_read_write(int argc, char * const argv[])
+{
+ unsigned long addr;
+ unsigned long offset;
+ unsigned long len;
+ void *buf;
+ char *endp;
+ int ret;
+
+ if (argc < 4)
+ goto usage;
+
+ addr = simple_strtoul(argv[1], &endp, 16);
+ if (*argv[1] == 0 || *endp != 0)
+ goto usage;
+ offset = simple_strtoul(argv[2], &endp, 16);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ len = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+
+ buf = map_physmem(addr, len, MAP_WRBACK);
+ if (!buf) {
+ puts("Failed to map physical memory\n");
+ return 1;
+ }
+
+ if (strcmp(argv[0], "read") == 0)
+ ret = spi_flash_read(flash, offset, len, buf);
+ else
+ ret = spi_flash_write(flash, offset, len, buf);
+
+ unmap_physmem(buf, len);
+
+ if (ret) {
+ printf("SPI flash %s failed\n", argv[0]);
+ return 1;
+ }
+
+ return 0;
+
+usage:
+ printf("Usage: sf %s addr offset len\n", argv[0]);
+ return 1;
+}
+
+static int do_spi_flash_erase(int argc, char * const argv[])
+{
+ unsigned long offset;
+ unsigned long len;
+ char *endp;
+ int ret;
+
+ if (argc < 3)
+ goto usage;
+
+ offset = simple_strtoul(argv[1], &endp, 16);
+ if (*argv[1] == 0 || *endp != 0)
+ goto usage;
+ len = simple_strtoul(argv[2], &endp, 16);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+
+ ret = spi_flash_erase(flash, offset, len);
+ if (ret) {
+ printf("SPI flash %s failed\n", argv[0]);
+ return 1;
+ }
+
+ return 0;
+
+usage:
+ puts("Usage: sf erase offset len\n");
+ return 1;
+}
+
+static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const char *cmd;
+
+ /* need at least two arguments */
+ if (argc < 2)
+ goto usage;
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "probe") == 0)
+ return do_spi_flash_probe(argc - 1, argv + 1);
+
+ /* The remaining commands require a selected device */
+ if (!flash) {
+ puts("No SPI flash selected. Please run `sf probe'\n");
+ return 1;
+ }
+
+ if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
+ return do_spi_flash_read_write(argc - 1, argv + 1);
+ if (strcmp(cmd, "erase") == 0)
+ return do_spi_flash_erase(argc - 1, argv + 1);
+
+usage:
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ sf, 5, 1, do_spi_flash,
+ "SPI flash sub-system",
+ "probe [bus:]cs [hz] [mode] - init flash device on given SPI bus\n"
+ " and chip select\n"
+ "sf read addr offset len - read `len' bytes starting at\n"
+ " `offset' to memory at `addr'\n"
+ "sf write addr offset len - write `len' bytes from memory\n"
+ " at `addr' to flash at `offset'\n"
+ "sf erase offset len - erase `len' bytes from `offset'"
+);
diff --git a/u-boot/common/cmd_source.c b/u-boot/common/cmd_source.c
new file mode 100644
index 0000000..16a627a
--- /dev/null
+++ b/u-boot/common/cmd_source.c
@@ -0,0 +1,239 @@
+/*
+ * (C) Copyright 2001
+ * Kyle Harris, kharris@nexus-tech.net
+ *
+ * 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
+ */
+
+/*
+ * The "source" command allows to define "script images", i. e. files
+ * that contain command sequences that can be executed by the command
+ * interpreter. It returns the exit status of the last command
+ * executed from the script. This is very similar to running a shell
+ * script in a UNIX shell, hence the name for the command.
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#endif
+#ifdef CONFIG_SYS_HUSH_PARSER
+#include <hush.h>
+#endif
+
+int
+source (ulong addr, const char *fit_uname)
+{
+ ulong len;
+ image_header_t *hdr;
+ ulong *data;
+ char *cmd;
+ int rcode = 0;
+ int verify;
+#if defined(CONFIG_FIT)
+ const void* fit_hdr;
+ int noffset;
+ const void *fit_data;
+ size_t fit_len;
+#endif
+
+ verify = getenv_yesno ("verify");
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+
+ if (!image_check_magic (hdr)) {
+ puts ("Bad magic number\n");
+ return 1;
+ }
+
+ if (!image_check_hcrc (hdr)) {
+ puts ("Bad header crc\n");
+ return 1;
+ }
+
+ if (verify) {
+ if (!image_check_dcrc (hdr)) {
+ puts ("Bad data crc\n");
+ return 1;
+ }
+ }
+
+ if (!image_check_type (hdr, IH_TYPE_SCRIPT)) {
+ puts ("Bad image type\n");
+ return 1;
+ }
+
+ /* get length of script */
+ data = (ulong *)image_get_data (hdr);
+
+ if ((len = uimage_to_cpu (*data)) == 0) {
+ puts ("Empty Script\n");
+ return 1;
+ }
+
+ /*
+ * scripts are just multi-image files with one component, seek
+ * past the zero-terminated sequence of image lengths to get
+ * to the actual image data
+ */
+ while (*data++);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ if (fit_uname == NULL) {
+ puts ("No FIT subimage unit name\n");
+ return 1;
+ }
+
+ fit_hdr = (const void *)addr;
+ if (!fit_check_format (fit_hdr)) {
+ puts ("Bad FIT image format\n");
+ return 1;
+ }
+
+ /* get script component image node offset */
+ noffset = fit_image_get_node (fit_hdr, fit_uname);
+ if (noffset < 0) {
+ printf ("Can't find '%s' FIT subimage\n", fit_uname);
+ return 1;
+ }
+
+ if (!fit_image_check_type (fit_hdr, noffset, IH_TYPE_SCRIPT)) {
+ puts ("Not a image image\n");
+ return 1;
+ }
+
+ /* verify integrity */
+ if (verify) {
+ if (!fit_image_check_hashes (fit_hdr, noffset)) {
+ puts ("Bad Data Hash\n");
+ return 1;
+ }
+ }
+
+ /* get script subimage data address and length */
+ if (fit_image_get_data (fit_hdr, noffset, &fit_data, &fit_len)) {
+ puts ("Could not find script subimage data\n");
+ return 1;
+ }
+
+ data = (ulong *)fit_data;
+ len = (ulong)fit_len;
+ break;
+#endif
+ default:
+ puts ("Wrong image format for \"source\" command\n");
+ return 1;
+ }
+
+ debug ("** Script length: %ld\n", len);
+
+ if ((cmd = malloc (len + 1)) == NULL) {
+ return 1;
+ }
+
+ /* make sure cmd is null terminated */
+ memmove (cmd, (char *)data, len);
+ *(cmd + len) = 0;
+
+#ifdef CONFIG_SYS_HUSH_PARSER /*?? */
+ rcode = parse_string_outer (cmd, FLAG_PARSE_SEMICOLON);
+#else
+ {
+ char *line = cmd;
+ char *next = cmd;
+
+ /*
+ * break into individual lines,
+ * and execute each line;
+ * terminate on error.
+ */
+ while (*next) {
+ if (*next == '\n') {
+ *next = '\0';
+ /* run only non-empty commands */
+ if (*line) {
+ debug ("** exec: \"%s\"\n",
+ line);
+ if (run_command (line, 0) < 0) {
+ rcode = 1;
+ break;
+ }
+ }
+ line = next + 1;
+ }
+ ++next;
+ }
+ if (rcode == 0 && *line)
+ rcode = (run_command(line, 0) >= 0);
+ }
+#endif
+ free (cmd);
+ return rcode;
+}
+
+/**************************************************/
+#if defined(CONFIG_CMD_SOURCE)
+int
+do_source (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr;
+ int rcode;
+ const char *fit_uname = NULL;
+
+ /* Find script image */
+ if (argc < 2) {
+ addr = CONFIG_SYS_LOAD_ADDR;
+ debug ("* source: default load address = 0x%08lx\n", addr);
+#if defined(CONFIG_FIT)
+ } else if (fit_parse_subimage (argv[1], load_addr, &addr, &fit_uname)) {
+ debug ("* source: subimage '%s' from FIT image at 0x%08lx\n",
+ fit_uname, addr);
+#endif
+ } else {
+ addr = simple_strtoul(argv[1], NULL, 16);
+ debug ("* source: cmdline image address = 0x%08lx\n", addr);
+ }
+
+ printf ("## Executing script at %08lx\n", addr);
+ rcode = source (addr, fit_uname);
+ return rcode;
+}
+
+U_BOOT_CMD(
+ source, 2, 0, do_source,
+ "run script from memory",
+ "[addr]\n"
+ "\t- run script starting at addr\n"
+ "\t- A valid image header must be present"
+#if defined(CONFIG_FIT)
+ "\n"
+ "For FIT format uImage addr must include subimage\n"
+ "unit name in the form of addr:<subimg_uname>"
+#endif
+);
+#endif
diff --git a/u-boot/common/cmd_spi.c b/u-boot/common/cmd_spi.c
new file mode 100644
index 0000000..8c623c9
--- /dev/null
+++ b/u-boot/common/cmd_spi.c
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright 2002
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * SPI Read/Write Utilities
+ */
+
+#include <common.h>
+#include <command.h>
+#include <spi.h>
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#ifndef MAX_SPI_BYTES
+# define MAX_SPI_BYTES 32 /* Maximum number of bytes we can handle */
+#endif
+
+#ifndef CONFIG_DEFAULT_SPI_BUS
+# define CONFIG_DEFAULT_SPI_BUS 0
+#endif
+#ifndef CONFIG_DEFAULT_SPI_MODE
+# define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0
+#endif
+
+/*
+ * Values from last command.
+ */
+static unsigned int bus;
+static unsigned int cs;
+static unsigned int mode;
+static int bitlen;
+static uchar dout[MAX_SPI_BYTES];
+static uchar din[MAX_SPI_BYTES];
+
+/*
+ * SPI read/write
+ *
+ * Syntax:
+ * spi {dev} {num_bits} {dout}
+ * {dev} is the device number for controlling chip select (see TBD)
+ * {num_bits} is the number of bits to send & receive (base 10)
+ * {dout} is a hexadecimal string of data to send
+ * The command prints out the hexadecimal string received via SPI.
+ */
+
+int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct spi_slave *slave;
+ char *cp = 0;
+ uchar tmp;
+ int j;
+ int rcode = 0;
+
+ /*
+ * We use the last specified parameters, unless new ones are
+ * entered.
+ */
+
+ if ((flag & CMD_FLAG_REPEAT) == 0)
+ {
+ if (argc >= 2) {
+ mode = CONFIG_DEFAULT_SPI_MODE;
+ bus = simple_strtoul(argv[1], &cp, 10);
+ if (*cp == ':') {
+ cs = simple_strtoul(cp+1, &cp, 10);
+ } else {
+ cs = bus;
+ bus = CONFIG_DEFAULT_SPI_BUS;
+ }
+ if (*cp == '.');
+ mode = simple_strtoul(cp+1, NULL, 10);
+ }
+ if (argc >= 3)
+ bitlen = simple_strtoul(argv[2], NULL, 10);
+ if (argc >= 4) {
+ cp = argv[3];
+ for(j = 0; *cp; j++, cp++) {
+ tmp = *cp - '0';
+ if(tmp > 9)
+ tmp -= ('A' - '0') - 10;
+ if(tmp > 15)
+ tmp -= ('a' - 'A');
+ if(tmp > 15) {
+ printf("Hex conversion error on %c\n", *cp);
+ return 1;
+ }
+ if((j % 2) == 0)
+ dout[j / 2] = (tmp << 4);
+ else
+ dout[j / 2] |= tmp;
+ }
+ }
+ }
+
+ if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) {
+ printf("Invalid bitlen %d\n", bitlen);
+ return 1;
+ }
+
+ slave = spi_setup_slave(bus, cs, 1000000, mode);
+ if (!slave) {
+ printf("Invalid device %d:%d\n", bus, cs);
+ return 1;
+ }
+
+ spi_claim_bus(slave);
+ if(spi_xfer(slave, bitlen, dout, din,
+ SPI_XFER_BEGIN | SPI_XFER_END) != 0) {
+ printf("Error during SPI transaction\n");
+ rcode = 1;
+ } else {
+ for(j = 0; j < ((bitlen + 7) / 8); j++) {
+ printf("%02X", din[j]);
+ }
+ printf("\n");
+ }
+ spi_release_bus(slave);
+ spi_free_slave(slave);
+
+ return rcode;
+}
+
+/***************************************************/
+
+U_BOOT_CMD(
+ sspi, 5, 1, do_spi,
+ "SPI utility command",
+ "[<bus>:]<cs>[.<mode>] <bit_len> <dout> - Send and receive bits\n"
+ "<bus> - Identifies the SPI bus\n"
+ "<cs> - Identifies the chip select\n"
+ "<mode> - Identifies the SPI mode to use\n"
+ "<bit_len> - Number of bits to send (base 10)\n"
+ "<dout> - Hexadecimal string that gets sent"
+);
diff --git a/u-boot/common/cmd_spibootldr.c b/u-boot/common/cmd_spibootldr.c
new file mode 100644
index 0000000..ca76dde
--- /dev/null
+++ b/u-boot/common/cmd_spibootldr.c
@@ -0,0 +1,37 @@
+/*
+ * U-boot - spibootldr.c
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/bootrom.h>
+
+int do_spibootldr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ s32 addr;
+
+ /* Get the address */
+ if (argc < 2)
+ addr = 0;
+ else
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ printf("## Booting ldr image at SPI offset 0x%x ...\n", addr);
+
+ return bfrom_SpiBoot(addr, BFLAG_PERIPHERAL | 4, 0, NULL);
+}
+
+U_BOOT_CMD(
+ spibootldr, 2, 0, do_spibootldr,
+ "boot ldr image from spi",
+ "[offset]\n"
+ " - boot ldr image stored at offset into spi\n");
diff --git a/u-boot/common/cmd_strings.c b/u-boot/common/cmd_strings.c
new file mode 100644
index 0000000..2986324
--- /dev/null
+++ b/u-boot/common/cmd_strings.c
@@ -0,0 +1,46 @@
+/*
+ * cmd_strings.c - just like `strings` command
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+
+static char *start_addr, *last_addr;
+
+int do_strings(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc == 1)
+ return cmd_usage(cmdtp);
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ start_addr = (char *)simple_strtoul(argv[1], NULL, 16);
+ if (argc > 2)
+ last_addr = (char *)simple_strtoul(argv[2], NULL, 16);
+ else
+ last_addr = (char *)-1;
+ }
+
+ char *addr = start_addr;
+ do {
+ puts(addr);
+ puts("\n");
+ addr += strlen(addr) + 1;
+ } while (addr[0] && addr < last_addr);
+
+ last_addr = addr + (last_addr - start_addr);
+ start_addr = addr;
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ strings, 3, 1, do_strings,
+ "display strings",
+ "<addr> [byte count]\n"
+ " - display strings at <addr> for at least [byte count] or first double NUL"
+);
diff --git a/u-boot/common/cmd_terminal.c b/u-boot/common/cmd_terminal.c
new file mode 100644
index 0000000..7cc1a6c
--- /dev/null
+++ b/u-boot/common/cmd_terminal.c
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2007 OpenMoko, Inc.
+ * Written by Harald Welte <laforge@openmoko.org>
+ *
+ * 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
+ */
+
+/*
+ * Boot support
+ */
+#include <common.h>
+#include <command.h>
+#include <stdio_dev.h>
+#include <serial.h>
+
+int do_terminal(cmd_tbl_t * cmd, int flag, int argc, char * const argv[])
+{
+ int last_tilde = 0;
+ struct stdio_dev *dev = NULL;
+
+ if (argc < 1)
+ return -1;
+
+ /* Scan for selected output/input device */
+ dev = stdio_get_by_name(argv[1]);
+ if (!dev)
+ return -1;
+
+ serial_reinit_all();
+ printf("Entering terminal mode for port %s\n", dev->name);
+ puts("Use '~.' to leave the terminal and get back to u-boot\n");
+
+ while (1) {
+ int c;
+
+ /* read from console and display on serial port */
+ if (stdio_devices[0]->tstc()) {
+ c = stdio_devices[0]->getc();
+ if (last_tilde == 1) {
+ if (c == '.') {
+ putc(c);
+ putc('\n');
+ break;
+ } else {
+ last_tilde = 0;
+ /* write the delayed tilde */
+ dev->putc('~');
+ /* fall-through to print current
+ * character */
+ }
+ }
+ if (c == '~') {
+ last_tilde = 1;
+ puts("[u-boot]");
+ putc(c);
+ }
+ dev->putc(c);
+ }
+
+ /* read from serial port and display on console */
+ if (dev->tstc()) {
+ c = dev->getc();
+ putc(c);
+ }
+ }
+ return 0;
+}
+
+
+/***************************************************/
+
+U_BOOT_CMD(
+ terminal, 3, 1, do_terminal,
+ "start terminal emulator",
+ ""
+);
diff --git a/u-boot/common/cmd_test.c b/u-boot/common/cmd_test.c
new file mode 100644
index 0000000..fcb5ef2
--- /dev/null
+++ b/u-boot/common/cmd_test.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+int do_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char * const *ap;
+ int left, adv, expr, last_expr, neg, last_cmp;
+
+ /* args? */
+ if (argc < 3)
+ return 1;
+
+#if 0
+ {
+ printf("test:");
+ left = 1;
+ while (argv[left])
+ printf(" %s", argv[left++]);
+ }
+#endif
+
+ last_expr = 0;
+ left = argc - 1; ap = argv + 1;
+ if (left > 0 && strcmp(ap[0], "!") == 0) {
+ neg = 1;
+ ap++;
+ left--;
+ } else
+ neg = 0;
+
+ expr = -1;
+ last_cmp = -1;
+ last_expr = -1;
+ while (left > 0) {
+
+ if (strcmp(ap[0], "-o") == 0 || strcmp(ap[0], "-a") == 0)
+ adv = 1;
+ else if (strcmp(ap[0], "-z") == 0 || strcmp(ap[0], "-n") == 0)
+ adv = 2;
+ else
+ adv = 3;
+
+ if (left < adv) {
+ expr = 1;
+ break;
+ }
+
+ if (adv == 1) {
+ if (strcmp(ap[0], "-o") == 0) {
+ last_expr = expr;
+ last_cmp = 0;
+ } else if (strcmp(ap[0], "-a") == 0) {
+ last_expr = expr;
+ last_cmp = 1;
+ } else {
+ expr = 1;
+ break;
+ }
+ }
+
+ if (adv == 2) {
+ if (strcmp(ap[0], "-z") == 0)
+ expr = strlen(ap[1]) == 0 ? 1 : 0;
+ else if (strcmp(ap[0], "-n") == 0)
+ expr = strlen(ap[1]) == 0 ? 0 : 1;
+ else {
+ expr = 1;
+ break;
+ }
+
+ if (last_cmp == 0)
+ expr = last_expr || expr;
+ else if (last_cmp == 1)
+ expr = last_expr && expr;
+ last_cmp = -1;
+ }
+
+ if (adv == 3) {
+ if (strcmp(ap[1], "=") == 0)
+ expr = strcmp(ap[0], ap[2]) == 0;
+ else if (strcmp(ap[1], "!=") == 0)
+ expr = strcmp(ap[0], ap[2]) != 0;
+ else if (strcmp(ap[1], ">") == 0)
+ expr = strcmp(ap[0], ap[2]) > 0;
+ else if (strcmp(ap[1], "<") == 0)
+ expr = strcmp(ap[0], ap[2]) < 0;
+ else if (strcmp(ap[1], "-eq") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) == simple_strtol(ap[2], NULL, 10);
+ else if (strcmp(ap[1], "-ne") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) != simple_strtol(ap[2], NULL, 10);
+ else if (strcmp(ap[1], "-lt") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) < simple_strtol(ap[2], NULL, 10);
+ else if (strcmp(ap[1], "-le") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) <= simple_strtol(ap[2], NULL, 10);
+ else if (strcmp(ap[1], "-gt") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) > simple_strtol(ap[2], NULL, 10);
+ else if (strcmp(ap[1], "-ge") == 0)
+ expr = simple_strtol(ap[0], NULL, 10) >= simple_strtol(ap[2], NULL, 10);
+ else {
+ expr = 1;
+ break;
+ }
+
+ if (last_cmp == 0)
+ expr = last_expr || expr;
+ else if (last_cmp == 1)
+ expr = last_expr && expr;
+ last_cmp = -1;
+ }
+
+ ap += adv; left -= adv;
+ }
+
+ if (neg)
+ expr = !expr;
+
+ expr = !expr;
+
+ debug (": returns %d\n", expr);
+
+ return expr;
+}
+
+U_BOOT_CMD(
+ test, CONFIG_SYS_MAXARGS, 1, do_test,
+ "minimal test like /bin/sh",
+ "[args..]"
+);
+
+int do_false(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return 1;
+}
+
+U_BOOT_CMD(
+ false, CONFIG_SYS_MAXARGS, 1, do_false,
+ "do nothing, unsuccessfully",
+ NULL
+);
+
+int do_true(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return 0;
+}
+
+U_BOOT_CMD(
+ true, CONFIG_SYS_MAXARGS, 1, do_true,
+ "do nothing, successfully",
+ NULL
+);
diff --git a/u-boot/common/cmd_tsi148.c b/u-boot/common/cmd_tsi148.c
new file mode 100644
index 0000000..6dc9dab
--- /dev/null
+++ b/u-boot/common/cmd_tsi148.c
@@ -0,0 +1,491 @@
+/*
+ * (C) Copyright 2009 Reinhard Arlt, reinhard.arlt@esd-electronics.com
+ *
+ * base on universe.h by
+ *
+ * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#include <tsi148.h>
+
+#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
+#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
+
+typedef struct _TSI148_DEV TSI148_DEV;
+
+struct _TSI148_DEV {
+ int bus;
+ pci_dev_t busdevfn;
+ TSI148 *uregs;
+ unsigned int pci_bs;
+};
+
+static TSI148_DEV *dev;
+
+/*
+ * Most of the TSI148 register are BIGENDIAN
+ * This is the reason for the __raw_writel(htonl(x), x) usage!
+ */
+
+int tsi148_init(void)
+{
+ int j, result, lastError = 0;
+ pci_dev_t busdevfn;
+ unsigned int val;
+
+ busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
+ if (busdevfn == -1) {
+ puts("Tsi148: No Tundra Tsi148 found!\n");
+ return -1;
+ }
+
+ /* Lets turn Latency off */
+ pci_write_config_dword(busdevfn, 0x0c, 0);
+
+ dev = malloc(sizeof(*dev));
+ if (NULL == dev) {
+ puts("Tsi148: No memory!\n");
+ result = -1;
+ goto break_20;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ dev->busdevfn = busdevfn;
+
+ pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val);
+ val &= ~0xf;
+ dev->uregs = (TSI148 *)val;
+
+ debug("Tsi148: Base : %p\n", dev->uregs);
+
+ /* check mapping */
+ debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
+ readl(&dev->uregs->pci_id));
+ if (((PCI_DEVICE << 16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
+ printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
+ readl(&dev->uregs->pci_id));
+ result = -1;
+ goto break_30;
+ }
+
+ debug("Tsi148: PCI_BS = %08X\n", readl(&dev->uregs->pci_mbarl));
+
+ dev->pci_bs = readl(&dev->uregs->pci_mbarl);
+
+ /* turn off windows */
+ for (j = 0; j < 8; j++) {
+ __raw_writel(htonl(0x00000000), &dev->uregs->outbound[j].otat);
+ __raw_writel(htonl(0x00000000), &dev->uregs->inbound[j].itat);
+ }
+
+ /* Tsi148 VME timeout etc */
+ __raw_writel(htonl(0x00000084), &dev->uregs->vctrl);
+
+#ifdef DEBUG
+ if ((__raw_readl(&dev->uregs->vstat) & 0x00000100) != 0)
+ printf("Tsi148: System Controller!\n");
+ else
+ printf("Tsi148: Not System Controller!\n");
+#endif
+
+ /*
+ * Lets turn off interrupts
+ */
+ /* Disable interrupts in Tsi148 first */
+ __raw_writel(htonl(0x00000000), &dev->uregs->inten);
+ /* Disable interrupt out */
+ __raw_writel(htonl(0x00000000), &dev->uregs->inteo);
+ eieio();
+ /* Reset all IRQ's */
+ __raw_writel(htonl(0x03ff3f00), &dev->uregs->intc);
+ /* Map all ints to 0 */
+ __raw_writel(htonl(0x00000000), &dev->uregs->intm1);
+ __raw_writel(htonl(0x00000000), &dev->uregs->intm2);
+ eieio();
+
+ val = __raw_readl(&dev->uregs->vstat);
+ val &= ~(0x00004000);
+ __raw_writel(val, &dev->uregs->vstat);
+ eieio();
+
+ debug("Tsi148: register struct size %08x\n", sizeof(TSI148));
+
+ return 0;
+
+ break_30:
+ free(dev);
+ dev = NULL;
+ break_20:
+ lastError = result;
+
+ return result;
+}
+
+/*
+ * Create pci slave window (access: pci -> vme)
+ */
+int tsi148_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr,
+ int size, int vam, int vdw)
+{
+ int result, i;
+ unsigned int ctl = 0;
+
+ if (NULL == dev) {
+ result = -1;
+ goto exit_10;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (0x00000000 == readl(&dev->uregs->outbound[i].otat))
+ break;
+ }
+
+ if (i > 7) {
+ printf("Tsi148: No Image available\n");
+ result = -1;
+ goto exit_10;
+ }
+
+ debug("Tsi148: Using image %d\n", i);
+
+ printf("Tsi148: Pci addr %08x\n", pciAddr);
+
+ __raw_writel(htonl(pciAddr), &dev->uregs->outbound[i].otsal);
+ __raw_writel(0x00000000, &dev->uregs->outbound[i].otsau);
+ __raw_writel(htonl(pciAddr + size), &dev->uregs->outbound[i].oteal);
+ __raw_writel(0x00000000, &dev->uregs->outbound[i].oteau);
+ __raw_writel(htonl(vmeAddr - pciAddr), &dev->uregs->outbound[i].otofl);
+ __raw_writel(0x00000000, &dev->uregs->outbound[i].otofu);
+
+ switch (vam & VME_AM_Axx) {
+ case VME_AM_A16:
+ ctl = 0x00000000;
+ break;
+ case VME_AM_A24:
+ ctl = 0x00000001;
+ break;
+ case VME_AM_A32:
+ ctl = 0x00000002;
+ break;
+ }
+
+ switch (vam & VME_AM_Mxx) {
+ case VME_AM_DATA:
+ ctl |= 0x00000000;
+ break;
+ case VME_AM_PROG:
+ ctl |= 0x00000010;
+ break;
+ }
+
+ if (vam & VME_AM_SUP)
+ ctl |= 0x00000020;
+
+ switch (vdw & VME_FLAG_Dxx) {
+ case VME_FLAG_D16:
+ ctl |= 0x00000000;
+ break;
+ case VME_FLAG_D32:
+ ctl |= 0x00000040;
+ break;
+ }
+
+ ctl |= 0x80040000; /* enable, no prefetch */
+
+ __raw_writel(htonl(ctl), &dev->uregs->outbound[i].otat);
+
+ debug("Tsi148: window-addr =%p\n",
+ &dev->uregs->outbound[i].otsau);
+ debug("Tsi148: pci slave window[%d] attr =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->outbound[i].otat)));
+ debug("Tsi148: pci slave window[%d] start =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->outbound[i].otsal)));
+ debug("Tsi148: pci slave window[%d] end =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->outbound[i].oteal)));
+ debug("Tsi148: pci slave window[%d] offset=%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->outbound[i].otofl)));
+
+ return 0;
+
+ exit_10:
+ return -result;
+}
+
+unsigned int tsi148_eval_vam(int vam)
+{
+ unsigned int ctl = 0;
+
+ switch (vam & VME_AM_Axx) {
+ case VME_AM_A16:
+ ctl = 0x00000000;
+ break;
+ case VME_AM_A24:
+ ctl = 0x00000010;
+ break;
+ case VME_AM_A32:
+ ctl = 0x00000020;
+ break;
+ }
+ switch (vam & VME_AM_Mxx) {
+ case VME_AM_DATA:
+ ctl |= 0x00000001;
+ break;
+ case VME_AM_PROG:
+ ctl |= 0x00000002;
+ break;
+ case (VME_AM_PROG | VME_AM_DATA):
+ ctl |= 0x00000003;
+ break;
+ }
+
+ if (vam & VME_AM_SUP)
+ ctl |= 0x00000008;
+ if (vam & VME_AM_USR)
+ ctl |= 0x00000004;
+
+ return ctl;
+}
+
+/*
+ * Create vme slave window (access: vme -> pci)
+ */
+int tsi148_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr,
+ int size, int vam)
+{
+ int result, i;
+ unsigned int ctl = 0;
+
+ if (NULL == dev) {
+ result = -1;
+ goto exit_10;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (0x00000000 == readl(&dev->uregs->inbound[i].itat))
+ break;
+ }
+
+ if (i > 7) {
+ printf("Tsi148: No Image available\n");
+ result = -1;
+ goto exit_10;
+ }
+
+ debug("Tsi148: Using image %d\n", i);
+
+ __raw_writel(htonl(vmeAddr), &dev->uregs->inbound[i].itsal);
+ __raw_writel(0x00000000, &dev->uregs->inbound[i].itsau);
+ __raw_writel(htonl(vmeAddr + size), &dev->uregs->inbound[i].iteal);
+ __raw_writel(0x00000000, &dev->uregs->inbound[i].iteau);
+ __raw_writel(htonl(pciAddr - vmeAddr), &dev->uregs->inbound[i].itofl);
+ if (vmeAddr > pciAddr)
+ __raw_writel(0xffffffff, &dev->uregs->inbound[i].itofu);
+ else
+ __raw_writel(0x00000000, &dev->uregs->inbound[i].itofu);
+
+ ctl = tsi148_eval_vam(vam);
+ ctl |= 0x80000000; /* enable */
+ __raw_writel(htonl(ctl), &dev->uregs->inbound[i].itat);
+
+ debug("Tsi148: window-addr =%p\n",
+ &dev->uregs->inbound[i].itsau);
+ debug("Tsi148: vme slave window[%d] attr =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->inbound[i].itat)));
+ debug("Tsi148: vme slave window[%d] start =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->inbound[i].itsal)));
+ debug("Tsi148: vme slave window[%d] end =%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->inbound[i].iteal)));
+ debug("Tsi148: vme slave window[%d] offset=%08x\n",
+ i, ntohl(__raw_readl(&dev->uregs->inbound[i].itofl)));
+
+ return 0;
+
+ exit_10:
+ return -result;
+}
+
+/*
+ * Create vme slave window (access: vme -> gcsr)
+ */
+int tsi148_vme_gcsr_window(unsigned int vmeAddr, int vam)
+{
+ int result;
+ unsigned int ctl;
+
+ result = 0;
+
+ if (NULL == dev) {
+ result = 1;
+ } else {
+ __raw_writel(htonl(vmeAddr), &dev->uregs->gbal);
+ __raw_writel(0x00000000, &dev->uregs->gbau);
+
+ ctl = tsi148_eval_vam(vam);
+ ctl |= 0x00000080; /* enable */
+ __raw_writel(htonl(ctl), &dev->uregs->gcsrat);
+ }
+
+ return result;
+}
+
+/*
+ * Create vme slave window (access: vme -> crcsr)
+ */
+int tsi148_vme_crcsr_window(unsigned int vmeAddr)
+{
+ int result;
+ unsigned int ctl;
+
+ result = 0;
+
+ if (NULL == dev) {
+ result = 1;
+ } else {
+ __raw_writel(htonl(vmeAddr), &dev->uregs->crol);
+ __raw_writel(0x00000000, &dev->uregs->crou);
+
+ ctl = 0x00000080; /* enable */
+ __raw_writel(htonl(ctl), &dev->uregs->crat);
+ }
+
+ return result;
+}
+
+/*
+ * Create vme slave window (access: vme -> crg)
+ */
+int tsi148_vme_crg_window(unsigned int vmeAddr, int vam)
+{
+ int result;
+ unsigned int ctl;
+
+ result = 0;
+
+ if (NULL == dev) {
+ result = 1;
+ } else {
+ __raw_writel(htonl(vmeAddr), &dev->uregs->cbal);
+ __raw_writel(0x00000000, &dev->uregs->cbau);
+
+ ctl = tsi148_eval_vam(vam);
+ ctl |= 0x00000080; /* enable */
+ __raw_writel(htonl(ctl), &dev->uregs->crgat);
+ }
+
+ return result;
+}
+
+/*
+ * Tundra Tsi148 configuration
+ */
+int do_tsi148(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, vdw = 0;
+ char cmd = 'x';
+
+ /* get parameter */
+ if (argc > 1)
+ cmd = argv[1][0];
+ if (argc > 2)
+ addr1 = simple_strtoul(argv[2], NULL, 16);
+ if (argc > 3)
+ addr2 = simple_strtoul(argv[3], NULL, 16);
+ if (argc > 4)
+ size = simple_strtoul(argv[4], NULL, 16);
+ if (argc > 5)
+ vam = simple_strtoul(argv[5], NULL, 16);
+ if (argc > 6)
+ vdw = simple_strtoul(argv[6], NULL, 16);
+
+ switch (cmd) {
+ case 'c':
+ if (strcmp(argv[1], "crg") == 0) {
+ vam = addr2;
+ printf("Tsi148: Configuring VME CRG Window "
+ "(VME->CRG):\n");
+ printf(" vme=%08lx vam=%02lx\n", addr1, vam);
+ tsi148_vme_crg_window(addr1, vam);
+ } else {
+ printf("Tsi148: Configuring VME CR/CSR Window "
+ "(VME->CR/CSR):\n");
+ printf(" pci=%08lx\n", addr1);
+ tsi148_vme_crcsr_window(addr1);
+ }
+ break;
+ case 'i': /* init */
+ tsi148_init();
+ break;
+ case 'g':
+ vam = addr2;
+ printf("Tsi148: Configuring VME GCSR Window (VME->GCSR):\n");
+ printf(" vme=%08lx vam=%02lx\n", addr1, vam);
+ tsi148_vme_gcsr_window(addr1, vam);
+ break;
+ case 'v': /* vme */
+ printf("Tsi148: Configuring VME Slave Window (VME->PCI):\n");
+ printf(" vme=%08lx pci=%08lx size=%08lx vam=%02lx\n",
+ addr1, addr2, size, vam);
+ tsi148_vme_slave_window(addr1, addr2, size, vam);
+ break;
+ case 'p': /* pci */
+ printf("Tsi148: Configuring PCI Slave Window (PCI->VME):\n");
+ printf(" pci=%08lx vme=%08lx size=%08lx vam=%02lx vdw=%02lx\n",
+ addr1, addr2, size, vam, vdw);
+ tsi148_pci_slave_window(addr1, addr2, size, vam, vdw);
+ break;
+ default:
+ printf("Tsi148: Command %s not supported!\n", argv[1]);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ tsi148, 7, 1, do_tsi148,
+ "initialize and configure Turndra Tsi148\n",
+ "init\n"
+ " - initialize tsi148\n"
+ "tsi148 vme [vme_addr] [pci_addr] [size] [vam]\n"
+ " - create vme slave window (access: vme->pci)\n"
+ "tsi148 pci [pci_addr] [vme_addr] [size] [vam] [vdw]\n"
+ " - create pci slave window (access: pci->vme)\n"
+ "tsi148 crg [vme_addr] [vam]\n"
+ " - create vme slave window: (access vme->CRG\n"
+ "tsi148 crcsr [pci_addr]\n"
+ " - create vme slave window: (access vme->CR/CSR\n"
+ "tsi148 gcsr [vme_addr] [vam]\n"
+ " - create vme slave window: (access vme->GCSR\n"
+ " [vam] = VMEbus Address-Modifier: 01 -> A16 Address Space\n"
+ " 02 -> A24 Address Space\n"
+ " 03 -> A32 Address Space\n"
+ " 04 -> Usr AM Code\n"
+ " 08 -> Supervisor AM Code\n"
+ " 10 -> Data AM Code\n"
+ " 20 -> Program AM Code\n"
+ " [vdw] = VMEbus Maximum Datawidth: 02 -> D16 Data Width\n"
+ " 03 -> D32 Data Width\n"
+);
diff --git a/u-boot/common/cmd_ubi.c b/u-boot/common/cmd_ubi.c
new file mode 100644
index 0000000..b486ca8
--- /dev/null
+++ b/u-boot/common/cmd_ubi.c
@@ -0,0 +1,636 @@
+/*
+ * Unsorted Block Image commands
+ *
+ * Copyright (C) 2008 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Copyright 2008-2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <exports.h>
+
+#include <nand.h>
+#include <onenand_uboot.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <ubi_uboot.h>
+#include <asm/errno.h>
+#include <jffs2/load_kernel.h>
+
+#define DEV_TYPE_NONE 0
+#define DEV_TYPE_NAND 1
+#define DEV_TYPE_ONENAND 2
+#define DEV_TYPE_NOR 3
+
+/* Private own data */
+static struct ubi_device *ubi;
+static char buffer[80];
+static int ubi_initialized;
+
+struct selected_dev {
+ char part_name[80];
+ int selected;
+ int nr;
+ struct mtd_info *mtd_info;
+};
+
+static struct selected_dev ubi_dev;
+
+#ifdef CONFIG_CMD_UBIFS
+int ubifs_is_mounted(void);
+void cmd_ubifs_umount(void);
+#endif
+
+static void ubi_dump_vol_info(const struct ubi_volume *vol)
+{
+ ubi_msg("volume information dump:");
+ ubi_msg("vol_id %d", vol->vol_id);
+ ubi_msg("reserved_pebs %d", vol->reserved_pebs);
+ ubi_msg("alignment %d", vol->alignment);
+ ubi_msg("data_pad %d", vol->data_pad);
+ ubi_msg("vol_type %d", vol->vol_type);
+ ubi_msg("name_len %d", vol->name_len);
+ ubi_msg("usable_leb_size %d", vol->usable_leb_size);
+ ubi_msg("used_ebs %d", vol->used_ebs);
+ ubi_msg("used_bytes %lld", vol->used_bytes);
+ ubi_msg("last_eb_bytes %d", vol->last_eb_bytes);
+ ubi_msg("corrupted %d", vol->corrupted);
+ ubi_msg("upd_marker %d", vol->upd_marker);
+
+ if (vol->name_len <= UBI_VOL_NAME_MAX &&
+ strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
+ ubi_msg("name %s", vol->name);
+ } else {
+ ubi_msg("the 1st 5 characters of the name: %c%c%c%c%c",
+ vol->name[0], vol->name[1], vol->name[2],
+ vol->name[3], vol->name[4]);
+ }
+ printf("\n");
+}
+
+static void display_volume_info(struct ubi_device *ubi)
+{
+ int i;
+
+ for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
+ if (!ubi->volumes[i])
+ continue; /* Empty record */
+ ubi_dump_vol_info(ubi->volumes[i]);
+ }
+}
+
+static void display_ubi_info(struct ubi_device *ubi)
+{
+ ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
+ ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
+ ubi->peb_size, ubi->peb_size >> 10);
+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
+ ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
+ ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
+ ubi_msg("VID header offset: %d (aligned %d)",
+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+ ubi_msg("data offset: %d", ubi->leb_start);
+ ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
+ ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
+ ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
+ ubi_msg("number of user volumes: %d",
+ ubi->vol_count - UBI_INT_VOL_COUNT);
+ ubi_msg("available PEBs: %d", ubi->avail_pebs);
+ ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
+ ubi_msg("number of PEBs reserved for bad PEB handling: %d",
+ ubi->beb_rsvd_pebs);
+ ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+}
+
+static int ubi_info(int layout)
+{
+ if (layout)
+ display_volume_info(ubi);
+ else
+ display_ubi_info(ubi);
+
+ return 0;
+}
+
+static int verify_mkvol_req(const struct ubi_device *ubi,
+ const struct ubi_mkvol_req *req)
+{
+ int n, err = -EINVAL;
+
+ if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
+ req->name_len < 0)
+ goto bad;
+
+ if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
+ req->vol_id != UBI_VOL_NUM_AUTO)
+ goto bad;
+
+ if (req->alignment == 0)
+ goto bad;
+
+ if (req->bytes == 0)
+ goto bad;
+
+ if (req->vol_type != UBI_DYNAMIC_VOLUME &&
+ req->vol_type != UBI_STATIC_VOLUME)
+ goto bad;
+
+ if (req->alignment > ubi->leb_size)
+ goto bad;
+
+ n = req->alignment % ubi->min_io_size;
+ if (req->alignment != 1 && n)
+ goto bad;
+
+ if (req->name_len > UBI_VOL_NAME_MAX) {
+ err = -ENAMETOOLONG;
+ goto bad;
+ }
+
+ return 0;
+bad:
+ printf("bad volume creation request");
+ return err;
+}
+
+static int ubi_create_vol(char *volume, int size, int dynamic)
+{
+ struct ubi_mkvol_req req;
+ int err;
+
+ if (dynamic)
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ else
+ req.vol_type = UBI_STATIC_VOLUME;
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = size;
+
+ strcpy(req.name, volume);
+ req.name_len = strlen(volume);
+ req.name[req.name_len] = '\0';
+ req.padding1 = 0;
+ /* It's duplicated at drivers/mtd/ubi/cdev.c */
+ err = verify_mkvol_req(ubi, &req);
+ if (err) {
+ printf("verify_mkvol_req failed %d\n", err);
+ return err;
+ }
+ printf("Creating %s volume %s of size %d\n",
+ dynamic ? "dynamic" : "static", volume, size);
+ /* Call real ubi create volume */
+ return ubi_create_volume(ubi, &req);
+}
+
+static int ubi_remove_vol(char *volume)
+{
+ int i, err, reserved_pebs;
+ int found = 0, vol_id = 0;
+ struct ubi_volume *vol = NULL;
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ vol = ubi->volumes[i];
+ if (vol && !strcmp(vol->name, volume)) {
+ printf("Volume %s found at valid %d\n", volume, i);
+ vol_id = i;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printf("%s volume not found\n", volume);
+ return -ENODEV;
+ }
+ printf("remove UBI volume %s (id %d)\n", vol->name, vol->vol_id);
+
+ if (ubi->ro_mode) {
+ printf("It's read-only mode\n");
+ err = -EROFS;
+ goto out_err;
+ }
+
+ err = ubi_change_vtbl_record(ubi, vol_id, NULL);
+ if (err) {
+ printf("Error changing Vol tabel record err=%x\n", err);
+ goto out_err;
+ }
+ reserved_pebs = vol->reserved_pebs;
+ for (i = 0; i < vol->reserved_pebs; i++) {
+ err = ubi_eba_unmap_leb(ubi, vol, i);
+ if (err)
+ goto out_err;
+ }
+
+ kfree(vol->eba_tbl);
+ ubi->volumes[vol_id]->eba_tbl = NULL;
+ ubi->volumes[vol_id] = NULL;
+
+ ubi->rsvd_pebs -= reserved_pebs;
+ ubi->avail_pebs += reserved_pebs;
+ i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+ if (i > 0) {
+ i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
+ ubi->avail_pebs -= i;
+ ubi->rsvd_pebs += i;
+ ubi->beb_rsvd_pebs += i;
+ if (i > 0)
+ ubi_msg("reserve more %d PEBs", i);
+ }
+ ubi->vol_count -= 1;
+
+ return 0;
+out_err:
+ ubi_err("cannot remove volume %d, error %d", vol_id, err);
+ return err;
+}
+
+static int ubi_volume_write(char *volume, void *buf, size_t size)
+{
+ int i = 0, err = -1;
+ int rsvd_bytes = 0;
+ int found = 0;
+ struct ubi_volume *vol;
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ vol = ubi->volumes[i];
+ if (vol && !strcmp(vol->name, volume)) {
+ printf("Volume \"%s\" found at volume id %d\n", volume, i);
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printf("%s volume not found\n", volume);
+ return 1;
+ }
+ rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
+ if (size < 0 || size > rsvd_bytes) {
+ printf("rsvd_bytes=%d vol->reserved_pebs=%d ubi->leb_size=%d\n",
+ rsvd_bytes, vol->reserved_pebs, ubi->leb_size);
+ printf("vol->data_pad=%d\n", vol->data_pad);
+ printf("Size > volume size !!\n");
+ return 1;
+ }
+
+ err = ubi_start_update(ubi, vol, size);
+ if (err < 0) {
+ printf("Cannot start volume update\n");
+ return err;
+ }
+
+ err = ubi_more_update_data(ubi, vol, buf, size);
+ if (err < 0) {
+ printf("Couldnt or partially wrote data \n");
+ return err;
+ }
+
+ if (err) {
+ size = err;
+
+ err = ubi_check_volume(ubi, vol->vol_id);
+ if ( err < 0 )
+ return err;
+
+ if (err) {
+ ubi_warn("volume %d on UBI device %d is corrupted",
+ vol->vol_id, ubi->ubi_num);
+ vol->corrupted = 1;
+ }
+
+ vol->checked = 1;
+ ubi_gluebi_updated(vol);
+ }
+
+ return 0;
+}
+
+static int ubi_volume_read(char *volume, char *buf, size_t size)
+{
+ int err, lnum, off, len, tbuf_size, i = 0;
+ size_t count_save = size;
+ void *tbuf;
+ unsigned long long tmp;
+ struct ubi_volume *vol = NULL;
+ loff_t offp = 0;
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ vol = ubi->volumes[i];
+ if (vol && !strcmp(vol->name, volume)) {
+ printf("Volume %s found at volume id %d\n",
+ volume, vol->vol_id);
+ break;
+ }
+ }
+ if (i == ubi->vtbl_slots) {
+ printf("%s volume not found\n", volume);
+ return -ENODEV;
+ }
+
+ printf("read %i bytes from volume %d to %x(buf address)\n",
+ (int) size, vol->vol_id, (unsigned)buf);
+
+ if (vol->updating) {
+ printf("updating");
+ return -EBUSY;
+ }
+ if (vol->upd_marker) {
+ printf("damaged volume, update marker is set");
+ return -EBADF;
+ }
+ if (offp == vol->used_bytes)
+ return 0;
+
+ if (size == 0) {
+ printf("Read [%lu] bytes\n", (unsigned long) vol->used_bytes);
+ size = vol->used_bytes;
+ }
+
+ if (vol->corrupted)
+ printf("read from corrupted volume %d", vol->vol_id);
+ if (offp + size > vol->used_bytes)
+ count_save = size = vol->used_bytes - offp;
+
+ tbuf_size = vol->usable_leb_size;
+ if (size < tbuf_size)
+ tbuf_size = ALIGN(size, ubi->min_io_size);
+ tbuf = malloc(tbuf_size);
+ if (!tbuf) {
+ printf("NO MEM\n");
+ return -ENOMEM;
+ }
+ len = size > tbuf_size ? tbuf_size : size;
+
+ tmp = offp;
+ off = do_div(tmp, vol->usable_leb_size);
+ lnum = tmp;
+ do {
+ if (off + len >= vol->usable_leb_size)
+ len = vol->usable_leb_size - off;
+
+ err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
+ if (err) {
+ printf("read err %x\n", err);
+ break;
+ }
+ off += len;
+ if (off == vol->usable_leb_size) {
+ lnum += 1;
+ off -= vol->usable_leb_size;
+ }
+
+ size -= len;
+ offp += len;
+
+ memcpy(buf, tbuf, len);
+
+ buf += len;
+ len = size > tbuf_size ? tbuf_size : size;
+ } while (size);
+
+ free(tbuf);
+ return err ? err : count_save - size;
+}
+
+static int ubi_dev_scan(struct mtd_info *info, char *ubidev,
+ const char *vid_header_offset)
+{
+ struct mtd_device *dev;
+ struct part_info *part;
+ struct mtd_partition mtd_part;
+ char ubi_mtd_param_buffer[80];
+ u8 pnum;
+ int err;
+
+ if (find_dev_and_part(ubidev, &dev, &pnum, &part) != 0)
+ return 1;
+
+ sprintf(buffer, "mtd=%d", pnum);
+ memset(&mtd_part, 0, sizeof(mtd_part));
+ mtd_part.name = buffer;
+ mtd_part.size = part->size;
+ mtd_part.offset = part->offset;
+ add_mtd_partitions(info, &mtd_part, 1);
+
+ strcpy(ubi_mtd_param_buffer, buffer);
+ if (vid_header_offset)
+ sprintf(ubi_mtd_param_buffer, "mtd=%d,%s", pnum,
+ vid_header_offset);
+ err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
+ if (err) {
+ del_mtd_partitions(info);
+ return err;
+ }
+
+ err = ubi_init();
+ if (err) {
+ del_mtd_partitions(info);
+ return err;
+ }
+
+ ubi_initialized = 1;
+
+ return 0;
+}
+
+static int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ size_t size = 0;
+ ulong addr = 0;
+ int err = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if (mtdparts_init() != 0) {
+ printf("Error initializing mtdparts!\n");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "part") == 0) {
+ char mtd_dev[16];
+ struct mtd_device *dev;
+ struct part_info *part;
+ const char *vid_header_offset = NULL;
+ u8 pnum;
+
+ /* Print current partition */
+ if (argc == 2) {
+ if (!ubi_dev.selected) {
+ printf("Error, no UBI device/partition selected!\n");
+ return 1;
+ }
+
+ printf("Device %d: %s, partition %s\n",
+ ubi_dev.nr, ubi_dev.mtd_info->name, ubi_dev.part_name);
+ return 0;
+ }
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+#ifdef CONFIG_CMD_UBIFS
+ /*
+ * Automatically unmount UBIFS partition when user
+ * changes the UBI device. Otherwise the following
+ * UBIFS commands will crash.
+ */
+ if (ubifs_is_mounted())
+ cmd_ubifs_umount();
+#endif
+
+ /* todo: get dev number for NAND... */
+ ubi_dev.nr = 0;
+
+ /*
+ * Call ubi_exit() before re-initializing the UBI subsystem
+ */
+ if (ubi_initialized) {
+ ubi_exit();
+ del_mtd_partitions(ubi_dev.mtd_info);
+ }
+
+ /*
+ * Search the mtd device number where this partition
+ * is located
+ */
+ if (find_dev_and_part(argv[2], &dev, &pnum, &part)) {
+ printf("Partition %s not found!\n", argv[2]);
+ return 1;
+ }
+ sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);
+ ubi_dev.mtd_info = get_mtd_device_nm(mtd_dev);
+ if (IS_ERR(ubi_dev.mtd_info)) {
+ printf("Partition %s not found on device %s!\n", argv[2], mtd_dev);
+ return 1;
+ }
+
+ ubi_dev.selected = 1;
+
+ if (argc > 3)
+ vid_header_offset = argv[3];
+ strcpy(ubi_dev.part_name, argv[2]);
+ err = ubi_dev_scan(ubi_dev.mtd_info, ubi_dev.part_name,
+ vid_header_offset);
+ if (err) {
+ printf("UBI init error %d\n", err);
+ ubi_dev.selected = 0;
+ return err;
+ }
+
+ ubi = ubi_devices[0];
+
+ return 0;
+ }
+
+ if ((strcmp(argv[1], "part") != 0) && (!ubi_dev.selected)) {
+ printf("Error, no UBI device/partition selected!\n");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "info") == 0) {
+ int layout = 0;
+ if (argc > 2 && !strncmp(argv[2], "l", 1))
+ layout = 1;
+ return ubi_info(layout);
+ }
+
+ if (strncmp(argv[1], "create", 6) == 0) {
+ int dynamic = 1; /* default: dynamic volume */
+
+ /* Use maximum available size */
+ size = 0;
+
+ /* E.g., create volume size type */
+ if (argc == 5) {
+ if (strncmp(argv[4], "s", 1) == 0)
+ dynamic = 0;
+ else if (strncmp(argv[4], "d", 1) != 0) {
+ printf("Incorrect type\n");
+ return 1;
+ }
+ argc--;
+ }
+ /* E.g., create volume size */
+ if (argc == 4) {
+ size = simple_strtoul(argv[3], NULL, 16);
+ argc--;
+ }
+ /* Use maximum available size */
+ if (!size)
+ size = ubi->avail_pebs * ubi->leb_size;
+ /* E.g., create volume */
+ if (argc == 3)
+ return ubi_create_vol(argv[2], size, dynamic);
+ }
+
+ if (strncmp(argv[1], "remove", 6) == 0) {
+ /* E.g., remove volume */
+ if (argc == 3)
+ return ubi_remove_vol(argv[2]);
+ }
+
+ if (strncmp(argv[1], "write", 5) == 0) {
+ if (argc < 5) {
+ printf("Please see usage\n");
+ return 1;
+ }
+
+ addr = simple_strtoul(argv[2], NULL, 16);
+ size = simple_strtoul(argv[4], NULL, 16);
+
+ return ubi_volume_write(argv[3], (void *)addr, size);
+ }
+
+ if (strncmp(argv[1], "read", 4) == 0) {
+ size = 0;
+
+ /* E.g., read volume size */
+ if (argc == 5) {
+ size = simple_strtoul(argv[4], NULL, 16);
+ argc--;
+ }
+
+ /* E.g., read volume */
+ if (argc == 4) {
+ addr = simple_strtoul(argv[2], NULL, 16);
+ argc--;
+ }
+
+ if (argc == 3)
+ return ubi_volume_read(argv[3], (char *)addr, size);
+ }
+
+ printf("Please see usage\n");
+ return -1;
+}
+
+U_BOOT_CMD(
+ ubi, 6, 1, do_ubi,
+ "ubi commands",
+ "part [part] [offset]\n"
+ " - Show or set current partition (with optional VID"
+ " header offset)\n"
+ "ubi info [l[ayout]]"
+ " - Display volume and ubi layout information\n"
+ "ubi create[vol] volume [size] [type]"
+ " - create volume name with size\n"
+ "ubi write[vol] address volume size"
+ " - Write volume from address with size\n"
+ "ubi read[vol] address volume [size]"
+ " - Read volume to address with size\n"
+ "ubi remove[vol] volume"
+ " - Remove volume\n"
+ "[Legends]\n"
+ " volume: character name\n"
+ " size: specified in bytes\n"
+ " type: s[tatic] or d[ynamic] (default=dynamic)"
+);
diff --git a/u-boot/common/cmd_ubifs.c b/u-boot/common/cmd_ubifs.c
new file mode 100644
index 0000000..3cd2d8f
--- /dev/null
+++ b/u-boot/common/cmd_ubifs.c
@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * 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
+ *
+ */
+
+
+/*
+ * UBIFS command support
+ */
+
+#undef DEBUG
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+#include "../fs/ubifs/ubifs.h"
+
+static int ubifs_initialized;
+static int ubifs_mounted;
+
+extern struct super_block *ubifs_sb;
+
+/* Prototypes */
+int ubifs_init(void);
+int ubifs_mount(char *vol_name);
+void ubifs_umount(struct ubifs_info *c);
+int ubifs_ls(char *dir_name);
+int ubifs_load(char *filename, u32 addr, u32 size);
+
+int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *vol_name;
+ int ret;
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+ vol_name = argv[1];
+ debug("Using volume %s\n", vol_name);
+
+ if (ubifs_initialized == 0) {
+ ubifs_init();
+ ubifs_initialized = 1;
+ }
+
+ ret = ubifs_mount(vol_name);
+ if (ret)
+ return -1;
+
+ ubifs_mounted = 1;
+
+ return 0;
+}
+
+int ubifs_is_mounted(void)
+{
+ return ubifs_mounted;
+}
+
+void cmd_ubifs_umount(void)
+{
+
+ if (ubifs_sb) {
+ printf("Unmounting UBIFS volume %s!\n",
+ ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
+ ubifs_umount(ubifs_sb->s_fs_info);
+ }
+
+ ubifs_sb = NULL;
+ ubifs_mounted = 0;
+ ubifs_initialized = 0;
+}
+
+int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc != 1)
+ return cmd_usage(cmdtp);
+
+ if (ubifs_initialized == 0) {
+ printf("No UBIFS volume mounted!\n");
+ return -1;
+ }
+
+ cmd_ubifs_umount();
+
+ return 0;
+}
+
+int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = "/";
+ int ret;
+
+ if (!ubifs_mounted) {
+ printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
+ return -1;
+ }
+
+ if (argc == 2)
+ filename = argv[1];
+ debug("Using filename %s\n", filename);
+
+ ret = ubifs_ls(filename);
+ if (ret)
+ printf("%s not found!\n", filename);
+
+ return ret;
+}
+
+int do_ubifs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename;
+ char *endp;
+ int ret;
+ u32 addr;
+ u32 size = 0;
+
+ if (!ubifs_mounted) {
+ printf("UBIFS not mounted, use ubifs mount to mount volume first!\n");
+ return -1;
+ }
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ addr = simple_strtoul(argv[1], &endp, 16);
+ if (endp == argv[1])
+ return cmd_usage(cmdtp);
+
+ filename = argv[2];
+
+ if (argc == 4) {
+ size = simple_strtoul(argv[3], &endp, 16);
+ if (endp == argv[3])
+ return cmd_usage(cmdtp);
+ }
+ debug("Loading file '%s' to address 0x%08x (size %d)\n", filename, addr, size);
+
+ ret = ubifs_load(filename, addr, size);
+ if (ret)
+ printf("%s not found!\n", filename);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ ubifsmount, 2, 0, do_ubifs_mount,
+ "mount UBIFS volume",
+ "<volume-name>\n"
+ " - mount 'volume-name' volume"
+);
+
+U_BOOT_CMD(
+ ubifsumount, 1, 0, do_ubifs_umount,
+ "unmount UBIFS volume",
+ " - unmount current volume"
+);
+
+U_BOOT_CMD(
+ ubifsls, 2, 0, do_ubifs_ls,
+ "list files in a directory",
+ "[directory]\n"
+ " - list files in a 'directory' (default '/')"
+);
+
+U_BOOT_CMD(
+ ubifsload, 4, 0, do_ubifs_load,
+ "load file from an UBIFS filesystem",
+ "<addr> <filename> [bytes]\n"
+ " - load file 'filename' to address 'addr'"
+);
diff --git a/u-boot/common/cmd_universe.c b/u-boot/common/cmd_universe.c
new file mode 100644
index 0000000..a86a574
--- /dev/null
+++ b/u-boot/common/cmd_universe.c
@@ -0,0 +1,386 @@
+/*
+ * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#include <universe.h>
+
+#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
+#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_CA91C042
+
+
+typedef struct _UNI_DEV UNI_DEV;
+
+struct _UNI_DEV {
+ int bus;
+ pci_dev_t busdevfn;
+ UNIVERSE *uregs;
+ unsigned int pci_bs;
+};
+
+static UNI_DEV *dev;
+
+
+int universe_init(void)
+{
+ int j, result, lastError = 0;
+ pci_dev_t busdevfn;
+ unsigned int val;
+
+ busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
+ if (busdevfn == -1) {
+ puts("No Tundra Universe found!\n");
+ return -1;
+ }
+
+ /* Lets turn Latency off */
+ pci_write_config_dword(busdevfn, 0x0c, 0);
+
+ dev = malloc(sizeof(*dev));
+ if (NULL == dev) {
+ puts("UNIVERSE: No memory!\n");
+ result = -1;
+ goto break_20;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ dev->busdevfn = busdevfn;
+
+ pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_1, &val);
+ if (val & 1) {
+ pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val);
+ }
+ val &= ~0xf;
+ dev->uregs = (UNIVERSE *)val;
+
+ debug ("UNIVERSE-Base : %p\n", dev->uregs);
+
+ /* check mapping */
+ debug (" Read via mapping, PCI_ID = %08X\n", readl(&dev->uregs->pci_id));
+ if (((PCI_DEVICE <<16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
+ printf ("UNIVERSE: Cannot read PCI-ID via Mapping: %08x\n",
+ readl(&dev->uregs->pci_id));
+ result = -1;
+ goto break_30;
+ }
+
+ debug ("PCI_BS = %08X\n", readl(&dev->uregs->pci_bs));
+
+ dev->pci_bs = readl(&dev->uregs->pci_bs);
+
+ /* turn off windows */
+ for (j=0; j <4; j ++) {
+ writel(0x00800000, &dev->uregs->lsi[j].ctl);
+ writel(0x00800000, &dev->uregs->vsi[j].ctl);
+ }
+
+ /*
+ * Write to Misc Register
+ * Set VME Bus Time-out
+ * Arbitration Mode
+ * DTACK Enable
+ */
+ writel(0x15040000 | (readl(&dev->uregs->misc_ctl) & 0x00020000), &dev->uregs->misc_ctl);
+
+ if (readl(&dev->uregs->misc_ctl) & 0x00020000) {
+ debug ("System Controller!\n"); /* test-only */
+ } else {
+ debug ("Not System Controller!\n"); /* test-only */
+ }
+
+ /*
+ * Lets turn off interrupts
+ */
+ writel(0x00000000,&dev->uregs->lint_en); /* Disable interrupts in the Universe first */
+ writel(0x0000FFFF,&dev->uregs->lint_stat); /* Clear Any Pending Interrupts */
+ eieio();
+ writel(0x0000, &dev->uregs->lint_map0); /* Map all ints to 0 */
+ writel(0x0000, &dev->uregs->lint_map1); /* Map all ints to 0 */
+ eieio();
+
+ return 0;
+
+ break_30:
+ free(dev);
+ break_20:
+ lastError = result;
+
+ return result;
+}
+
+
+/*
+ * Create pci slave window (access: pci -> vme)
+ */
+int universe_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr, int size, int vam, int pms, int vdw)
+{
+ int result, i;
+ unsigned int ctl = 0;
+
+ if (NULL == dev) {
+ result = -1;
+ goto exit_10;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (0x00800000 == readl(&dev->uregs->lsi[i].ctl))
+ break;
+ }
+
+ if (i == 4) {
+ printf ("universe: No Image available\n");
+ result = -1;
+ goto exit_10;
+ }
+
+ debug ("universe: Using image %d\n", i);
+
+ writel(pciAddr , &dev->uregs->lsi[i].bs);
+ writel((pciAddr + size), &dev->uregs->lsi[i].bd);
+ writel((vmeAddr - pciAddr), &dev->uregs->lsi[i].to);
+
+ switch (vam & VME_AM_Axx) {
+ case VME_AM_A16:
+ ctl = 0x00000000;
+ break;
+ case VME_AM_A24:
+ ctl = 0x00010000;
+ break;
+ case VME_AM_A32:
+ ctl = 0x00020000;
+ break;
+ }
+
+ switch (vam & VME_AM_Mxx) {
+ case VME_AM_DATA:
+ ctl |= 0x00000000;
+ break;
+ case VME_AM_PROG:
+ ctl |= 0x00008000;
+ break;
+ }
+
+ if (vam & VME_AM_SUP) {
+ ctl |= 0x00001000;
+
+ }
+
+ switch (vdw & VME_FLAG_Dxx) {
+ case VME_FLAG_D8:
+ ctl |= 0x00000000;
+ break;
+ case VME_FLAG_D16:
+ ctl |= 0x00400000;
+ break;
+ case VME_FLAG_D32:
+ ctl |= 0x00800000;
+ break;
+ }
+
+ switch (pms & PCI_MS_Mxx) {
+ case PCI_MS_MEM:
+ ctl |= 0x00000000;
+ break;
+ case PCI_MS_IO:
+ ctl |= 0x00000001;
+ break;
+ case PCI_MS_CONFIG:
+ ctl |= 0x00000002;
+ break;
+ }
+
+ ctl |= 0x80000000; /* enable */
+
+ writel(ctl, &dev->uregs->lsi[i].ctl);
+
+ debug ("universe: window-addr=%p\n", &dev->uregs->lsi[i].ctl);
+ debug ("universe: pci slave window[%d] ctl=%08x\n", i, readl(&dev->uregs->lsi[i].ctl));
+ debug ("universe: pci slave window[%d] bs=%08x\n", i, readl(&dev->uregs->lsi[i].bs));
+ debug ("universe: pci slave window[%d] bd=%08x\n", i, readl(&dev->uregs->lsi[i].bd));
+ debug ("universe: pci slave window[%d] to=%08x\n", i, readl(&dev->uregs->lsi[i].to));
+
+ return 0;
+
+ exit_10:
+ return -result;
+}
+
+
+/*
+ * Create vme slave window (access: vme -> pci)
+ */
+int universe_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr, int size, int vam, int pms)
+{
+ int result, i;
+ unsigned int ctl = 0;
+
+ if (NULL == dev) {
+ result = -1;
+ goto exit_10;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (0x00800000 == readl(&dev->uregs->vsi[i].ctl))
+ break;
+ }
+
+ if (i == 4) {
+ printf ("universe: No Image available\n");
+ result = -1;
+ goto exit_10;
+ }
+
+ debug ("universe: Using image %d\n", i);
+
+ writel(vmeAddr , &dev->uregs->vsi[i].bs);
+ writel((vmeAddr + size), &dev->uregs->vsi[i].bd);
+ writel((pciAddr - vmeAddr), &dev->uregs->vsi[i].to);
+
+ switch (vam & VME_AM_Axx) {
+ case VME_AM_A16:
+ ctl = 0x00000000;
+ break;
+ case VME_AM_A24:
+ ctl = 0x00010000;
+ break;
+ case VME_AM_A32:
+ ctl = 0x00020000;
+ break;
+ }
+
+ switch (vam & VME_AM_Mxx) {
+ case VME_AM_DATA:
+ ctl |= 0x00000000;
+ break;
+ case VME_AM_PROG:
+ ctl |= 0x00800000;
+ break;
+ }
+
+ if (vam & VME_AM_SUP) {
+ ctl |= 0x00100000;
+
+ }
+
+ switch (pms & PCI_MS_Mxx) {
+ case PCI_MS_MEM:
+ ctl |= 0x00000000;
+ break;
+ case PCI_MS_IO:
+ ctl |= 0x00000001;
+ break;
+ case PCI_MS_CONFIG:
+ ctl |= 0x00000002;
+ break;
+ }
+
+ ctl |= 0x80f00000; /* enable */
+
+ writel(ctl, &dev->uregs->vsi[i].ctl);
+
+ debug ("universe: window-addr=%p\n", &dev->uregs->vsi[i].ctl);
+ debug ("universe: vme slave window[%d] ctl=%08x\n", i, readl(&dev->uregs->vsi[i].ctl));
+ debug ("universe: vme slave window[%d] bs=%08x\n", i, readl(&dev->uregs->vsi[i].bs));
+ debug ("universe: vme slave window[%d] bd=%08x\n", i, readl(&dev->uregs->vsi[i].bd));
+ debug ("universe: vme slave window[%d] to=%08x\n", i, readl(&dev->uregs->vsi[i].to));
+
+ return 0;
+
+ exit_10:
+ return -result;
+}
+
+
+/*
+ * Tundra Universe configuration
+ */
+int do_universe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, pms = 0, vdw = 0;
+ char cmd = 'x';
+
+ /* get parameter */
+ if (argc > 1)
+ cmd = argv[1][0];
+ if (argc > 2)
+ addr1 = simple_strtoul(argv[2], NULL, 16);
+ if (argc > 3)
+ addr2 = simple_strtoul(argv[3], NULL, 16);
+ if (argc > 4)
+ size = simple_strtoul(argv[4], NULL, 16);
+ if (argc > 5)
+ vam = simple_strtoul(argv[5], NULL, 16);
+ if (argc > 6)
+ pms = simple_strtoul(argv[6], NULL, 16);
+ if (argc > 7)
+ vdw = simple_strtoul(argv[7], NULL, 16);
+
+ switch (cmd) {
+ case 'i': /* init */
+ universe_init();
+ break;
+ case 'v': /* vme */
+ printf("Configuring Universe VME Slave Window (VME->PCI):\n");
+ printf(" vme=%08lx pci=%08lx size=%08lx vam=%02lx pms=%02lx\n",
+ addr1, addr2, size, vam, pms);
+ universe_vme_slave_window(addr1, addr2, size, vam, pms);
+ break;
+ case 'p': /* pci */
+ printf("Configuring Universe PCI Slave Window (PCI->VME):\n");
+ printf(" pci=%08lx vme=%08lx size=%08lx vam=%02lx pms=%02lx vdw=%02lx\n",
+ addr1, addr2, size, vam, pms, vdw);
+ universe_pci_slave_window(addr1, addr2, size, vam, pms, vdw);
+ break;
+ default:
+ printf("Universe command %s not supported!\n", argv[1]);
+ }
+
+ return 0;
+}
+
+
+U_BOOT_CMD(
+ universe, 8, 1, do_universe,
+ "initialize and configure Turndra Universe",
+ "init\n"
+ " - initialize universe\n"
+ "universe vme [vme_addr] [pci_addr] [size] [vam] [pms]\n"
+ " - create vme slave window (access: vme->pci)\n"
+ "universe pci [pci_addr] [vme_addr] [size] [vam] [pms] [vdw]\n"
+ " - create pci slave window (access: pci->vme)\n"
+ " [vam] = VMEbus Address-Modifier: 01 -> A16 Address Space\n"
+ " 02 -> A24 Address Space\n"
+ " 03 -> A32 Address Space\n"
+ " 04 -> Supervisor AM Code\n"
+ " 10 -> Data AM Code\n"
+ " 20 -> Program AM Code\n"
+ " [pms] = PCI Memory Space: 01 -> Memory Space\n"
+ " 02 -> I/O Space\n"
+ " 03 -> Configuration Space\n"
+ " [vdw] = VMEbus Maximum Datawidth: 01 -> D8 Data Width\n"
+ " 02 -> D16 Data Width\n"
+ " 03 -> D32 Data Width"
+);
diff --git a/u-boot/common/cmd_usb.c b/u-boot/common/cmd_usb.c
new file mode 100644
index 0000000..b5731a7
--- /dev/null
+++ b/u-boot/common/cmd_usb.c
@@ -0,0 +1,742 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Most of this source has been derived from the Linux USB
+ * project.
+ *
+ * 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 <asm/byteorder.h>
+#include <part.h>
+#include <usb.h>
+
+#ifdef CONFIG_USB_STORAGE
+static int usb_stor_curr_dev = -1; /* current device */
+#endif
+#ifdef CONFIG_USB_HOST_ETHER
+static int usb_ether_curr_dev = -1; /* current ethernet device */
+#endif
+
+/* some display routines (info command) */
+char *usb_get_class_desc(unsigned char dclass)
+{
+ switch (dclass) {
+ case USB_CLASS_PER_INTERFACE:
+ return "See Interface";
+ case USB_CLASS_AUDIO:
+ return "Audio";
+ case USB_CLASS_COMM:
+ return "Communication";
+ case USB_CLASS_HID:
+ return "Human Interface";
+ case USB_CLASS_PRINTER:
+ return "Printer";
+ case USB_CLASS_MASS_STORAGE:
+ return "Mass Storage";
+ case USB_CLASS_HUB:
+ return "Hub";
+ case USB_CLASS_DATA:
+ return "CDC Data";
+ case USB_CLASS_VENDOR_SPEC:
+ return "Vendor specific";
+ default:
+ return "";
+ }
+}
+
+void usb_display_class_sub(unsigned char dclass, unsigned char subclass,
+ unsigned char proto)
+{
+ switch (dclass) {
+ case USB_CLASS_PER_INTERFACE:
+ printf("See Interface");
+ break;
+ case USB_CLASS_HID:
+ printf("Human Interface, Subclass: ");
+ switch (subclass) {
+ case USB_SUB_HID_NONE:
+ printf("None");
+ break;
+ case USB_SUB_HID_BOOT:
+ printf("Boot ");
+ switch (proto) {
+ case USB_PROT_HID_NONE:
+ printf("None");
+ break;
+ case USB_PROT_HID_KEYBOARD:
+ printf("Keyboard");
+ break;
+ case USB_PROT_HID_MOUSE:
+ printf("Mouse");
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+ break;
+ case USB_CLASS_MASS_STORAGE:
+ printf("Mass Storage, ");
+ switch (subclass) {
+ case US_SC_RBC:
+ printf("RBC ");
+ break;
+ case US_SC_8020:
+ printf("SFF-8020i (ATAPI)");
+ break;
+ case US_SC_QIC:
+ printf("QIC-157 (Tape)");
+ break;
+ case US_SC_UFI:
+ printf("UFI");
+ break;
+ case US_SC_8070:
+ printf("SFF-8070");
+ break;
+ case US_SC_SCSI:
+ printf("Transp. SCSI");
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+ printf(", ");
+ switch (proto) {
+ case US_PR_CB:
+ printf("Command/Bulk");
+ break;
+ case US_PR_CBI:
+ printf("Command/Bulk/Int");
+ break;
+ case US_PR_BULK:
+ printf("Bulk only");
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+ break;
+ default:
+ printf("%s", usb_get_class_desc(dclass));
+ break;
+ }
+}
+
+void usb_display_string(struct usb_device *dev, int index)
+{
+ char buffer[256];
+ if (index != 0) {
+ if (usb_string(dev, index, &buffer[0], 256) > 0)
+ printf("String: \"%s\"", buffer);
+ }
+}
+
+void usb_display_desc(struct usb_device *dev)
+{
+ if (dev->descriptor.bDescriptorType == USB_DT_DEVICE) {
+ printf("%d: %s, USB Revision %x.%x\n", dev->devnum,
+ usb_get_class_desc(dev->config.if_desc[0].desc.bInterfaceClass),
+ (dev->descriptor.bcdUSB>>8) & 0xff,
+ dev->descriptor.bcdUSB & 0xff);
+
+ if (strlen(dev->mf) || strlen(dev->prod) ||
+ strlen(dev->serial))
+ printf(" - %s %s %s\n", dev->mf, dev->prod,
+ dev->serial);
+ if (dev->descriptor.bDeviceClass) {
+ printf(" - Class: ");
+ usb_display_class_sub(dev->descriptor.bDeviceClass,
+ dev->descriptor.bDeviceSubClass,
+ dev->descriptor.bDeviceProtocol);
+ printf("\n");
+ } else {
+ printf(" - Class: (from Interface) %s\n",
+ usb_get_class_desc(
+ dev->config.if_desc[0].desc.bInterfaceClass));
+ }
+ printf(" - PacketSize: %d Configurations: %d\n",
+ dev->descriptor.bMaxPacketSize0,
+ dev->descriptor.bNumConfigurations);
+ printf(" - Vendor: 0x%04x Product 0x%04x Version %d.%d\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct,
+ (dev->descriptor.bcdDevice>>8) & 0xff,
+ dev->descriptor.bcdDevice & 0xff);
+ }
+
+}
+
+void usb_display_conf_desc(struct usb_configuration_descriptor *config,
+ struct usb_device *dev)
+{
+ printf(" Configuration: %d\n", config->bConfigurationValue);
+ printf(" - Interfaces: %d %s%s%dmA\n", config->bNumInterfaces,
+ (config->bmAttributes & 0x40) ? "Self Powered " : "Bus Powered ",
+ (config->bmAttributes & 0x20) ? "Remote Wakeup " : "",
+ config->bMaxPower*2);
+ if (config->iConfiguration) {
+ printf(" - ");
+ usb_display_string(dev, config->iConfiguration);
+ printf("\n");
+ }
+}
+
+void usb_display_if_desc(struct usb_interface_descriptor *ifdesc,
+ struct usb_device *dev)
+{
+ printf(" Interface: %d\n", ifdesc->bInterfaceNumber);
+ printf(" - Alternate Setting %d, Endpoints: %d\n",
+ ifdesc->bAlternateSetting, ifdesc->bNumEndpoints);
+ printf(" - Class ");
+ usb_display_class_sub(ifdesc->bInterfaceClass,
+ ifdesc->bInterfaceSubClass, ifdesc->bInterfaceProtocol);
+ printf("\n");
+ if (ifdesc->iInterface) {
+ printf(" - ");
+ usb_display_string(dev, ifdesc->iInterface);
+ printf("\n");
+ }
+}
+
+void usb_display_ep_desc(struct usb_endpoint_descriptor *epdesc)
+{
+ printf(" - Endpoint %d %s ", epdesc->bEndpointAddress & 0xf,
+ (epdesc->bEndpointAddress & 0x80) ? "In" : "Out");
+ switch ((epdesc->bmAttributes & 0x03)) {
+ case 0:
+ printf("Control");
+ break;
+ case 1:
+ printf("Isochronous");
+ break;
+ case 2:
+ printf("Bulk");
+ break;
+ case 3:
+ printf("Interrupt");
+ break;
+ }
+ printf(" MaxPacket %d", epdesc->wMaxPacketSize);
+ if ((epdesc->bmAttributes & 0x03) == 0x3)
+ printf(" Interval %dms", epdesc->bInterval);
+ printf("\n");
+}
+
+/* main routine to diasplay the configs, interfaces and endpoints */
+void usb_display_config(struct usb_device *dev)
+{
+ struct usb_config *config;
+ struct usb_interface *ifdesc;
+ struct usb_endpoint_descriptor *epdesc;
+ int i, ii;
+
+ config = &dev->config;
+ usb_display_conf_desc(&config->desc, dev);
+ for (i = 0; i < config->no_of_if; i++) {
+ ifdesc = &config->if_desc[i];
+ usb_display_if_desc(&ifdesc->desc, dev);
+ for (ii = 0; ii < ifdesc->no_of_ep; ii++) {
+ epdesc = &ifdesc->ep_desc[ii];
+ usb_display_ep_desc(epdesc);
+ }
+ }
+ printf("\n");
+}
+
+static inline char *portspeed(int speed)
+{
+ if (speed == USB_SPEED_HIGH)
+ return "480 Mb/s";
+ else if (speed == USB_SPEED_LOW)
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
+/* shows the device tree recursively */
+void usb_show_tree_graph(struct usb_device *dev, char *pre)
+{
+ int i, index;
+ int has_child, last_child, port;
+
+ index = strlen(pre);
+ printf(" %s", pre);
+ /* check if the device has connected children */
+ has_child = 0;
+ for (i = 0; i < dev->maxchild; i++) {
+ if (dev->children[i] != NULL)
+ has_child = 1;
+ }
+ /* check if we are the last one */
+ last_child = 1;
+ if (dev->parent != NULL) {
+ for (i = 0; i < dev->parent->maxchild; i++) {
+ /* search for children */
+ if (dev->parent->children[i] == dev) {
+ /* found our pointer, see if we have a
+ * little sister
+ */
+ port = i;
+ while (i++ < dev->parent->maxchild) {
+ if (dev->parent->children[i] != NULL) {
+ /* found a sister */
+ last_child = 0;
+ break;
+ } /* if */
+ } /* while */
+ } /* device found */
+ } /* for all children of the parent */
+ printf("\b+-");
+ /* correct last child */
+ if (last_child)
+ pre[index-1] = ' ';
+ } /* if not root hub */
+ else
+ printf(" ");
+ printf("%d ", dev->devnum);
+ pre[index++] = ' ';
+ pre[index++] = has_child ? '|' : ' ';
+ pre[index] = 0;
+ printf(" %s (%s, %dmA)\n", usb_get_class_desc(
+ dev->config.if_desc[0].desc.bInterfaceClass),
+ portspeed(dev->speed),
+ dev->config.desc.bMaxPower * 2);
+ if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial))
+ printf(" %s %s %s %s\n", pre, dev->mf, dev->prod, dev->serial);
+ printf(" %s\n", pre);
+ if (dev->maxchild > 0) {
+ for (i = 0; i < dev->maxchild; i++) {
+ if (dev->children[i] != NULL) {
+ usb_show_tree_graph(dev->children[i], pre);
+ pre[index] = 0;
+ }
+ }
+ }
+}
+
+/* main routine for the tree command */
+void usb_show_tree(struct usb_device *dev)
+{
+ char preamble[32];
+
+ memset(preamble, 0, 32);
+ usb_show_tree_graph(dev, &preamble[0]);
+}
+
+
+/******************************************************************************
+ * usb boot command intepreter. Derived from diskboot
+ */
+#ifdef CONFIG_USB_STORAGE
+int do_usbboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev, part = 1, rcode;
+ ulong addr, cnt;
+ disk_partition_t info;
+ image_header_t *hdr;
+ block_dev_desc_t *stor_dev;
+#if defined(CONFIG_FIT)
+ const void *fit_hdr = NULL;
+#endif
+
+ switch (argc) {
+ case 1:
+ addr = CONFIG_SYS_LOAD_ADDR;
+ boot_device = getenv("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (!boot_device) {
+ puts("\n** No boot device **\n");
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+ stor_dev = usb_stor_get_dev(dev);
+ if (stor_dev == NULL || stor_dev->type == DEV_TYPE_UNKNOWN) {
+ printf("\n** Device %d not available\n", dev);
+ return 1;
+ }
+ if (stor_dev->block_read == NULL) {
+ printf("storage device not initialized. Use usb scan\n");
+ return 1;
+ }
+ if (*ep) {
+ if (*ep != ':') {
+ puts("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ part = simple_strtoul(++ep, NULL, 16);
+ }
+
+ if (get_partition_info(stor_dev, part, &info)) {
+ /* try to boot raw .... */
+ strncpy((char *)&info.type[0], BOOT_PART_TYPE,
+ sizeof(BOOT_PART_TYPE));
+ strncpy((char *)&info.name[0], "Raw", 4);
+ info.start = 0;
+ info.blksz = 0x200;
+ info.size = 2880;
+ printf("error reading partinfo...try to boot raw\n");
+ }
+ if ((strncmp((char *)info.type, BOOT_PART_TYPE,
+ sizeof(info.type)) != 0) &&
+ (strncmp((char *)info.type, BOOT_PART_COMP,
+ sizeof(info.type)) != 0)) {
+ printf("\n** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ return 1;
+ }
+ printf("\nLoading from USB device %d, partition %d: "
+ "Name: %.32s Type: %.32s\n",
+ dev, part, info.name, info.type);
+
+ debug("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
+ info.start, info.size, info.blksz);
+
+ if (stor_dev->block_read(dev, info.start, 1, (ulong *)addr) != 1) {
+ printf("** Read error on %d:%d\n", dev, part);
+ return 1;
+ }
+
+ switch (genimg_get_format((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ hdr = (image_header_t *)addr;
+
+ if (!image_check_hcrc(hdr)) {
+ puts("\n** Bad Header Checksum **\n");
+ return 1;
+ }
+
+ image_print_contents(hdr);
+
+ cnt = image_get_image_size(hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (const void *)addr;
+ puts("Fit image detected...\n");
+
+ cnt = fit_get_size(fit_hdr);
+ break;
+#endif
+ default:
+ puts("** Unknown image type\n");
+ return 1;
+ }
+
+ cnt += info.blksz - 1;
+ cnt /= info.blksz;
+ cnt -= 1;
+
+ if (stor_dev->block_read(dev, info.start+1, cnt,
+ (ulong *)(addr+info.blksz)) != cnt) {
+ printf("\n** Read error on %d:%d\n", dev, part);
+ return 1;
+ }
+
+#if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM
+ * first
+ */
+ if (genimg_get_format((void *)addr) == IMAGE_FORMAT_FIT) {
+ if (!fit_check_format(fit_hdr)) {
+ puts("** Bad FIT image format\n");
+ return 1;
+ }
+ fit_print_contents(fit_hdr);
+ }
+#endif
+
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ flush_cache(addr, (cnt+1)*info.blksz);
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
+ char *local_args[2];
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+ printf("Automatic boot of image at addr 0x%08lX ...\n", addr);
+ rcode = do_bootm(cmdtp, 0, 1, local_args);
+ return rcode;
+ }
+ return 0;
+}
+#endif /* CONFIG_USB_STORAGE */
+
+
+/******************************************************************************
+ * usb command intepreter
+ */
+int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+
+ int i;
+ struct usb_device *dev = NULL;
+ extern char usb_started;
+#ifdef CONFIG_USB_STORAGE
+ block_dev_desc_t *stor_dev;
+#endif
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if ((strncmp(argv[1], "reset", 5) == 0) ||
+ (strncmp(argv[1], "start", 5) == 0)) {
+ usb_stop();
+ printf("(Re)start USB...\n");
+ i = usb_init();
+ if (i >= 0) {
+#ifdef CONFIG_USB_STORAGE
+ /* try to recognize storage devices immediately */
+ usb_stor_curr_dev = usb_stor_scan(1);
+#endif
+#ifdef CONFIG_USB_HOST_ETHER
+ /* try to recognize ethernet devices immediately */
+ usb_ether_curr_dev = usb_host_eth_scan(1);
+#endif
+ }
+ return 0;
+ }
+ if (strncmp(argv[1], "stop", 4) == 0) {
+#ifdef CONFIG_USB_KEYBOARD
+ if (argc == 2) {
+ if (usb_kbd_deregister() != 0) {
+ printf("USB not stopped: usbkbd still"
+ " using USB\n");
+ return 1;
+ }
+ } else {
+ /* forced stop, switch console in to serial */
+ console_assign(stdin, "serial");
+ usb_kbd_deregister();
+ }
+#endif
+ printf("stopping USB..\n");
+ usb_stop();
+ return 0;
+ }
+ if (!usb_started) {
+ printf("USB is stopped. Please issue 'usb start' first.\n");
+ return 1;
+ }
+ if (strncmp(argv[1], "tree", 4) == 0) {
+ printf("\nDevice Tree:\n");
+ usb_show_tree(usb_get_dev_index(0));
+ return 0;
+ }
+ if (strncmp(argv[1], "inf", 3) == 0) {
+ int d;
+ if (argc == 2) {
+ for (d = 0; d < USB_MAX_DEVICE; d++) {
+ dev = usb_get_dev_index(d);
+ if (dev == NULL)
+ break;
+ usb_display_desc(dev);
+ usb_display_config(dev);
+ }
+ return 0;
+ } else {
+ int d;
+
+ i = simple_strtoul(argv[2], NULL, 16);
+ printf("config for device %d\n", i);
+ for (d = 0; d < USB_MAX_DEVICE; d++) {
+ dev = usb_get_dev_index(d);
+ if (dev == NULL)
+ break;
+ if (dev->devnum == i)
+ break;
+ }
+ if (dev == NULL) {
+ printf("*** NO Device avaiable ***\n");
+ return 0;
+ } else {
+ usb_display_desc(dev);
+ usb_display_config(dev);
+ }
+ }
+ return 0;
+ }
+#ifdef CONFIG_USB_STORAGE
+ if (strncmp(argv[1], "stor", 4) == 0)
+ return usb_stor_info();
+
+ if (strncmp(argv[1], "part", 4) == 0) {
+ int devno, ok = 0;
+ if (argc == 2) {
+ for (devno = 0; ; ++devno) {
+ stor_dev = usb_stor_get_dev(devno);
+ if (stor_dev == NULL)
+ break;
+ if (stor_dev->type != DEV_TYPE_UNKNOWN) {
+ ok++;
+ if (devno)
+ printf("\n");
+ debug("print_part of %x\n", devno);
+ print_part(stor_dev);
+ }
+ }
+ } else {
+ devno = simple_strtoul(argv[2], NULL, 16);
+ stor_dev = usb_stor_get_dev(devno);
+ if (stor_dev != NULL &&
+ stor_dev->type != DEV_TYPE_UNKNOWN) {
+ ok++;
+ debug("print_part of %x\n", devno);
+ print_part(stor_dev);
+ }
+ }
+ if (!ok) {
+ printf("\nno USB devices available\n");
+ return 1;
+ }
+ return 0;
+ }
+ if (strcmp(argv[1], "read") == 0) {
+ if (usb_stor_curr_dev < 0) {
+ printf("no current device selected\n");
+ return 1;
+ }
+ if (argc == 5) {
+ unsigned long addr = simple_strtoul(argv[2], NULL, 16);
+ unsigned long blk = simple_strtoul(argv[3], NULL, 16);
+ unsigned long cnt = simple_strtoul(argv[4], NULL, 16);
+ unsigned long n;
+ printf("\nUSB read: device %d block # %ld, count %ld"
+ " ... ", usb_stor_curr_dev, blk, cnt);
+ stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+ n = stor_dev->block_read(usb_stor_curr_dev, blk, cnt,
+ (ulong *)addr);
+ printf("%ld blocks read: %s\n", n,
+ (n == cnt) ? "OK" : "ERROR");
+ if (n == cnt)
+ return 0;
+ return 1;
+ }
+ }
+ if (strcmp(argv[1], "write") == 0) {
+ if (usb_stor_curr_dev < 0) {
+ printf("no current device selected\n");
+ return 1;
+ }
+ if (argc == 5) {
+ unsigned long addr = simple_strtoul(argv[2], NULL, 16);
+ unsigned long blk = simple_strtoul(argv[3], NULL, 16);
+ unsigned long cnt = simple_strtoul(argv[4], NULL, 16);
+ unsigned long n;
+ printf("\nUSB write: device %d block # %ld, count %ld"
+ " ... ", usb_stor_curr_dev, blk, cnt);
+ stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+ n = stor_dev->block_write(usb_stor_curr_dev, blk, cnt,
+ (ulong *)addr);
+ printf("%ld blocks write: %s\n", n,
+ (n == cnt) ? "OK" : "ERROR");
+ if (n == cnt)
+ return 0;
+ return 1;
+ }
+ }
+ if (strncmp(argv[1], "dev", 3) == 0) {
+ if (argc == 3) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+ printf("\nUSB device %d: ", dev);
+ stor_dev = usb_stor_get_dev(dev);
+ if (stor_dev == NULL) {
+ printf("unknown device\n");
+ return 1;
+ }
+ printf("\n Device %d: ", dev);
+ dev_print(stor_dev);
+ if (stor_dev->type == DEV_TYPE_UNKNOWN)
+ return 1;
+ usb_stor_curr_dev = dev;
+ printf("... is now current device\n");
+ return 0;
+ } else {
+ printf("\nUSB device %d: ", usb_stor_curr_dev);
+ stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+ dev_print(stor_dev);
+ if (stor_dev->type == DEV_TYPE_UNKNOWN)
+ return 1;
+ return 0;
+ }
+ return 0;
+ }
+#endif /* CONFIG_USB_STORAGE */
+ return cmd_usage(cmdtp);
+}
+
+#ifdef CONFIG_USB_STORAGE
+U_BOOT_CMD(
+ usb, 5, 1, do_usb,
+ "USB sub-system",
+ "reset - reset (rescan) USB controller\n"
+ "usb stop [f] - stop USB [f]=force stop\n"
+ "usb tree - show USB device tree\n"
+ "usb info [dev] - show available USB devices\n"
+ "usb storage - show details of USB storage devices\n"
+ "usb dev [dev] - show or set current USB storage device\n"
+ "usb part [dev] - print partition table of one or all USB storage"
+ " devices\n"
+ "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
+ " to memory address `addr'\n"
+ "usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'\n"
+ " from memory address `addr'"
+);
+
+
+U_BOOT_CMD(
+ usbboot, 3, 1, do_usbboot,
+ "boot from USB device",
+ "loadAddr dev:part"
+);
+
+#else
+U_BOOT_CMD(
+ usb, 5, 1, do_usb,
+ "USB sub-system",
+ "reset - reset (rescan) USB controller\n"
+ "usb tree - show USB device tree\n"
+ "usb info [dev] - show available USB devices"
+);
+#endif
diff --git a/u-boot/common/cmd_version.c b/u-boot/common/cmd_version.c
new file mode 100644
index 0000000..83cb11c
--- /dev/null
+++ b/u-boot/common/cmd_version.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <version.h>
+
+extern char version_string[];
+
+int do_version(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("\n%s\n", version_string);
+#ifdef CC_VERSION_STRING
+ puts(CC_VERSION_STRING "\n");
+#endif
+#ifdef LD_VERSION_STRING
+ puts(LD_VERSION_STRING "\n");
+#endif
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ version, 1, 1, do_version,
+ "print monitor, compiler and linker version",
+ ""
+);
diff --git a/u-boot/common/cmd_vfd.c b/u-boot/common/cmd_vfd.c
new file mode 100644
index 0000000..18c14d1
--- /dev/null
+++ b/u-boot/common/cmd_vfd.c
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Command to load a splash screen to the VFDs.
+ * NOTE that this will be controlled by a key combination when
+ * the keyboard stuff works. For now the user has to enter a
+ * bitmap number (only VFD_TEST_LOGO is supported now - 16.10.2002).
+ * Added VFD_REMOTE_LOGO (same as VFD_TEST_LOGO but a different color)
+ * on 20.10.2002.
+ *
+ * This rather crudely requires that each bitmap be included as a
+ * header file.
+ */
+#include <common.h>
+#include <command.h>
+
+#if defined(CONFIG_CMD_VFD)
+
+#include <vfd_logo.h>
+#define VFD_TEST_LOGO_BMPNR 0
+#define VFD_REMOTE_LOGO_BMPNR 1
+
+extern int transfer_pic(unsigned char, unsigned char *, int, int);
+
+int trab_vfd (ulong bitmap);
+
+int do_vfd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong bitmap;
+
+ if (argc != 2)
+ return cmd_usage(cmdtp);
+
+ if (argv[1][0] == '/') { /* select bitmap by number */
+ bitmap = simple_strtoul(argv[1]+1, NULL, 10);
+ return (trab_vfd(bitmap));
+ }
+
+ /* display bitmap at given address */
+ bitmap = simple_strtoul(argv[1], NULL, 16);
+ transfer_pic(3, (uchar *)bitmap, VFD_LOGO_HEIGHT, VFD_LOGO_WIDTH);
+ return 0;
+}
+
+U_BOOT_CMD(
+ vfd, 2, 0, do_vfd,
+ "load a bitmap to the VFDs on TRAB",
+ "/N\n"
+ " - load bitmap N to the VFDs (N is _decimal_ !!!)\n"
+ "vfd ADDR\n"
+ " - load bitmap at address ADDR"
+);
+#endif
+
+int trab_vfd (ulong bitmap)
+{
+ uchar *addr;
+ char *s;
+
+ switch (bitmap) {
+ case VFD_TEST_LOGO_BMPNR:
+ if ((s = getenv ("bitmap0")) != NULL) {
+ addr = (uchar *)simple_strtoul (s, NULL, 16);
+ } else {
+ addr = &vfd_test_logo_bitmap[0];
+ }
+ break;
+ case VFD_REMOTE_LOGO_BMPNR:
+ if ((s = getenv ("bitmap1")) != NULL) {
+ addr = (uchar *)simple_strtoul (s, NULL, 16);
+ } else {
+ addr = &vfd_remote_logo_bitmap[0];
+ }
+ break;
+ default:
+ printf("Unknown bitmap %ld\n", bitmap);
+ return 1;
+ }
+ transfer_pic(3, addr, VFD_LOGO_HEIGHT, VFD_LOGO_WIDTH);
+ return 0;
+}
diff --git a/u-boot/common/cmd_ximg.c b/u-boot/common/cmd_ximg.c
new file mode 100644
index 0000000..dceb975
--- /dev/null
+++ b/u-boot/common/cmd_ximg.c
@@ -0,0 +1,275 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2003
+ * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
+ *
+ * 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
+ */
+
+
+/*
+ * Multi Image extract
+ */
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <watchdog.h>
+#if defined(CONFIG_BZIP2)
+#include <bzlib.h>
+#endif
+#include <asm/byteorder.h>
+
+#ifndef CONFIG_SYS_XIMG_LEN
+/* use 8MByte as default max gunzip size */
+#define CONFIG_SYS_XIMG_LEN 0x800000
+#endif
+
+int
+do_imgextract(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr = load_addr;
+ ulong dest = 0;
+ ulong data, len, count;
+ int verify;
+ int part = 0;
+ char pbuf[10];
+ image_header_t *hdr;
+#if defined(CONFIG_FIT)
+ const char *uname = NULL;
+ const void* fit_hdr;
+ int noffset;
+ const void *fit_data;
+ size_t fit_len;
+#endif
+ uint unc_len = CONFIG_SYS_XIMG_LEN;
+ uint8_t comp;
+
+ verify = getenv_yesno ("verify");
+
+ if (argc > 1) {
+ addr = simple_strtoul(argv[1], NULL, 16);
+ }
+ if (argc > 2) {
+ part = simple_strtoul(argv[2], NULL, 16);
+#if defined(CONFIG_FIT)
+ uname = argv[2];
+#endif
+ }
+ if (argc > 3) {
+ dest = simple_strtoul(argv[3], NULL, 16);
+ }
+
+ switch (genimg_get_format ((void *)addr)) {
+ case IMAGE_FORMAT_LEGACY:
+
+ printf("## Copying part %d from legacy image "
+ "at %08lx ...\n", part, addr);
+
+ hdr = (image_header_t *)addr;
+ if (!image_check_magic (hdr)) {
+ printf("Bad Magic Number\n");
+ return 1;
+ }
+
+ if (!image_check_hcrc (hdr)) {
+ printf("Bad Header Checksum\n");
+ return 1;
+ }
+#ifdef DEBUG
+ image_print_contents (hdr);
+#endif
+
+ if (!image_check_type (hdr, IH_TYPE_MULTI)) {
+ printf("Wrong Image Type for %s command\n",
+ cmdtp->name);
+ return 1;
+ }
+
+ comp = image_get_comp (hdr);
+ if ((comp != IH_COMP_NONE) && (argc < 4)) {
+ printf("Must specify load address for %s command "
+ "with compressed image\n",
+ cmdtp->name);
+ return 1;
+ }
+
+ if (verify) {
+ printf(" Verifying Checksum ... ");
+ if (!image_check_dcrc (hdr)) {
+ printf("Bad Data CRC\n");
+ return 1;
+ }
+ printf("OK\n");
+ }
+
+ count = image_multi_count (hdr);
+ if (part >= count) {
+ printf("Bad Image Part\n");
+ return 1;
+ }
+
+ image_multi_getimg (hdr, part, &data, &len);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ if (uname == NULL) {
+ puts ("No FIT subimage unit name\n");
+ return 1;
+ }
+
+ printf("## Copying '%s' subimage from FIT image "
+ "at %08lx ...\n", uname, addr);
+
+ fit_hdr = (const void *)addr;
+ if (!fit_check_format (fit_hdr)) {
+ puts ("Bad FIT image format\n");
+ return 1;
+ }
+
+ /* get subimage node offset */
+ noffset = fit_image_get_node (fit_hdr, uname);
+ if (noffset < 0) {
+ printf ("Can't find '%s' FIT subimage\n", uname);
+ return 1;
+ }
+
+ if (fit_image_check_comp (fit_hdr, noffset, IH_COMP_NONE)
+ && (argc < 4)) {
+ printf("Must specify load address for %s command "
+ "with compressed image\n",
+ cmdtp->name);
+ return 1;
+ }
+
+ /* verify integrity */
+ if (verify) {
+ if (!fit_image_check_hashes (fit_hdr, noffset)) {
+ puts ("Bad Data Hash\n");
+ return 1;
+ }
+ }
+
+ /* get subimage data address and length */
+ if (fit_image_get_data (fit_hdr, noffset,
+ &fit_data, &fit_len)) {
+ puts ("Could not find script subimage data\n");
+ return 1;
+ }
+
+ if (fit_image_get_comp (fit_hdr, noffset, &comp)) {
+ puts ("Could not find script subimage "
+ "compression type\n");
+ return 1;
+ }
+
+ data = (ulong)fit_data;
+ len = (ulong)fit_len;
+ break;
+#endif
+ default:
+ puts ("Invalid image type for imxtract\n");
+ return 1;
+ }
+
+ if (argc > 3) {
+ switch (comp) {
+ case IH_COMP_NONE:
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+ {
+ size_t l = len;
+ size_t tail;
+ void *to = (void *) dest;
+ void *from = (void *)data;
+
+ printf (" Loading part %d ... ", part);
+
+ while (l > 0) {
+ tail = (l > CHUNKSZ) ? CHUNKSZ : l;
+ WATCHDOG_RESET();
+ memmove (to, from, tail);
+ to += tail;
+ from += tail;
+ l -= tail;
+ }
+ }
+#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
+ printf (" Loading part %d ... ", part);
+ memmove ((char *) dest, (char *)data, len);
+#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
+ break;
+ case IH_COMP_GZIP:
+ printf (" Uncompressing part %d ... ", part);
+ if (gunzip ((void *) dest, unc_len,
+ (uchar *) data, &len) != 0) {
+ puts ("GUNZIP ERROR - image not loaded\n");
+ return 1;
+ }
+ break;
+#if defined(CONFIG_BZIP2)
+ case IH_COMP_BZIP2:
+ {
+ int i;
+
+ printf (" Uncompressing part %d ... ", part);
+ /*
+ * If we've got less than 4 MB of malloc()
+ * space, use slower decompression algorithm
+ * which requires at most 2300 KB of memory.
+ */
+ i = BZ2_bzBuffToBuffDecompress(
+ (char*)ntohl(hdr->ih_load),
+ &unc_len, (char *)data, len,
+ CONFIG_SYS_MALLOC_LEN < (4096 * 1024),
+ 0);
+ if (i != BZ_OK) {
+ printf ("BUNZIP2 ERROR %d - "
+ "image not loaded\n", i);
+ return 1;
+ }
+ }
+ break;
+#endif /* CONFIG_BZIP2 */
+ default:
+ printf ("Unimplemented compression type %d\n", comp);
+ return 1;
+ }
+ puts ("OK\n");
+ }
+
+ sprintf(pbuf, "%8lx", data);
+ setenv("fileaddr", pbuf);
+ sprintf(pbuf, "%8lx", len);
+ setenv("filesize", pbuf);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ imxtract, 4, 1, do_imgextract,
+ "extract a part of a multi-image",
+ "addr part [dest]\n"
+ " - extract <part> from legacy image at <addr> and copy to <dest>"
+#if defined(CONFIG_FIT)
+ "\n"
+ "addr uname [dest]\n"
+ " - extract <uname> subimage from FIT image at <addr> and copy to <dest>"
+#endif
+);
diff --git a/u-boot/common/cmd_yaffs2.c b/u-boot/common/cmd_yaffs2.c
new file mode 100644
index 0000000..7c01ea2
--- /dev/null
+++ b/u-boot/common/cmd_yaffs2.c
@@ -0,0 +1,213 @@
+#include <common.h>
+
+#include <config.h>
+#include <command.h>
+
+#ifdef YAFFS2_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+extern void cmd_yaffs_mount(char *mp);
+extern void cmd_yaffs_umount(char *mp);
+extern void cmd_yaffs_read_file(char *fn);
+extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile);
+extern void cmd_yaffs_ls(const char *mountpt, int longlist);
+extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
+extern void cmd_yaffs_mread_file(char *fn, char *addr);
+extern void cmd_yaffs_mkdir(const char *dir);
+extern void cmd_yaffs_rmdir(const char *dir);
+extern void cmd_yaffs_rm(const char *path);
+extern void cmd_yaffs_mv(const char *oldPath, const char *newPath);
+
+extern int yaffs_DumpDevStruct(const char *path);
+
+
+int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *mtpoint = argv[1];
+ cmd_yaffs_mount(mtpoint);
+
+ return(0);
+}
+
+int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *mtpoint = argv[1];
+ cmd_yaffs_umount(mtpoint);
+
+ return(0);
+}
+
+int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *dirname = argv[argc-1];
+
+ cmd_yaffs_ls(dirname, (argc>2)?1:0);
+
+ return(0);
+}
+
+int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = argv[1];
+ printf ("Reading file %s ", filename);
+
+ cmd_yaffs_read_file(filename);
+
+ printf ("done\n");
+ return(0);
+}
+
+int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = argv[1];
+ ulong value = simple_strtoul(argv[2], NULL, 16);
+ ulong numValues = simple_strtoul(argv[3], NULL, 16);
+
+ printf ("Writing value (%x) %x times to %s... ", value, numValues, filename);
+
+ cmd_yaffs_write_file(filename,value,numValues);
+
+ printf ("done\n");
+ return(0);
+}
+
+int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = argv[1];
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+
+ cmd_yaffs_mread_file(filename, (char *)addr);
+
+ return(0);
+}
+
+int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *filename = argv[1];
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong size = simple_strtoul(argv[3], NULL, 16);
+
+ cmd_yaffs_mwrite_file(filename, (char *)addr, size);
+
+ return(0);
+}
+
+int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *dirname = argv[1];
+
+ cmd_yaffs_mkdir(dirname);
+
+ return(0);
+}
+
+int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *dirname = argv[1];
+
+ cmd_yaffs_rmdir(dirname);
+
+ return(0);
+}
+
+int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *path = argv[1];
+
+ cmd_yaffs_rm(path);
+
+ return(0);
+}
+
+int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *oldPath = argv[1];
+ char *newPath = argv[2];
+
+ cmd_yaffs_mv(newPath, oldPath);
+
+ return(0);
+}
+
+int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *dirname = argv[1];
+ if (yaffs_DumpDevStruct(dirname) != 0)
+ printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname);
+ return 0;
+}
+
+U_BOOT_CMD(
+ ymount, 3, 0, do_ymount,
+ "mount yaffs",
+ ""
+);
+
+U_BOOT_CMD(
+ yumount, 3, 0, do_yumount,
+ "unmount yaffs",
+ ""
+);
+
+U_BOOT_CMD(
+ yls, 4, 0, do_yls,
+ "yaffs ls",
+ "[-l] name"
+);
+
+U_BOOT_CMD(
+ yrd, 2, 0, do_yrd,
+ "read file from yaffs",
+ "filename"
+);
+
+U_BOOT_CMD(
+ ywr, 4, 0, do_ywr,
+ "write file to yaffs",
+ "filename value num_vlues"
+);
+
+U_BOOT_CMD(
+ yrdm, 3, 0, do_yrdm,
+ "read file to memory from yaffs",
+ "filename offset"
+);
+
+U_BOOT_CMD(
+ ywrm, 4, 0, do_ywrm,
+ "write file from memory to yaffs",
+ "filename offset size"
+);
+
+U_BOOT_CMD(
+ ymkdir, 2, 0, do_ymkdir,
+ "YAFFS mkdir",
+ "dirname"
+);
+
+U_BOOT_CMD(
+ yrmdir, 2, 0, do_yrmdir,
+ "YAFFS rmdir",
+ "dirname"
+);
+
+U_BOOT_CMD(
+ yrm, 2, 0, do_yrm,
+ "YAFFS rm",
+ "path"
+);
+
+U_BOOT_CMD(
+ ymv, 4, 0, do_ymv,
+ "YAFFS mv",
+ "oldPath newPath"
+);
+
+U_BOOT_CMD(
+ ydump, 2, 0, do_ydump,
+ "YAFFS device struct",
+ "dirname"
+);
diff --git a/u-boot/common/command.c b/u-boot/common/command.c
new file mode 100644
index 0000000..b3ec510
--- /dev/null
+++ b/u-boot/common/command.c
@@ -0,0 +1,481 @@
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/*
+ * Command Processor Table
+ */
+
+#include <common.h>
+#include <command.h>
+
+/*
+ * Use puts() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+
+int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
+ flag, int argc, char * const argv[])
+{
+ int i;
+ int rcode = 0;
+
+ if (argc == 1) { /*show list of commands */
+ cmd_tbl_t *cmd_array[cmd_items];
+ int i, j, swaps;
+
+ /* Make array of commands from .uboot_cmd section */
+ cmdtp = cmd_start;
+ for (i = 0; i < cmd_items; i++) {
+ cmd_array[i] = cmdtp++;
+ }
+
+ /* Sort command list (trivial bubble sort) */
+ for (i = cmd_items - 1; i > 0; --i) {
+ swaps = 0;
+ for (j = 0; j < i; ++j) {
+ if (strcmp (cmd_array[j]->name,
+ cmd_array[j + 1]->name) > 0) {
+ cmd_tbl_t *tmp;
+ tmp = cmd_array[j];
+ cmd_array[j] = cmd_array[j + 1];
+ cmd_array[j + 1] = tmp;
+ ++swaps;
+ }
+ }
+ if (!swaps)
+ break;
+ }
+
+ /* print short help (usage) */
+ for (i = 0; i < cmd_items; i++) {
+ const char *usage = cmd_array[i]->usage;
+
+ /* allow user abort */
+ if (ctrlc ())
+ return 1;
+ if (usage == NULL)
+ continue;
+ printf("%-*s- %s\n", CONFIG_SYS_HELP_CMD_WIDTH,
+ cmd_array[i]->name, usage);
+ }
+ return 0;
+ }
+ /*
+ * command help (long version)
+ */
+ for (i = 1; i < argc; ++i) {
+ if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL) {
+ rcode |= cmd_usage(cmdtp);
+ } else {
+ printf ("Unknown command '%s' - try 'help'"
+ " without arguments for list of all"
+ " known commands\n\n", argv[i]
+ );
+ rcode = 1;
+ }
+ }
+ return rcode;
+}
+
+/***************************************************************************
+ * find command table entry for a command
+ */
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
+{
+ cmd_tbl_t *cmdtp;
+ cmd_tbl_t *cmdtp_temp = table; /*Init value */
+ const char *p;
+ int len;
+ int n_found = 0;
+
+ if (!cmd)
+ return NULL;
+ /*
+ * Some commands allow length modifiers (like "cp.b");
+ * compare command name only until first dot.
+ */
+ len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
+
+ for (cmdtp = table;
+ cmdtp != table + table_len;
+ cmdtp++) {
+ if (strncmp (cmd, cmdtp->name, len) == 0) {
+ if (len == strlen (cmdtp->name))
+ return cmdtp; /* full match */
+
+ cmdtp_temp = cmdtp; /* abbreviated command ? */
+ n_found++;
+ }
+ }
+ if (n_found == 1) { /* exactly one match */
+ return cmdtp_temp;
+ }
+
+ return NULL; /* not found or ambiguous command */
+}
+
+cmd_tbl_t *find_cmd (const char *cmd)
+{
+ int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
+ return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
+}
+
+int cmd_usage(cmd_tbl_t *cmdtp)
+{
+ printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+
+#ifdef CONFIG_SYS_LONGHELP
+ printf("Usage:\n%s ", cmdtp->name);
+
+ if (!cmdtp->help) {
+ puts ("- No additional help available.\n");
+ return 1;
+ }
+
+ puts (cmdtp->help);
+ putc ('\n');
+#endif /* CONFIG_SYS_LONGHELP */
+ return 1;
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+
+int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+ static char tmp_buf[512];
+ int space;
+
+ space = last_char == '\0' || last_char == ' ' || last_char == '\t';
+
+ if (space && argc == 1)
+ return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+ if (!space && argc == 2)
+ return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+ return 0;
+}
+
+/*************************************************************************************/
+
+static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+ cmd_tbl_t *cmdtp;
+ const char *p;
+ int len, clen;
+ int n_found = 0;
+ const char *cmd;
+
+ /* sanity? */
+ if (maxv < 2)
+ return -2;
+
+ cmdv[0] = NULL;
+
+ if (argc == 0) {
+ /* output full list of commands */
+ for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+ cmdv[n_found++] = cmdtp->name;
+ }
+ cmdv[n_found] = NULL;
+ return n_found;
+ }
+
+ /* more than one arg or one but the start of the next */
+ if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
+ cmdtp = find_cmd(argv[0]);
+ if (cmdtp == NULL || cmdtp->complete == NULL) {
+ cmdv[0] = NULL;
+ return 0;
+ }
+ return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
+ }
+
+ cmd = argv[0];
+ /*
+ * Some commands allow length modifiers (like "cp.b");
+ * compare command name only until first dot.
+ */
+ p = strchr(cmd, '.');
+ if (p == NULL)
+ len = strlen(cmd);
+ else
+ len = p - cmd;
+
+ /* return the partial matches */
+ for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
+
+ clen = strlen(cmdtp->name);
+ if (clen < len)
+ continue;
+
+ if (memcmp(cmd, cmdtp->name, len) != 0)
+ continue;
+
+ /* too many! */
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+
+ cmdv[n_found++] = cmdtp->name;
+ }
+
+ cmdv[n_found] = NULL;
+ return n_found;
+}
+
+static int make_argv(char *s, int argvsz, char *argv[])
+{
+ int argc = 0;
+
+ /* split into argv */
+ while (argc < argvsz - 1) {
+
+ /* skip any white space */
+ while ((*s == ' ') || (*s == '\t'))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ argv[argc++] = s; /* begin of argument string */
+
+ /* find end of string */
+ while (*s && (*s != ' ') && (*s != '\t'))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ *s++ = '\0'; /* terminate current arg */
+ }
+ argv[argc] = NULL;
+
+ return argc;
+}
+
+static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
+{
+ int ll = leader != NULL ? strlen(leader) : 0;
+ int sl = sep != NULL ? strlen(sep) : 0;
+ int len, i;
+
+ if (banner) {
+ puts("\n");
+ puts(banner);
+ }
+
+ i = linemax; /* force leader and newline */
+ while (*argv != NULL) {
+ len = strlen(*argv) + sl;
+ if (i + len >= linemax) {
+ puts("\n");
+ if (leader)
+ puts(leader);
+ i = ll - sl;
+ } else if (sep)
+ puts(sep);
+ puts(*argv++);
+ i += len;
+ }
+ printf("\n");
+}
+
+static int find_common_prefix(char * const argv[])
+{
+ int i, len;
+ char *anchor, *s, *t;
+
+ if (*argv == NULL)
+ return 0;
+
+ /* begin with max */
+ anchor = *argv++;
+ len = strlen(anchor);
+ while ((t = *argv++) != NULL) {
+ s = anchor;
+ for (i = 0; i < len; i++, t++, s++) {
+ if (*t != *s)
+ break;
+ }
+ len = s - anchor;
+ }
+ return len;
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
+
+int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
+{
+ int n = *np, col = *colp;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ char *cmdv[20];
+ char *s, *t;
+ const char *sep;
+ int i, j, k, len, seplen, argc;
+ int cnt;
+ char last_char;
+
+ if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0)
+ return 0; /* not in normal console */
+
+ cnt = strlen(buf);
+ if (cnt >= 1)
+ last_char = buf[cnt - 1];
+ else
+ last_char = '\0';
+
+ /* copy to secondary buffer which will be affected */
+ strcpy(tmp_buf, buf);
+
+ /* separate into argv */
+ argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
+
+ /* do the completion and return the possible completions */
+ i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
+
+ /* no match; bell and out */
+ if (i == 0) {
+ if (argc > 1) /* allow tab for non command */
+ return 0;
+ putc('\a');
+ return 1;
+ }
+
+ s = NULL;
+ len = 0;
+ sep = NULL;
+ seplen = 0;
+ if (i == 1) { /* one match; perfect */
+ k = strlen(argv[argc - 1]);
+ s = cmdv[0] + k;
+ len = strlen(s);
+ sep = " ";
+ seplen = 1;
+ } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
+ k = strlen(argv[argc - 1]);
+ j -= k;
+ if (j > 0) {
+ s = cmdv[0] + k;
+ len = j;
+ }
+ }
+
+ if (s != NULL) {
+ k = len + seplen;
+ /* make sure it fits */
+ if (n + k >= CONFIG_SYS_CBSIZE - 2) {
+ putc('\a');
+ return 1;
+ }
+
+ t = buf + cnt;
+ for (i = 0; i < len; i++)
+ *t++ = *s++;
+ if (sep != NULL)
+ for (i = 0; i < seplen; i++)
+ *t++ = sep[i];
+ *t = '\0';
+ n += k;
+ col += k;
+ puts(t - k);
+ if (sep == NULL)
+ putc('\a');
+ *np = n;
+ *colp = col;
+ } else {
+ print_argv(NULL, " ", " ", 78, cmdv);
+
+ puts(prompt);
+ puts(buf);
+ }
+ return 1;
+}
+
+#endif
+
+#ifdef CMD_DATA_SIZE
+int cmd_get_data_size(char* arg, int default_size)
+{
+ /* Check for a size specification .b, .w or .l.
+ */
+ int len = strlen(arg);
+ if (len > 2 && arg[len-2] == '.') {
+ switch(arg[len-1]) {
+ case 'b':
+ return 1;
+ case 'w':
+ return 2;
+ case 'l':
+ return 4;
+ case 's':
+ return -2;
+ default:
+ return -1;
+ }
+ }
+ return default_size;
+}
+#endif
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+
+void fixup_cmdtable(cmd_tbl_t *cmdtp, int size)
+{
+ int i;
+
+ if (gd->reloc_off == 0)
+ return;
+
+ for (i = 0; i < size; i++) {
+ ulong addr;
+
+ addr = (ulong) (cmdtp->cmd) + gd->reloc_off;
+#if DEBUG_COMMANDS
+ printf("Command \"%s\": 0x%08lx => 0x%08lx\n",
+ cmdtp->name, (ulong) (cmdtp->cmd), addr);
+#endif
+ cmdtp->cmd =
+ (int (*)(struct cmd_tbl_s *, int, int, char * const []))addr;
+ addr = (ulong)(cmdtp->name) + gd->reloc_off;
+ cmdtp->name = (char *)addr;
+ if (cmdtp->usage) {
+ addr = (ulong)(cmdtp->usage) + gd->reloc_off;
+ cmdtp->usage = (char *)addr;
+ }
+#ifdef CONFIG_SYS_LONGHELP
+ if (cmdtp->help) {
+ addr = (ulong)(cmdtp->help) + gd->reloc_off;
+ cmdtp->help = (char *)addr;
+ }
+#endif
+ cmdtp++;
+ }
+}
+#endif
diff --git a/u-boot/common/console.c b/u-boot/common/console.c
new file mode 100644
index 0000000..8c650e0
--- /dev/null
+++ b/u-boot/common/console.c
@@ -0,0 +1,722 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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 <stdarg.h>
+#include <malloc.h>
+#include <stdio_dev.h>
+#include <exports.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
+/*
+ * if overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console(void);
+#define OVERWRITE_CONSOLE overwrite_console()
+#else
+#define OVERWRITE_CONSOLE 0
+#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
+
+#endif /* CONFIG_SYS_CONSOLE_IS_IN_ENV */
+
+static int console_setfile(int file, struct stdio_dev * dev)
+{
+ int error = 0;
+
+ if (dev == NULL)
+ return -1;
+
+ switch (file) {
+ case stdin:
+ case stdout:
+ case stderr:
+ /* Start new device */
+ if (dev->start) {
+ error = dev->start();
+ /* If it's not started dont use it */
+ if (error < 0)
+ break;
+ }
+
+ /* Assign the new device (leaving the existing one started) */
+ stdio_devices[file] = dev;
+
+ /*
+ * Update monitor functions
+ * (to use the console stuff by other applications)
+ */
+ switch (file) {
+ case stdin:
+ gd->jt[XF_getc] = dev->getc;
+ gd->jt[XF_tstc] = dev->tstc;
+ break;
+ case stdout:
+ gd->jt[XF_putc] = dev->putc;
+ gd->jt[XF_puts] = dev->puts;
+ gd->jt[XF_printf] = printf;
+ break;
+ }
+ break;
+
+ default: /* Invalid file ID */
+ error = -1;
+ }
+ return error;
+}
+
+#if defined(CONFIG_CONSOLE_MUX)
+/** Console I/O multiplexing *******************************************/
+
+static struct stdio_dev *tstcdev;
+struct stdio_dev **console_devices[MAX_FILES];
+int cd_count[MAX_FILES];
+
+/*
+ * This depends on tstc() always being called before getc().
+ * This is guaranteed to be true because this routine is called
+ * only from fgetc() which assures it.
+ * No attempt is made to demultiplex multiple input sources.
+ */
+static int console_getc(int file)
+{
+ unsigned char ret;
+
+ /* This is never called with testcdev == NULL */
+ ret = tstcdev->getc();
+ tstcdev = NULL;
+ return ret;
+}
+
+static int console_tstc(int file)
+{
+ int i, ret;
+ struct stdio_dev *dev;
+
+ disable_ctrlc(1);
+ for (i = 0; i < cd_count[file]; i++) {
+ dev = console_devices[file][i];
+ if (dev->tstc != NULL) {
+ ret = dev->tstc();
+ if (ret > 0) {
+ tstcdev = dev;
+ disable_ctrlc(0);
+ return ret;
+ }
+ }
+ }
+ disable_ctrlc(0);
+
+ return 0;
+}
+
+static void console_putc(int file, const char c)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for (i = 0; i < cd_count[file]; i++) {
+ dev = console_devices[file][i];
+ if (dev->putc != NULL)
+ dev->putc(c);
+ }
+}
+
+static void console_puts(int file, const char *s)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for (i = 0; i < cd_count[file]; i++) {
+ dev = console_devices[file][i];
+ if (dev->puts != NULL)
+ dev->puts(s);
+ }
+}
+
+static inline void console_printdevs(int file)
+{
+ iomux_printdevs(file);
+}
+
+static inline void console_doenv(int file, struct stdio_dev *dev)
+{
+ iomux_doenv(file, dev->name);
+}
+#else
+static inline int console_getc(int file)
+{
+ return stdio_devices[file]->getc();
+}
+
+static inline int console_tstc(int file)
+{
+ return stdio_devices[file]->tstc();
+}
+
+static inline void console_putc(int file, const char c)
+{
+ stdio_devices[file]->putc(c);
+}
+
+static inline void console_puts(int file, const char *s)
+{
+ stdio_devices[file]->puts(s);
+}
+
+static inline void console_printdevs(int file)
+{
+ printf("%s\n", stdio_devices[file]->name);
+}
+
+static inline void console_doenv(int file, struct stdio_dev *dev)
+{
+ console_setfile(file, dev);
+}
+#endif /* defined(CONFIG_CONSOLE_MUX) */
+
+/** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/
+
+int serial_printf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ serial_puts(printbuffer);
+ return i;
+}
+
+int fgetc(int file)
+{
+ if (file < MAX_FILES) {
+#if defined(CONFIG_CONSOLE_MUX)
+ /*
+ * Effectively poll for input wherever it may be available.
+ */
+ for (;;) {
+ /*
+ * Upper layer may have already called tstc() so
+ * check for that first.
+ */
+ if (tstcdev != NULL)
+ return console_getc(file);
+ console_tstc(file);
+#ifdef CONFIG_WATCHDOG
+ /*
+ * If the watchdog must be rate-limited then it should
+ * already be handled in board-specific code.
+ */
+ udelay(1);
+#endif
+ }
+#else
+ return console_getc(file);
+#endif
+ }
+
+ return -1;
+}
+
+int ftstc(int file)
+{
+ if (file < MAX_FILES)
+ return console_tstc(file);
+
+ return -1;
+}
+
+void fputc(int file, const char c)
+{
+ if (file < MAX_FILES)
+ console_putc(file, c);
+}
+
+void fputs(int file, const char *s)
+{
+ if (file < MAX_FILES)
+ console_puts(file, s);
+}
+
+int fprintf(int file, const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ /* Send to desired file */
+ fputs(file, printbuffer);
+ return i;
+}
+
+/** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
+
+int getc(void)
+{
+#ifdef CONFIG_DISABLE_CONSOLE
+ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
+ return 0;
+#endif
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Get from the standard input */
+ return fgetc(stdin);
+ }
+
+ /* Send directly to the handler */
+ return serial_getc();
+}
+
+int tstc(void)
+{
+#ifdef CONFIG_DISABLE_CONSOLE
+ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
+ return 0;
+#endif
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Test the standard input */
+ return ftstc(stdin);
+ }
+
+ /* Send directly to the handler */
+ return serial_tstc();
+}
+
+void putc(const char c)
+{
+#ifdef CONFIG_SILENT_CONSOLE
+ if (gd->flags & GD_FLG_SILENT)
+ return;
+#endif
+
+#ifdef CONFIG_DISABLE_CONSOLE
+ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
+ return;
+#endif
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Send to the standard output */
+ fputc(stdout, c);
+ } else {
+ /* Send directly to the handler */
+ serial_putc(c);
+ }
+}
+
+void puts(const char *s)
+{
+#ifdef CONFIG_SILENT_CONSOLE
+ if (gd->flags & GD_FLG_SILENT)
+ return;
+#endif
+
+#ifdef CONFIG_DISABLE_CONSOLE
+ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
+ return;
+#endif
+
+ if (gd->flags & GD_FLG_DEVINIT) {
+ /* Send to the standard output */
+ fputs(stdout, s);
+ } else {
+ /* Send directly to the handler */
+ serial_puts(s);
+ }
+}
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ /* Print the string */
+ puts(printbuffer);
+ return i;
+}
+
+int vprintf(const char *fmt, va_list args)
+{
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf(printbuffer, fmt, args);
+
+ /* Print the string */
+ puts(printbuffer);
+ return i;
+}
+
+/* test if ctrl-c was pressed */
+static int ctrlc_disabled = 0; /* see disable_ctrl() */
+static int ctrlc_was_pressed = 0;
+int ctrlc(void)
+{
+ if (!ctrlc_disabled && gd->have_console) {
+ if (tstc()) {
+ switch (getc()) {
+ case 0x03: /* ^C - Control C */
+ ctrlc_was_pressed = 1;
+ return 1;
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+int disable_ctrlc(int disable)
+{
+ int prev = ctrlc_disabled; /* save previous state */
+
+ ctrlc_disabled = disable;
+ return prev;
+}
+
+int had_ctrlc (void)
+{
+ return ctrlc_was_pressed;
+}
+
+void clear_ctrlc(void)
+{
+ ctrlc_was_pressed = 0;
+}
+
+#ifdef CONFIG_MODEM_SUPPORT_DEBUG
+char screen[1024];
+char *cursor = screen;
+int once = 0;
+inline void dbg(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CONFIG_SYS_PBSIZE];
+
+ if (!once) {
+ memset(screen, 0, sizeof(screen));
+ once++;
+ }
+
+ va_start(args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ if ((screen + sizeof(screen) - 1 - cursor)
+ < strlen(printbuffer) + 1) {
+ memset(screen, 0, sizeof(screen));
+ cursor = screen;
+ }
+ sprintf(cursor, printbuffer);
+ cursor += strlen(printbuffer);
+
+}
+#else
+inline void dbg(const char *fmt, ...)
+{
+}
+#endif
+
+/** U-Boot INIT FUNCTIONS *************************************************/
+
+struct stdio_dev *search_device(int flags, const char *name)
+{
+ struct stdio_dev *dev;
+
+ dev = stdio_get_by_name(name);
+
+ if (dev && (dev->flags & flags))
+ return dev;
+
+ return NULL;
+}
+
+int console_assign(int file, const char *devname)
+{
+ int flag;
+ struct stdio_dev *dev;
+
+ /* Check for valid file */
+ switch (file) {
+ case stdin:
+ flag = DEV_FLAGS_INPUT;
+ break;
+ case stdout:
+ case stderr:
+ flag = DEV_FLAGS_OUTPUT;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Check for valid device name */
+
+ dev = search_device(flag, devname);
+
+ if (dev)
+ return console_setfile(file, dev);
+
+ return -1;
+}
+
+/* Called before relocation - use serial functions */
+int console_init_f(void)
+{
+ gd->have_console = 1;
+
+#ifdef CONFIG_SILENT_CONSOLE
+ if (getenv("silent") != NULL)
+ gd->flags |= GD_FLG_SILENT;
+#endif
+
+ return 0;
+}
+
+void stdio_print_current_devices(void)
+{
+#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
+ /* Print information */
+ puts("In: ");
+ if (stdio_devices[stdin] == NULL) {
+ puts("No input devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stdin]->name);
+ }
+
+ puts("Out: ");
+ if (stdio_devices[stdout] == NULL) {
+ puts("No output devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stdout]->name);
+ }
+
+ puts("Err: ");
+ if (stdio_devices[stderr] == NULL) {
+ puts("No error devices available!\n");
+ } else {
+ printf ("%s\n", stdio_devices[stderr]->name);
+ }
+#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */
+}
+
+#ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
+/* Called after the relocation - use desired console functions */
+int console_init_r(void)
+{
+ char *stdinname, *stdoutname, *stderrname;
+ struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
+#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
+ int i;
+#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
+#ifdef CONFIG_CONSOLE_MUX
+ int iomux_err = 0;
+#endif
+
+ /* set default handlers at first */
+ gd->jt[XF_getc] = serial_getc;
+ gd->jt[XF_tstc] = serial_tstc;
+ gd->jt[XF_putc] = serial_putc;
+ gd->jt[XF_puts] = serial_puts;
+ gd->jt[XF_printf] = serial_printf;
+
+ /* stdin stdout and stderr are in environment */
+ /* scan for it */
+ stdinname = getenv("stdin");
+ stdoutname = getenv("stdout");
+ stderrname = getenv("stderr");
+
+ if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */
+ inputdev = search_device(DEV_FLAGS_INPUT, stdinname);
+ outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname);
+ errdev = search_device(DEV_FLAGS_OUTPUT, stderrname);
+#ifdef CONFIG_CONSOLE_MUX
+ iomux_err = iomux_doenv(stdin, stdinname);
+ iomux_err += iomux_doenv(stdout, stdoutname);
+ iomux_err += iomux_doenv(stderr, stderrname);
+ if (!iomux_err)
+ /* Successful, so skip all the code below. */
+ goto done;
+#endif
+ }
+ /* if the devices are overwritten or not found, use default device */
+ if (inputdev == NULL) {
+ inputdev = search_device(DEV_FLAGS_INPUT, "serial");
+ }
+ if (outputdev == NULL) {
+ outputdev = search_device(DEV_FLAGS_OUTPUT, "serial");
+ }
+ if (errdev == NULL) {
+ errdev = search_device(DEV_FLAGS_OUTPUT, "serial");
+ }
+ /* Initializes output console first */
+ if (outputdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stdout, outputdev);
+ }
+ if (errdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stderr, errdev);
+ }
+ if (inputdev != NULL) {
+ /* need to set a console if not done above. */
+ console_doenv(stdin, inputdev);
+ }
+
+#ifdef CONFIG_CONSOLE_MUX
+done:
+#endif
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
+ stdio_print_current_devices();
+
+#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
+ /* set the environment variables (will overwrite previous env settings) */
+ for (i = 0; i < 3; i++) {
+ setenv(stdio_names[i], stdio_devices[i]->name);
+ }
+#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
+
+#if 0
+ /* If nothing usable installed, use only the initial console */
+ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
+ return 0;
+#endif
+ return 0;
+}
+
+#else /* CONFIG_SYS_CONSOLE_IS_IN_ENV */
+
+/* Called after the relocation - use desired console functions */
+int console_init_r(void)
+{
+ struct stdio_dev *inputdev = NULL, *outputdev = NULL;
+ int i;
+ struct list_head *list = stdio_get_list();
+ struct list_head *pos;
+ struct stdio_dev *dev;
+
+#ifdef CONFIG_SPLASH_SCREEN
+ /*
+ * suppress all output if splash screen is enabled and we have
+ * a bmp to display. We redirect the output from frame buffer
+ * console to serial console in this case or suppress it if
+ * "silent" mode was requested.
+ */
+ if (getenv("splashimage") != NULL) {
+ if (!(gd->flags & GD_FLG_SILENT))
+ outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
+ }
+#endif
+
+ /* Scan devices looking for input and output devices */
+ list_for_each(pos, list) {
+ dev = list_entry(pos, struct stdio_dev, list);
+
+ if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
+ inputdev = dev;
+ }
+ if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
+ outputdev = dev;
+ }
+ if(inputdev && outputdev)
+ break;
+ }
+
+ /* Initializes output console first */
+ if (outputdev != NULL) {
+ console_setfile(stdout, outputdev);
+ console_setfile(stderr, outputdev);
+#ifdef CONFIG_CONSOLE_MUX
+ console_devices[stdout][0] = outputdev;
+ console_devices[stderr][0] = outputdev;
+#endif
+ }
+
+ /* Initializes input console */
+ if (inputdev != NULL) {
+ console_setfile(stdin, inputdev);
+#ifdef CONFIG_CONSOLE_MUX
+ console_devices[stdin][0] = inputdev;
+#endif
+ }
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
+ stdio_print_current_devices();
+
+ /* Setting environment variables */
+ for (i = 0; i < 3; i++) {
+ setenv(stdio_names[i], stdio_devices[i]->name);
+ }
+
+#if 0
+ /* If nothing usable installed, use only the initial console */
+ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
+ return 0;
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_SYS_CONSOLE_IS_IN_ENV */
diff --git a/u-boot/common/ddr_spd.c b/u-boot/common/ddr_spd.c
new file mode 100644
index 0000000..a7a30de
--- /dev/null
+++ b/u-boot/common/ddr_spd.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <ddr_spd.h>
+
+/* used for ddr1 and ddr2 spd */
+static int
+spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum)
+{
+ unsigned int cksum = 0;
+ unsigned int i;
+
+ /*
+ * Check SPD revision supported
+ * Rev 1.2 or less supported by this code
+ */
+ if (spd_rev >= 0x20) {
+ printf("SPD revision %02X not supported by this code\n",
+ spd_rev);
+ return 1;
+ }
+ if (spd_rev > 0x13) {
+ printf("SPD revision %02X not verified by this code\n",
+ spd_rev);
+ }
+
+ /*
+ * Calculate checksum
+ */
+ for (i = 0; i < 63; i++) {
+ cksum += *buf++;
+ }
+ cksum &= 0xFF;
+
+ if (cksum != spd_cksum) {
+ printf("SPD checksum unexpected. "
+ "Checksum in SPD = %02X, computed SPD = %02X\n",
+ spd_cksum, cksum);
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned int
+ddr1_spd_check(const ddr1_spd_eeprom_t *spd)
+{
+ const u8 *p = (const u8 *)spd;
+
+ return spd_check(p, spd->spd_rev, spd->cksum);
+}
+
+unsigned int
+ddr2_spd_check(const ddr2_spd_eeprom_t *spd)
+{
+ const u8 *p = (const u8 *)spd;
+
+ return spd_check(p, spd->spd_rev, spd->cksum);
+}
+
+/*
+ * CRC16 compute for DDR3 SPD
+ * Copied from DDR3 SPD spec.
+ */
+static int
+crc16(char *ptr, int count)
+{
+ int crc, i;
+
+ crc = 0;
+ while (--count >= 0) {
+ crc = crc ^ (int)*ptr++ << 8;
+ for (i = 0; i < 8; ++i)
+ if (crc & 0x8000)
+ crc = crc << 1 ^ 0x1021;
+ else
+ crc = crc << 1;
+ }
+ return crc & 0xffff;
+}
+
+unsigned int
+ddr3_spd_check(const ddr3_spd_eeprom_t *spd)
+{
+ char *p = (char *)spd;
+ int csum16;
+ int len;
+ char crc_lsb; /* byte 126 */
+ char crc_msb; /* byte 127 */
+
+ /*
+ * SPD byte0[7] - CRC coverage
+ * 0 = CRC covers bytes 0~125
+ * 1 = CRC covers bytes 0~116
+ */
+
+ len = !(spd->info_size_crc & 0x80) ? 126 : 117;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->crc[0] == crc_lsb && spd->crc[1] == crc_msb) {
+ return 0;
+ } else {
+ printf("SPD checksum unexpected.\n"
+ "Checksum lsb in SPD = %02X, computed SPD = %02X\n"
+ "Checksum msb in SPD = %02X, computed SPD = %02X\n",
+ spd->crc[0], crc_lsb, spd->crc[1], crc_msb);
+ return 1;
+ }
+}
diff --git a/u-boot/common/dlmalloc.c b/u-boot/common/dlmalloc.c
new file mode 100644
index 0000000..e9bab09
--- /dev/null
+++ b/u-boot/common/dlmalloc.c
@@ -0,0 +1,3341 @@
+#include <common.h>
+
+#if 0 /* Moved to malloc.h */
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit when the request
+ size is treaded as a long will return null.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_MEMCPY (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined if not WIN32)
+ Define this if your system does not have a <unistd.h>.
+ LACKS_SYS_PARAM_H (default: undefined if not WIN32)
+ Define this if your system does not have a <sys/param.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 1)
+ True (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+ USE_DL_PREFIX (default: undefined)
+ Prefix all public routines with the string 'dl'. Useful to
+ quickly avoid procedure declaration conflicts and linker symbol
+ conflicts with existing memory allocation routines.
+
+
+*/
+
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+
+
+/*
+ Compile-time options
+*/
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#ifdef DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+ WIN32 causes an emulation of sbrk to be compiled in
+ mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+ Include 'windows.h' to get the necessary declarations for the
+ Microsoft Visual C++ data structures and routines used in the 'sbrk'
+ emulation.
+
+ Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+ Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
+/* 'windows.h' */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32
+# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+
+
+*/
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ Useful to quickly avoid procedure declaration conflicts and linker
+ symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc dlcalloc
+#define fREe dlfree
+#define mALLOc dlmalloc
+#define mEMALIGn dlmemalign
+#define rEALLOc dlrealloc
+#define vALLOc dlvalloc
+#define pvALLOc dlpvalloc
+#define mALLINFo dlmallinfo
+#define mALLOPt dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc calloc
+#define fREe free
+#define mALLOc malloc
+#define mEMALIGn memalign
+#define rEALLOc realloc
+#define vALLOc valloc
+#define pvALLOc pvalloc
+#define mALLINFo mallinfo
+#define mALLOPt mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void cfree(Void_t*);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats();
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void cfree();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+#endif /* 0 */ /* Moved to malloc.h */
+
+#include <malloc.h>
+#ifdef DEBUG
+#if __STD_C
+static void malloc_update_mallinfo (void);
+void malloc_stats (void);
+#else
+static void malloc_update_mallinfo ();
+void malloc_stats();
+#endif
+#endif /* DEBUG */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+
+ Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ assert (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ assert (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ assert (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ if (size >= TOP_MEMORY) return NULL;
+
+ while ((unsigned long)start_address + size < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+ return start_address;
+ else
+ {
+ /* Requested region is not available so see if the */
+ /* next region is available. Set 'start_address' */
+ /* to the next region and call 'VirtualQuery()' */
+ /* again. */
+
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+
+ /* Make sure we start looking for the next region */
+ /* on the *next* 64K boundary. Otherwise, even if */
+ /* the new region is free according to */
+ /* 'VirtualQuery()', the subsequent call to */
+ /* 'VirtualAlloc()' (which follows the call to */
+ /* this routine in 'wsbrk()') will round *down* */
+ /* the requested address to a 64K boundary which */
+ /* we already know is an address in the */
+ /* unavailable region. Thus, the subsequent call */
+ /* to 'VirtualAlloc()' will fail and bring us back */
+ /* here, causing us to go into an infinite loop. */
+
+ start_address =
+ (void *) AlignPage64K((unsigned long) start_address);
+ }
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (new_address == 0)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ /* repeat in case of race condition */
+ /* The region that we found has been snagged */
+ /* by another thread */
+ }
+ while (gAddressBase == 0);
+
+ assert (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (res == 0)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+
+struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+} __attribute__((__may_alias__)) ;
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+/* sizes, alignments */
+
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+#define MINSIZE (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (av_[2]) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+void malloc_bin_reloc (void)
+{
+ unsigned long *p = (unsigned long *)(&av_[2]);
+ int i;
+ for (i=2; i<(sizeof(av_)/sizeof(mbinptr)); ++i) {
+ *p++ += gd->reloc_off;
+ }
+}
+#endif
+
+ulong mem_malloc_start = 0;
+ulong mem_malloc_end = 0;
+ulong mem_malloc_brk = 0;
+
+void *sbrk(ptrdiff_t increment)
+{
+ ulong old = mem_malloc_brk;
+ ulong new = old + increment;
+
+ /*
+ * if we are giving memory back make sure we clear it out since
+ * we set MORECORE_CLEARS to 1
+ */
+ if (increment < 0)
+ memset((void *)new, 0, -increment);
+
+ if ((new < mem_malloc_start) || (new > mem_malloc_end))
+ return (void *)MORECORE_FAILURE;
+
+ mem_malloc_brk = new;
+
+ return (void *)old;
+}
+
+void mem_malloc_init(ulong start, ulong size)
+{
+ mem_malloc_start = start;
+ mem_malloc_end = start + size;
+ mem_malloc_brk = start;
+
+ memset((void *)mem_malloc_start, 0, size);
+}
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks_r ((INTERNAL_SIZE_T)av_[1]) /* bitvector of nonempty blocks */
+#define binblocks_w (av_[1])
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r | idx2binblock(ii)))
+#define clear_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r & ~(idx2binblock(ii))))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+#ifdef DEBUG
+static unsigned int n_mmaps = 0;
+#endif /* DEBUG */
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+
+
+/*
+ Debugging support
+*/
+
+#ifdef DEBUG
+
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+#if 0 /* causes warnings because assert() is off */
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+#endif /* 0 */
+
+ /* No checkable chunk is mmapped */
+ assert(!chunk_is_mmapped(p));
+
+ /* Check for legal address ... */
+ assert((char*)p >= sbrk_base);
+ if (p != top)
+ assert((char*)p + sz <= (char*)top);
+ else
+ assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+#if 0 /* causes warnings because assert() is off */
+ mchunkptr next = chunk_at_offset(p, sz);
+#endif /* 0 */
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ assert(!inuse(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next = next_chunk(p);
+ do_check_chunk(p);
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+ if (next == top)
+ {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+#if 0 /* causes warnings because assert() is off */
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ long room = sz - s;
+#endif /* 0 */
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((long)sz >= (long)MINSIZE);
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(room >= 0);
+ assert(room < (long)MINSIZE);
+
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+
+
+ /* ... and was allocated at front of an available chunk */
+ assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+ * there is no following chunk whose prev_size field could be used.
+ */
+ size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+ new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert((p->prev_size == offset));
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* brk; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_brk; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ brk = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (brk == (char*)(MORECORE_FAILURE) ||
+ (brk < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (brk == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = brk;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += brk - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (MALLOC_ALIGNMENT) - front_misalign;
+ brk += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+
+ correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+ ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+ /* Allocate correction */
+ new_brk = (char*)(MORECORE (correction));
+ if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)brk;
+ top_size = new_brk - brk + correction;
+ set_head(top, top_size | PREV_INUSE);
+
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ /* Also keep size a multiple of MALLOC_ALIGNMENT */
+ old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head_size(old_top, old_top_size);
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE)
+ fREe(chunk2mem(old_top));
+ }
+ }
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb;
+
+ /* check if mem_malloc_init() was run */
+ if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
+ /* not initialized yet */
+ return 0;
+ }
+
+ if ((long)bytes < 0) return 0;
+
+ nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks_r)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks_r) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks_r) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ unlink(victim, bck, fwd);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ av_[1] = (mbinptr)(binblocks_r & ~block);
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks_r && (block != 0) )
+ {
+ while ((block & binblocks_r) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0)
+ return chunk2mem(victim);
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return 0; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ check_inuse_chunk(p);
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+ if ((long)bytes < 0) return 0;
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if(newp) return chunk2mem(newp);
+#endif
+ /* Note the extra SIZE_SZ overhead. */
+ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ check_inuse_chunk(oldp);
+
+ if ((long)(oldsize) < (long)(nb))
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(oldp, nb);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(newp, nb);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ if ((long)bytes < 0) return 0;
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ return chunk2mem(p); /* nothing more to do */
+#endif
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+ if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if ((long)n < 0) return 0;
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ MALLOC_ZERO(mem, csz - SIZE_SZ);
+ return mem;
+ }
+}
+
+/*
+
+ cfree just calls free. It is needed/defined on some systems
+ that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+#endif
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+ /* Test to make sure no one else called sbrk */
+ current_brk = (char*)(MORECORE (0));
+ if (current_brk != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+ {
+ new_brk = (char*)(MORECORE (-extra));
+
+ if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_brk = (char*)(MORECORE (0));
+ top_size = current_brk - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_brk - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ check_inuse_chunk(p);
+ return chunksize(p) - SIZE_SZ;
+ }
+ return chunksize(p) - 2*SIZE_SZ;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+#ifdef DEBUG
+static void malloc_update_mallinfo()
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#ifdef DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#ifdef DEBUG
+ check_free_chunk(p);
+ for (q = next_chunk(p);
+ q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+#endif /* DEBUG */
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+#ifdef DEBUG
+void malloc_stats()
+{
+ malloc_update_mallinfo();
+ printf("max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ printf("system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ printf("in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ printf("max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+#endif /* DEBUG */
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+#ifdef DEBUG
+struct mallinfo mALLINFo()
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+#endif /* DEBUG */
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup up header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/u-boot/common/dlmalloc.src b/u-boot/common/dlmalloc.src
new file mode 100644
index 0000000..32a38bc
--- /dev/null
+++ b/u-boot/common/dlmalloc.src
@@ -0,0 +1,3265 @@
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit when the request
+ size is treaded as a long will return null.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_MEMCPY (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined if not WIN32)
+ Define this if your system does not have a <unistd.h>.
+ LACKS_SYS_PARAM_H (default: undefined if not WIN32)
+ Define this if your system does not have a <sys/param.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 1)
+ True (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+ USE_DL_PREFIX (default: undefined)
+ Prefix all public routines with the string 'dl'. Useful to
+ quickly avoid procedure declaration conflicts and linker symbol
+ conflicts with existing memory allocation routines.
+
+
+*/
+
+
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+
+
+/*
+ Compile-time options
+*/
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+ WIN32 causes an emulation of sbrk to be compiled in
+ mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+ Include 'windows.h' to get the necessary declarations for the
+ Microsoft Visual C++ data structures and routines used in the 'sbrk'
+ emulation.
+
+ Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+ Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
+/* 'windows.h' */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32
+# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+
+
+*/
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ Useful to quickly avoid procedure declaration conflicts and linker
+ symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc dlcalloc
+#define fREe dlfree
+#define mALLOc dlmalloc
+#define mEMALIGn dlmemalign
+#define rEALLOc dlrealloc
+#define vALLOc dlvalloc
+#define pvALLOc dlpvalloc
+#define mALLINFo dlmallinfo
+#define mALLOPt dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc calloc
+#define fREe free
+#define mALLOc malloc
+#define mEMALIGn memalign
+#define rEALLOc realloc
+#define vALLOc valloc
+#define pvALLOc pvalloc
+#define mALLINFo mallinfo
+#define mALLOPt mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void cfree(Void_t*);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats();
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void cfree();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+
+ Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ assert (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ assert (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ assert (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ if (size >= TOP_MEMORY) return NULL;
+
+ while ((unsigned long)start_address + size < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+ return start_address;
+ else
+ {
+ /* Requested region is not available so see if the */
+ /* next region is available. Set 'start_address' */
+ /* to the next region and call 'VirtualQuery()' */
+ /* again. */
+
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+
+ /* Make sure we start looking for the next region */
+ /* on the *next* 64K boundary. Otherwise, even if */
+ /* the new region is free according to */
+ /* 'VirtualQuery()', the subsequent call to */
+ /* 'VirtualAlloc()' (which follows the call to */
+ /* this routine in 'wsbrk()') will round *down* */
+ /* the requested address to a 64K boundary which */
+ /* we already know is an address in the */
+ /* unavailable region. Thus, the subsequent call */
+ /* to 'VirtualAlloc()' will fail and bring us back */
+ /* here, causing us to go into an infinite loop. */
+
+ start_address =
+ (void *) AlignPage64K((unsigned long) start_address);
+ }
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (new_address == 0)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ /* repeat in case of race condition */
+ /* The region that we found has been snagged */
+ /* by another thread */
+ }
+ while (gAddressBase == 0);
+
+ assert (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (res == 0)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+
+struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+
+
+/* sizes, alignments */
+
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+#define MINSIZE (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (bin_at(0)->fd) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned int max_n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+static unsigned long max_mmapped_mem = 0;
+
+
+
+/*
+ Debugging support
+*/
+
+#if DEBUG
+
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ /* No checkable chunk is mmapped */
+ assert(!chunk_is_mmapped(p));
+
+ /* Check for legal address ... */
+ assert((char*)p >= sbrk_base);
+ if (p != top)
+ assert((char*)p + sz <= (char*)top);
+ else
+ assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ assert(!inuse(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next = next_chunk(p);
+ do_check_chunk(p);
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+ if (next == top)
+ {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((long)sz >= (long)MINSIZE);
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(room >= 0);
+ assert(room < (long)MINSIZE);
+
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+
+
+ /* ... and was allocated at front of an available chunk */
+ assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+ * there is no following chunk whose prev_size field could be used.
+ */
+ size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+ new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert((p->prev_size == offset));
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* brk; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_brk; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ brk = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (brk == (char*)(MORECORE_FAILURE) ||
+ (brk < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (brk == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = brk;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += brk - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (MALLOC_ALIGNMENT) - front_misalign;
+ brk += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+
+ correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+ ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+ /* Allocate correction */
+ new_brk = (char*)(MORECORE (correction));
+ if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)brk;
+ top_size = new_brk - brk + correction;
+ set_head(top, top_size | PREV_INUSE);
+
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ /* Also keep size a multiple of MALLOC_ALIGNMENT */
+ old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head_size(old_top, old_top_size);
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE)
+ fREe(chunk2mem(old_top));
+ }
+ }
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb;
+
+ if ((long)bytes < 0) return 0;
+
+ nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ unlink(victim, bck, fwd);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ binblocks &= ~block;
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks && (block != 0) )
+ {
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0)
+ return chunk2mem(victim);
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return 0; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ check_inuse_chunk(p);
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -((long) prevsz));
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+ if ((long)bytes < 0) return 0;
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if(newp) return chunk2mem(newp);
+#endif
+ /* Note the extra SIZE_SZ overhead. */
+ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ check_inuse_chunk(oldp);
+
+ if ((long)(oldsize) < (long)(nb))
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(oldp, nb);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(newp, nb);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ if ((long)bytes < 0) return 0;
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ return chunk2mem(p); /* nothing more to do */
+#endif
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+ if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if ((long)n < 0) return 0;
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ MALLOC_ZERO(mem, csz - SIZE_SZ);
+ return mem;
+ }
+}
+
+/*
+
+ cfree just calls free. It is needed/defined on some systems
+ that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+#endif
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+ /* Test to make sure no one else called sbrk */
+ current_brk = (char*)(MORECORE (0));
+ if (current_brk != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+ {
+ new_brk = (char*)(MORECORE (-extra));
+
+ if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_brk = (char*)(MORECORE (0));
+ top_size = current_brk - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_brk - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ check_inuse_chunk(p);
+ return chunksize(p) - SIZE_SZ;
+ }
+ return chunksize(p) - 2*SIZE_SZ;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo()
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#if DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#if DEBUG
+ check_free_chunk(p);
+ for (q = next_chunk(p);
+ q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on stderr the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+void malloc_stats()
+{
+ malloc_update_mallinfo();
+ fprintf(stderr, "max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ fprintf(stderr, "system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ fprintf(stderr, "in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ fprintf(stderr, "max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo()
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup up header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/u-boot/common/env_common.c b/u-boot/common/env_common.c
new file mode 100644
index 0000000..c3e6388
--- /dev/null
+++ b/u-boot/common/env_common.c
@@ -0,0 +1,278 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * 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 <environment.h>
+#include <linux/stddef.h>
+#include <search.h>
+#include <errno.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern env_t *env_ptr;
+
+extern void env_relocate_spec (void);
+extern uchar env_get_char_spec(int);
+
+static uchar env_get_char_init (int index);
+
+/************************************************************************
+ * Default settings to be used when no valid environment is found
+ */
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+
+uchar default_environment[] = {
+#ifdef CONFIG_BOOTARGS
+ "bootargs=" CONFIG_BOOTARGS "\0"
+#endif
+#ifdef CONFIG_BOOTCOMMAND
+ "bootcmd=" CONFIG_BOOTCOMMAND "\0"
+#endif
+#ifdef CONFIG_RAMBOOTCOMMAND
+ "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
+#endif
+#ifdef CONFIG_NFSBOOTCOMMAND
+ "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+ "baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
+#endif
+#ifdef CONFIG_LOADS_ECHO
+ "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
+#endif
+#ifdef CONFIG_ETHADDR
+ "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
+#endif
+#ifdef CONFIG_ETH1ADDR
+ "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH2ADDR
+ "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH3ADDR
+ "eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH4ADDR
+ "eth4addr=" MK_STR(CONFIG_ETH4ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH5ADDR
+ "eth5addr=" MK_STR(CONFIG_ETH5ADDR) "\0"
+#endif
+#ifdef CONFIG_IPADDR
+ "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
+#endif
+#ifdef CONFIG_SERVERIP
+ "serverip=" MK_STR(CONFIG_SERVERIP) "\0"
+#endif
+#ifdef CONFIG_SYS_AUTOLOAD
+ "autoload=" CONFIG_SYS_AUTOLOAD "\0"
+#endif
+#ifdef CONFIG_PREBOOT
+ "preboot=" CONFIG_PREBOOT "\0"
+#endif
+#ifdef CONFIG_ROOTPATH
+ "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
+#endif
+#ifdef CONFIG_GATEWAYIP
+ "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
+#endif
+#ifdef CONFIG_NETMASK
+ "netmask=" MK_STR(CONFIG_NETMASK) "\0"
+#endif
+#ifdef CONFIG_HOSTNAME
+ "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
+#endif
+#ifdef CONFIG_BOOTFILE
+ "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
+#endif
+#ifdef CONFIG_LOADADDR
+ "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
+#endif
+#ifdef CONFIG_CLOCKS_IN_MHZ
+ "clocks_in_mhz=1\0"
+#endif
+#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
+ "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
+#endif
+#ifdef CONFIG_EXTRA_ENV_SETTINGS
+ CONFIG_EXTRA_ENV_SETTINGS
+#endif
+ "\0"
+};
+
+struct hsearch_data env_htab;
+
+static uchar env_get_char_init (int index)
+{
+ uchar c;
+
+ /* if crc was bad, use the default environment */
+ if (gd->env_valid)
+ c = env_get_char_spec(index);
+ else
+ c = default_environment[index];
+
+ return (c);
+}
+
+uchar env_get_char_memory (int index)
+{
+ return *env_get_addr(index);
+}
+
+uchar env_get_char (int index)
+{
+ uchar c;
+
+ /* if relocated to RAM */
+ if (gd->flags & GD_FLG_RELOC)
+ c = env_get_char_memory(index);
+ else
+ c = env_get_char_init(index);
+
+ return (c);
+}
+
+uchar *env_get_addr (int index)
+{
+ if (gd->env_valid)
+ return (uchar *)(gd->env_addr + index);
+ else
+ return &default_environment[index];
+}
+
+void set_default_env(const char *s)
+{
+ if (sizeof(default_environment) > ENV_SIZE) {
+ puts("*** Error - default environment is too large\n\n");
+ return;
+ }
+
+ if (s) {
+ if (*s == '!') {
+ printf("*** Warning - %s, "
+ "using default environment\n\n",
+ s+1);
+ } else {
+ puts(s);
+ }
+ } else {
+ puts("Using default environment\n\n");
+ }
+
+ if (himport_r(&env_htab, (char *)default_environment,
+ sizeof(default_environment), '\0', 0) == 0) {
+ error("Environment import failed: errno = %d\n", errno);
+ }
+ gd->flags |= GD_FLG_ENV_READY;
+}
+
+/*
+ * Check if CRC is valid and (if yes) import the environment.
+ * Note that "buf" may or may not be aligned.
+ */
+int env_import(const char *buf, int check)
+{
+ env_t *ep = (env_t *)buf;
+
+ if (check) {
+ uint32_t crc;
+
+ memcpy(&crc, &ep->crc, sizeof(crc));
+
+ if (crc32(0, ep->data, ENV_SIZE) != crc) {
+ set_default_env("!bad CRC");
+ return 0;
+ }
+ }
+
+ if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0)) {
+ gd->flags |= GD_FLG_ENV_READY;
+ return 1;
+ }
+
+ error("Cannot import environment: errno = %d\n", errno);
+
+ set_default_env("!import failed");
+
+ return 0;
+}
+
+void env_relocate (void)
+{
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ extern void env_reloc(void);
+
+ env_reloc();
+#endif
+ if (gd->env_valid == 0) {
+#if defined(CONFIG_ENV_IS_NOWHERE) /* Environment not changable */
+ set_default_env(NULL);
+#else
+ show_boot_progress (-60);
+ set_default_env("!bad CRC");
+#endif
+ } else {
+ env_relocate_spec ();
+ }
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
+{
+ ENTRY *match;
+ int found, idx;
+
+ idx = 0;
+ found = 0;
+ cmdv[0] = NULL;
+
+ while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
+ int vallen = strlen(match->key) + 1;
+
+ if (found >= maxv - 2 || bufsz < vallen)
+ break;
+
+ cmdv[found++] = buf;
+ memcpy(buf, match->key, vallen);
+ buf += vallen;
+ bufsz -= vallen;
+ }
+
+ qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
+
+ if (idx)
+ cmdv[found++] = "...";
+ cmdv[found] = NULL;
+ return found;
+}
+#endif
diff --git a/u-boot/common/env_dataflash.c b/u-boot/common/env_dataflash.c
new file mode 100644
index 0000000..1d57079
--- /dev/null
+++ b/u-boot/common/env_dataflash.c
@@ -0,0 +1,126 @@
+/*
+ * LowLevel function for DataFlash environment support
+ * Author : Gilles Gastaldi (Atmel)
+ *
+ * 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 <environment.h>
+#include <linux/stddef.h>
+#include <dataflash.h>
+#include <search.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+env_t *env_ptr = NULL;
+
+char * env_name_spec = "dataflash";
+
+extern int read_dataflash(unsigned long addr, unsigned long size,
+ char *result);
+extern int write_dataflash(unsigned long addr_dest,
+ unsigned long addr_src, unsigned long size);
+extern int AT91F_DataflashInit(void);
+
+extern uchar default_environment[];
+
+uchar env_get_char_spec(int index)
+{
+ uchar c;
+
+ read_dataflash(CONFIG_ENV_ADDR + index + offsetof(env_t,data),
+ 1, (char *)&c);
+ return (c);
+}
+
+void env_relocate_spec(void)
+{
+ char buf[CONFIG_ENV_SIZE];
+
+ read_dataflash(CONFIG_ENV_ADDR, CONFIG_ENV_SIZE, buf);
+
+ env_import(buf, 1);
+}
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+#error No support for redundant environment on dataflash yet!
+#endif
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+ return write_dataflash(CONFIG_ENV_ADDR,
+ (unsigned long)&env_new,
+ CONFIG_ENV_SIZE);
+}
+
+/*
+ * Initialize environment use
+ *
+ * We are still running from ROM, so data use is limited.
+ * Use a (moderately small) buffer on the stack
+ */
+int env_init(void)
+{
+ ulong crc, len, new;
+ unsigned off;
+ uchar buf[64];
+
+ if (gd->env_valid)
+ return 0;
+
+ AT91F_DataflashInit(); /* prepare for DATAFLASH read/write */
+
+ /* read old CRC */
+ read_dataflash(CONFIG_ENV_ADDR + offsetof(env_t, crc),
+ sizeof(ulong), (char *)&crc);
+
+ new = 0;
+ len = ENV_SIZE;
+ off = offsetof(env_t,data);
+ while (len > 0) {
+ int n = (len > sizeof(buf)) ? sizeof(buf) : len;
+
+ read_dataflash(CONFIG_ENV_ADDR + off, n, (char *)buf);
+
+ new = crc32 (new, buf, n);
+ len -= n;
+ off += n;
+ }
+
+ if (crc == new) {
+ gd->env_addr = offsetof(env_t,data);
+ gd->env_valid = 1;
+ } else {
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+ }
+
+ return 0;
+}
diff --git a/u-boot/common/env_eeprom.c b/u-boot/common/env_eeprom.c
new file mode 100644
index 0000000..0a179ad
--- /dev/null
+++ b/u-boot/common/env_eeprom.c
@@ -0,0 +1,303 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * 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 <environment.h>
+#include <linux/stddef.h>
+#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
+#include <i2c.h>
+#endif
+#include <search.h>
+#include <errno.h>
+#include <linux/compiler.h> /* for BUG_ON */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+env_t *env_ptr = NULL;
+
+char *env_name_spec = "EEPROM";
+int env_eeprom_bus = -1;
+
+static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
+ uchar *buffer, unsigned cnt)
+{
+ int rcode;
+#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
+ int old_bus = i2c_get_bus_num();
+
+ if (gd->flags & GD_FLG_RELOC) {
+ if (env_eeprom_bus == -1) {
+ I2C_MUX_DEVICE *dev = NULL;
+ dev = i2c_mux_ident_muxstring(
+ (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
+ if (dev != NULL)
+ env_eeprom_bus = dev->busid;
+ else
+ printf ("error adding env eeprom bus.\n");
+ }
+ if (old_bus != env_eeprom_bus) {
+ i2c_set_bus_num(env_eeprom_bus);
+ old_bus = env_eeprom_bus;
+ }
+ } else {
+ rcode = i2c_mux_ident_muxstring_f(
+ (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
+ }
+#endif
+
+ rcode = eeprom_read (dev_addr, offset, buffer, cnt);
+
+#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
+ if (old_bus != env_eeprom_bus)
+ i2c_set_bus_num(old_bus);
+#endif
+ return rcode;
+}
+
+static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
+ uchar *buffer, unsigned cnt)
+{
+ int rcode;
+#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
+ int old_bus = i2c_get_bus_num();
+
+ rcode = i2c_mux_ident_muxstring_f((uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
+#endif
+ rcode = eeprom_write(dev_addr, offset, buffer, cnt);
+#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
+ i2c_set_bus_num(old_bus);
+#endif
+ return rcode;
+}
+
+uchar env_get_char_spec (int index)
+{
+ uchar c;
+ unsigned int off;
+ off = CONFIG_ENV_OFFSET;
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ if (gd->env_valid == 2)
+ off = CONFIG_ENV_OFFSET_REDUND;
+#endif
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off + index + offsetof(env_t,data),
+ &c, 1);
+
+ return (c);
+}
+
+void env_relocate_spec (void)
+{
+ char buf[CONFIG_ENV_SIZE];
+ unsigned int off = CONFIG_ENV_OFFSET;
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ if (gd->env_valid == 2)
+ off = CONFIG_ENV_OFFSET_REDUND;
+#endif
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off,
+ (uchar *)buf,
+ CONFIG_ENV_SIZE);
+
+ env_import(buf, 1);
+}
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ int rc;
+ unsigned int off = CONFIG_ENV_OFFSET;
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
+ char flag_obsolete = OBSOLETE_FLAG;
+#endif
+
+ BUG_ON(env_ptr != NULL);
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ if (gd->env_valid == 1) {
+ off = CONFIG_ENV_OFFSET_REDUND;
+ off_red = CONFIG_ENV_OFFSET;
+ }
+
+ env_new.flags = ACTIVE_FLAG;
+#endif
+
+ rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off,
+ (uchar *)&env_new,
+ CONFIG_ENV_SIZE);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ if (rc == 0) {
+ eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off_red + offsetof(env_t,flags),
+ (uchar *)&flag_obsolete,
+ 1);
+ if (gd->env_valid == 1)
+ gd->env_valid = 2;
+ else
+ gd->env_valid = 1;
+
+ }
+#endif
+
+ return rc;
+}
+
+/*
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited.
+ * Use a (moderately small) buffer on the stack
+ */
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+int env_init(void)
+{
+ ulong len;
+ ulong crc[2], crc_tmp;
+ unsigned int off, off_env[2];
+ uchar buf[64];
+ int crc_ok[2] = {0,0};
+ unsigned char flags[2];
+ int i;
+
+ eeprom_init(); /* prepare for EEPROM read/write */
+
+ off_env[0] = CONFIG_ENV_OFFSET;
+ off_env[1] = CONFIG_ENV_OFFSET_REDUND;
+
+ for (i = 0; i < 2; i++) {
+ /* read CRC */
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off_env[i] + offsetof(env_t,crc),
+ (uchar *)&crc[i], sizeof(ulong));
+ /* read FLAGS */
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ off_env[i] + offsetof(env_t,flags),
+ (uchar *)&flags[i], sizeof(uchar));
+
+ crc_tmp = 0;
+ len = ENV_SIZE;
+ off = off_env[i] + offsetof(env_t,data);
+ while (len > 0) {
+ int n = (len > sizeof(buf)) ? sizeof(buf) : len;
+
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
+ buf, n);
+
+ crc_tmp = crc32(crc_tmp, buf, n);
+ len -= n;
+ off += n;
+ }
+ if (crc_tmp == crc[i])
+ crc_ok[i] = 1;
+ }
+
+ if (!crc_ok[0] && !crc_ok[1]) {
+ gd->env_addr = 0;
+ gd->env_valid = 0;
+
+ return 0;
+ } else if (crc_ok[0] && !crc_ok[1]) {
+ gd->env_valid = 1;
+ }
+ else if (!crc_ok[0] && crc_ok[1]) {
+ gd->env_valid = 2;
+ } else {
+ /* both ok - check serial */
+ if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
+ gd->env_valid = 1;
+ else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
+ gd->env_valid = 2;
+ else if (flags[0] == 0xFF && flags[1] == 0)
+ gd->env_valid = 2;
+ else if(flags[1] == 0xFF && flags[0] == 0)
+ gd->env_valid = 1;
+ else /* flags are equal - almost impossible */
+ gd->env_valid = 1;
+ }
+
+ if (gd->env_valid == 2)
+ gd->env_addr = off_env[1] + offsetof(env_t,data);
+ else if (gd->env_valid == 1)
+ gd->env_addr = off_env[0] + offsetof(env_t,data);
+
+ return (0);
+}
+#else
+int env_init(void)
+{
+ ulong crc, len, new;
+ unsigned off;
+ uchar buf[64];
+
+ eeprom_init(); /* prepare for EEPROM read/write */
+
+ /* read old CRC */
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ CONFIG_ENV_OFFSET+offsetof(env_t,crc),
+ (uchar *)&crc, sizeof(ulong));
+
+ new = 0;
+ len = ENV_SIZE;
+ off = offsetof(env_t,data);
+
+ while (len > 0) {
+ int n = (len > sizeof(buf)) ? sizeof(buf) : len;
+
+ eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
+ CONFIG_ENV_OFFSET + off, buf, n);
+ new = crc32(new, buf, n);
+ len -= n;
+ off += n;
+ }
+
+ if (crc == new) {
+ gd->env_addr = offsetof(env_t,data);
+ gd->env_valid = 1;
+ } else {
+ gd->env_addr = 0;
+ gd->env_valid = 0;
+ }
+
+ return (0);
+}
+#endif
diff --git a/u-boot/common/env_embedded.c b/u-boot/common/env_embedded.c
new file mode 100644
index 0000000..ae6cac4
--- /dev/null
+++ b/u-boot/common/env_embedded.c
@@ -0,0 +1,214 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* Dirty trick to get only #defines */
+#endif
+#define __ASM_STUB_PROCESSOR_H__ /* don't include asm/processor. */
+#include <config.h>
+#undef __ASSEMBLY__
+#include <environment.h>
+
+/*
+ * Handle HOSTS that have prepended
+ * crap on symbol names, not TARGETS.
+ */
+#if defined(__APPLE__)
+/* Leading underscore on symbols */
+# define SYM_CHAR "_"
+#else /* No leading character on symbols */
+# define SYM_CHAR
+#endif
+
+/*
+ * Generate embedded environment table
+ * inside U-Boot image, if needed.
+ */
+#if defined(ENV_IS_EMBEDDED)
+/*
+ * Only put the environment in it's own section when we are building
+ * U-Boot proper. The host based program "tools/envcrc" does not need
+ * a seperate section. Note that ENV_CRC is only defined when building
+ * U-Boot itself.
+ */
+#if (defined(CONFIG_SYS_USE_PPCENV) || defined(CONFIG_NAND_U_BOOT)) && \
+ defined(ENV_CRC) /* Environment embedded in U-Boot .ppcenv section */
+/* XXX - This only works with GNU C */
+# define __PPCENV__ __attribute__ ((section(".ppcenv")))
+# define __PPCTEXT__ __attribute__ ((section(".text")))
+
+#elif defined(USE_HOSTCC) /* Native for 'tools/envcrc' */
+# define __PPCENV__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+# define __PPCTEXT__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+
+#else /* Environment is embedded in U-Boot's .text section */
+/* XXX - This only works with GNU C */
+# define __PPCENV__ __attribute__ ((section(".text")))
+# define __PPCTEXT__ __attribute__ ((section(".text")))
+#endif
+
+/*
+ * Macros to generate global absolutes.
+ */
+#if defined(__bfin__)
+# define GEN_SET_VALUE(name, value) asm (".set " GEN_SYMNAME(name) ", " GEN_VALUE(value))
+#else
+# define GEN_SET_VALUE(name, value) asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
+#endif
+#define GEN_SYMNAME(str) SYM_CHAR #str
+#define GEN_VALUE(str) #str
+#define GEN_ABS(name, value) \
+ asm (".globl " GEN_SYMNAME(name)); \
+ GEN_SET_VALUE(name, value)
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+
+/*
+ * Check to see if we are building with a
+ * computed CRC. Otherwise define it as ~0.
+ */
+#if !defined(ENV_CRC)
+# define ENV_CRC ~0
+#endif
+
+env_t environment __PPCENV__ = {
+ ENV_CRC, /* CRC Sum */
+#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
+ 1, /* Flags: valid */
+#endif
+ {
+#if defined(CONFIG_BOOTARGS)
+ "bootargs=" CONFIG_BOOTARGS "\0"
+#endif
+#if defined(CONFIG_BOOTCOMMAND)
+ "bootcmd=" CONFIG_BOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_RAMBOOTCOMMAND)
+ "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_NFSBOOTCOMMAND)
+ "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+ "baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
+#endif
+#ifdef CONFIG_LOADS_ECHO
+ "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
+#endif
+#ifdef CONFIG_ETHADDR
+ "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
+#endif
+#ifdef CONFIG_ETH1ADDR
+ "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH2ADDR
+ "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH3ADDR
+ "eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH4ADDR
+ "eth4addr=" MK_STR(CONFIG_ETH4ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH5ADDR
+ "eth5addr=" MK_STR(CONFIG_ETH5ADDR) "\0"
+#endif
+#ifdef CONFIG_ETHPRIME
+ "ethprime=" CONFIG_ETHPRIME "\0"
+#endif
+#ifdef CONFIG_IPADDR
+ "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
+#endif
+#ifdef CONFIG_SERVERIP
+ "serverip=" MK_STR(CONFIG_SERVERIP) "\0"
+#endif
+#ifdef CONFIG_SYS_AUTOLOAD
+ "autoload=" CONFIG_SYS_AUTOLOAD "\0"
+#endif
+#ifdef CONFIG_ROOTPATH
+ "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
+#endif
+#ifdef CONFIG_GATEWAYIP
+ "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
+#endif
+#ifdef CONFIG_NETMASK
+ "netmask=" MK_STR(CONFIG_NETMASK) "\0"
+#endif
+#ifdef CONFIG_HOSTNAME
+ "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
+#endif
+#ifdef CONFIG_BOOTFILE
+ "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
+#endif
+#ifdef CONFIG_LOADADDR
+ "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
+#endif
+#ifdef CONFIG_PREBOOT
+ "preboot=" CONFIG_PREBOOT "\0"
+#endif
+#ifdef CONFIG_CLOCKS_IN_MHZ
+ "clocks_in_mhz=" "1" "\0"
+#endif
+#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
+ "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
+#endif
+#ifdef CONFIG_EXTRA_ENV_SETTINGS
+ CONFIG_EXTRA_ENV_SETTINGS
+#endif
+ "\0" /* Term. env_t.data with 2 NULs */
+ }
+};
+#ifdef CONFIG_ENV_ADDR_REDUND
+env_t redundand_environment __PPCENV__ = {
+ 0, /* CRC Sum: invalid */
+ 0, /* Flags: invalid */
+ {
+ "\0"
+ }
+};
+#endif /* CONFIG_ENV_ADDR_REDUND */
+
+/*
+ * These will end up in the .text section
+ * if the environment strings are embedded
+ * in the image. When this is used for
+ * tools/envcrc, they are placed in the
+ * .data/.sdata section.
+ *
+ */
+unsigned long env_size __PPCTEXT__ = sizeof(env_t);
+
+/*
+ * Add in absolutes.
+ */
+GEN_ABS(env_offset, CONFIG_ENV_OFFSET);
+
+#endif /* ENV_IS_EMBEDDED */
diff --git a/u-boot/common/env_flash.c b/u-boot/common/env_flash.c
new file mode 100644
index 0000000..456f2e8
--- /dev/null
+++ b/u-boot/common/env_flash.c
@@ -0,0 +1,380 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+
+ * 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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <search.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_FLASH)
+#define CMD_SAVEENV
+#elif defined(CONFIG_ENV_ADDR_REDUND)
+#error Cannot use CONFIG_ENV_ADDR_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_FLASH
+#endif
+
+#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE)
+#error CONFIG_ENV_SIZE_REDUND should not be less then CONFIG_ENV_SIZE
+#endif
+
+char * env_name_spec = "Flash";
+
+#ifdef ENV_IS_EMBEDDED
+
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+
+static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
+
+#else /* ! ENV_IS_EMBEDDED */
+
+env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
+static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
+
+#endif /* ENV_IS_EMBEDDED */
+
+#if defined(CMD_SAVEENV) || defined(CONFIG_ENV_ADDR_REDUND)
+/* CONFIG_ENV_ADDR is supposed to be on sector boundary */
+static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1;
+#endif
+
+#ifdef CONFIG_ENV_ADDR_REDUND
+static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND;
+
+/* CONFIG_ENV_ADDR_REDUND is supposed to be on sector boundary */
+static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1;
+#endif /* CONFIG_ENV_ADDR_REDUND */
+
+extern uchar default_environment[];
+
+
+uchar env_get_char_spec(int index)
+{
+ return (*((uchar *)(gd->env_addr + index)));
+}
+
+#ifdef CONFIG_ENV_ADDR_REDUND
+
+int env_init(void)
+{
+ int crc1_ok = 0, crc2_ok = 0;
+
+ uchar flag1 = flash_addr->flags;
+ uchar flag2 = flash_addr_new->flags;
+
+ ulong addr_default = (ulong)&default_environment[0];
+ ulong addr1 = (ulong)&(flash_addr->data);
+ ulong addr2 = (ulong)&(flash_addr_new->data);
+
+ crc1_ok = (crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
+ crc2_ok = (crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
+
+ if (crc1_ok && ! crc2_ok) {
+ gd->env_addr = addr1;
+ gd->env_valid = 1;
+ } else if (! crc1_ok && crc2_ok) {
+ gd->env_addr = addr2;
+ gd->env_valid = 1;
+ } else if (! crc1_ok && ! crc2_ok) {
+ gd->env_addr = addr_default;
+ gd->env_valid = 0;
+ } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
+ gd->env_addr = addr1;
+ gd->env_valid = 1;
+ } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
+ gd->env_addr = addr2;
+ gd->env_valid = 1;
+ } else if (flag1 == flag2) {
+ gd->env_addr = addr1;
+ gd->env_valid = 2;
+ } else if (flag1 == 0xFF) {
+ gd->env_addr = addr1;
+ gd->env_valid = 2;
+ } else if (flag2 == 0xFF) {
+ gd->env_addr = addr2;
+ gd->env_valid = 2;
+ }
+
+ return 0;
+}
+
+#ifdef CMD_SAVEENV
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *saved_data = NULL;
+ char *res;
+ int rc = 1;
+ char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+ ulong up_data = 0;
+#endif
+
+ debug("Protect off %08lX ... %08lX\n",
+ (ulong)flash_addr, end_addr);
+
+ if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) {
+ goto done;
+ }
+
+ debug("Protect off %08lX ... %08lX\n",
+ (ulong)flash_addr_new, end_addr_new);
+
+ if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) {
+ goto done;
+ }
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ goto done;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+ env_new.flags = new_flag;
+
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+ up_data = (end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE));
+ debug("Data to save 0x%lX\n", up_data);
+ if (up_data) {
+ if ((saved_data = malloc(up_data)) == NULL) {
+ printf("Unable to save the rest of sector (%ld)\n",
+ up_data);
+ goto done;
+ }
+ memcpy(saved_data,
+ (void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data);
+ debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n",
+ (long)flash_addr_new + CONFIG_ENV_SIZE,
+ up_data, saved_data);
+ }
+#endif
+ puts("Erasing Flash...");
+ debug(" %08lX ... %08lX ...",
+ (ulong)flash_addr_new, end_addr_new);
+
+ if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) {
+ goto done;
+ }
+
+ puts("Writing to Flash... ");
+ debug(" %08lX ... %08lX ...",
+ (ulong)&(flash_addr_new->data),
+ sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
+ if ((rc = flash_write((char *)&env_new,
+ (ulong)flash_addr_new,
+ sizeof(env_new))) ||
+ (rc = flash_write(&flag,
+ (ulong)&(flash_addr->flags),
+ sizeof(flash_addr->flags))) ) {
+ flash_perror(rc);
+ goto done;
+ }
+
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+ if (up_data) { /* restore the rest of sector */
+ debug("Restoring the rest of data to 0x%lX len 0x%lX\n",
+ (long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
+ if (flash_write(saved_data,
+ (long)flash_addr_new + CONFIG_ENV_SIZE,
+ up_data)) {
+ flash_perror(rc);
+ goto done;
+ }
+ }
+#endif
+ puts("done\n");
+
+ {
+ env_t * etmp = flash_addr;
+ ulong ltmp = end_addr;
+
+ flash_addr = flash_addr_new;
+ flash_addr_new = etmp;
+
+ end_addr = end_addr_new;
+ end_addr_new = ltmp;
+ }
+
+ rc = 0;
+done:
+ if (saved_data)
+ free(saved_data);
+ /* try to re-protect */
+ (void) flash_sect_protect(1, (ulong)flash_addr, end_addr);
+ (void) flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
+
+ return rc;
+}
+#endif /* CMD_SAVEENV */
+
+#else /* ! CONFIG_ENV_ADDR_REDUND */
+
+int env_init(void)
+{
+ if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+ gd->env_addr = (ulong)&(env_ptr->data);
+ gd->env_valid = 1;
+ return(0);
+ }
+
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+ return 0;
+}
+
+#ifdef CMD_SAVEENV
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ int rc = 1;
+ char *res;
+ char *saved_data = NULL;
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+ ulong up_data = 0;
+
+ up_data = (end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE));
+ debug("Data to save 0x%lx\n", up_data);
+ if (up_data) {
+ if ((saved_data = malloc(up_data)) == NULL) {
+ printf("Unable to save the rest of sector (%ld)\n",
+ up_data);
+ goto done;
+ }
+ memcpy(saved_data,
+ (void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data);
+ debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n",
+ (ulong)flash_addr + CONFIG_ENV_SIZE,
+ up_data,
+ (ulong)saved_data);
+ }
+#endif /* CONFIG_ENV_SECT_SIZE */
+
+ debug("Protect off %08lX ... %08lX\n",
+ (ulong)flash_addr, end_addr);
+
+ if (flash_sect_protect(0, (long)flash_addr, end_addr))
+ goto done;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ goto done;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+ puts("Erasing Flash...");
+ if (flash_sect_erase((long)flash_addr, end_addr))
+ goto done;
+
+ puts("Writing to Flash... ");
+ rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE);
+ if (rc != 0) {
+ flash_perror(rc);
+ goto done;
+ }
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+ if (up_data) { /* restore the rest of sector */
+ debug("Restoring the rest of data to 0x%lx len 0x%lx\n",
+ (ulong)flash_addr + CONFIG_ENV_SIZE, up_data);
+ if (flash_write(saved_data,
+ (long)flash_addr + CONFIG_ENV_SIZE,
+ up_data)) {
+ flash_perror(rc);
+ goto done;
+ }
+ }
+#endif
+ puts("done\n");
+ rc = 0;
+done:
+ if (saved_data)
+ free(saved_data);
+ /* try to re-protect */
+ (void) flash_sect_protect(1, (long)flash_addr, end_addr);
+ return rc;
+}
+
+#endif /* CMD_SAVEENV */
+
+#endif /* CONFIG_ENV_ADDR_REDUND */
+
+void env_relocate_spec(void)
+{
+#ifdef CONFIG_ENV_ADDR_REDUND
+ if (gd->env_addr != (ulong)&(flash_addr->data)) {
+ env_t *etmp = flash_addr;
+ ulong ltmp = end_addr;
+
+ flash_addr = flash_addr_new;
+ flash_addr_new = etmp;
+
+ end_addr = end_addr_new;
+ end_addr_new = ltmp;
+ }
+
+ if (flash_addr_new->flags != OBSOLETE_FLAG &&
+ crc32(0, flash_addr_new->data, ENV_SIZE) ==
+ flash_addr_new->crc) {
+ char flag = OBSOLETE_FLAG;
+
+ gd->env_valid = 2;
+ flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new);
+ flash_write(&flag,
+ (ulong)&(flash_addr_new->flags),
+ sizeof(flash_addr_new->flags));
+ flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
+ }
+
+ if (flash_addr->flags != ACTIVE_FLAG &&
+ (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) {
+ char flag = ACTIVE_FLAG;
+
+ gd->env_valid = 2;
+ flash_sect_protect(0, (ulong)flash_addr, end_addr);
+ flash_write(&flag,
+ (ulong)&(flash_addr->flags),
+ sizeof(flash_addr->flags));
+ flash_sect_protect(1, (ulong)flash_addr, end_addr);
+ }
+
+ if (gd->env_valid == 2)
+ puts ("*** Warning - some problems detected "
+ "reading environment; recovered successfully\n\n");
+#endif /* CONFIG_ENV_ADDR_REDUND */
+
+ env_import((char *)flash_addr, 1);
+}
diff --git a/u-boot/common/env_mgdisk.c b/u-boot/common/env_mgdisk.c
new file mode 100644
index 0000000..a69923b
--- /dev/null
+++ b/u-boot/common/env_mgdisk.c
@@ -0,0 +1,84 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75@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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <mg_disk.h>
+
+/* references to names in env_common.c */
+extern uchar default_environment[];
+
+char *env_name_spec = "MG_DISK";
+
+env_t *env_ptr = 0;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+uchar env_get_char_spec(int index)
+{
+ return (*((uchar *)(gd->env_addr + index)));
+}
+
+void env_relocate_spec(void)
+{
+ char buf[CONFIG_ENV_SIZE];
+ unsigned int err, rc;
+
+ err = mg_disk_init();
+ if (err) {
+ set_default_env("!mg_disk_init error");
+ return;
+ }
+
+ err = mg_disk_read(CONFIG_ENV_ADDR, buf, CONFIG_ENV_SIZE);
+ if (err) {
+ set_default_env("!mg_disk_read error");
+ return;
+ }
+
+ env_import(buf, 1);
+}
+
+int saveenv(void)
+{
+ unsigned int err;
+
+ env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
+ err = mg_disk_write(CONFIG_ENV_ADDR, (u_char *)env_ptr,
+ CONFIG_ENV_SIZE);
+ if (err)
+ puts("*** Warning - mg_disk_write error\n\n");
+
+ return err;
+}
+
+int env_init(void)
+{
+ /* use default */
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 1;
+
+ return 0;
+}
diff --git a/u-boot/common/env_mmc.c b/u-boot/common/env_mmc.c
new file mode 100644
index 0000000..71dcc4c
--- /dev/null
+++ b/u-boot/common/env_mmc.c
@@ -0,0 +1,167 @@
+/*
+ * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
+ *
+ * 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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <search.h>
+#include <errno.h>
+
+/* references to names in env_common.c */
+extern uchar default_environment[];
+
+char *env_name_spec = "MMC";
+
+#ifdef ENV_IS_EMBEDDED
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+#else /* ! ENV_IS_EMBEDDED */
+env_t *env_ptr = NULL;
+#endif /* ENV_IS_EMBEDDED */
+
+/* local functions */
+#if !defined(ENV_IS_EMBEDDED)
+static void use_default(void);
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+uchar env_get_char_spec(int index)
+{
+ return *((uchar *)(gd->env_addr + index));
+}
+
+int env_init(void)
+{
+ /* use default */
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 1;
+
+ return 0;
+}
+
+int init_mmc_for_env(struct mmc *mmc)
+{
+ if (!mmc) {
+ puts("No MMC card found\n");
+ return -1;
+ }
+
+ if (mmc_init(mmc)) {
+ puts("MMC init failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_CMD_SAVEENV
+
+inline int write_env(struct mmc *mmc, unsigned long size,
+ unsigned long offset, const void *buffer)
+{
+ uint blk_start, blk_cnt, n;
+
+ blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
+ blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
+
+ n = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV, blk_start,
+ blk_cnt, (u_char *)buffer);
+
+ return (n == blk_cnt) ? 0 : -1;
+}
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+
+ if (init_mmc_for_env(mmc))
+ return 1;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+ printf("Writing to MMC(%d)... ", CONFIG_SYS_MMC_ENV_DEV);
+ if (write_env(mmc, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
+ puts("failed\n");
+ return 1;
+ }
+
+ puts("done\n");
+ return 0;
+}
+#endif /* CONFIG_CMD_SAVEENV */
+
+inline int read_env(struct mmc *mmc, unsigned long size,
+ unsigned long offset, const void *buffer)
+{
+ uint blk_start, blk_cnt, n;
+
+ blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
+ blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
+
+ n = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV, blk_start,
+ blk_cnt, (uchar *)buffer);
+
+ return (n == blk_cnt) ? 0 : -1;
+}
+
+void env_relocate_spec(void)
+{
+#if !defined(ENV_IS_EMBEDDED)
+ char buf[CONFIG_ENV_SIZE];
+
+ struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+
+ if (init_mmc_for_env(mmc)) {
+ use_default();
+ return;
+ }
+
+ if (read_env(mmc, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, buf)) {
+ use_default();
+ return;
+ }
+
+ env_import(buf, 1);
+#endif
+}
+
+#if !defined(ENV_IS_EMBEDDED)
+static void use_default()
+{
+ set_default_env(NULL);
+}
+#endif
diff --git a/u-boot/common/env_nand.c b/u-boot/common/env_nand.c
new file mode 100644
index 0000000..f25a31c
--- /dev/null
+++ b/u-boot/common/env_nand.c
@@ -0,0 +1,452 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2008
+ * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
+ *
+ * (C) Copyright 2004
+ * Jian Zhang, Texas Instruments, jzhang@ti.com.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * 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
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <nand.h>
+#include <search.h>
+#include <errno.h>
+
+#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
+#define CMD_SAVEENV
+#elif defined(CONFIG_ENV_OFFSET_REDUND)
+#error Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
+#endif
+
+#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
+#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
+#endif
+
+#ifndef CONFIG_ENV_RANGE
+#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
+#endif
+
+/* references to names in env_common.c */
+extern uchar default_environment[];
+
+char *env_name_spec = "NAND";
+
+
+#if defined(ENV_IS_EMBEDDED)
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+#elif defined(CONFIG_NAND_ENV_DST)
+env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
+#else /* ! ENV_IS_EMBEDDED */
+env_t *env_ptr = 0;
+#endif /* ENV_IS_EMBEDDED */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+uchar env_get_char_spec (int index)
+{
+ return ( *((uchar *)(gd->env_addr + index)) );
+}
+
+/*
+ * This is called before nand_init() so we can't read NAND to
+ * validate env data.
+ *
+ * Mark it OK for now. env_relocate() in env_common.c will call our
+ * relocate function which does the real validation.
+ *
+ * When using a NAND boot image (like sequoia_nand), the environment
+ * can be embedded or attached to the U-Boot image in NAND flash.
+ * This way the SPL loads not only the U-Boot image from NAND but
+ * also the environment.
+ */
+int env_init(void)
+{
+#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
+ int crc1_ok = 0, crc2_ok = 0;
+ env_t *tmp_env1;
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ env_t *tmp_env2;
+
+ tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
+ crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
+#endif
+
+ tmp_env1 = env_ptr;
+
+ crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
+
+ if (!crc1_ok && !crc2_ok) {
+ gd->env_addr = 0;
+ gd->env_valid = 0;
+
+ return 0;
+ } else if (crc1_ok && !crc2_ok) {
+ gd->env_valid = 1;
+ }
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ else if (!crc1_ok && crc2_ok) {
+ gd->env_valid = 2;
+ } else {
+ /* both ok - check serial */
+ if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
+ gd->env_valid = 2;
+ else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
+ gd->env_valid = 1;
+ else if(tmp_env1->flags > tmp_env2->flags)
+ gd->env_valid = 1;
+ else if(tmp_env2->flags > tmp_env1->flags)
+ gd->env_valid = 2;
+ else /* flags are equal - almost impossible */
+ gd->env_valid = 1;
+ }
+
+ if (gd->env_valid == 2)
+ env_ptr = tmp_env2;
+ else
+#endif
+ if (gd->env_valid == 1)
+ env_ptr = tmp_env1;
+
+ gd->env_addr = (ulong)env_ptr->data;
+
+#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 1;
+#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
+
+ return (0);
+}
+
+#ifdef CMD_SAVEENV
+/*
+ * The legacy NAND code saved the environment in the first NAND device i.e.,
+ * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
+ */
+int writeenv(size_t offset, u_char *buf)
+{
+ size_t end = offset + CONFIG_ENV_RANGE;
+ size_t amount_saved = 0;
+ size_t blocksize, len;
+
+ u_char *char_ptr;
+
+ blocksize = nand_info[0].erasesize;
+ len = min(blocksize, CONFIG_ENV_SIZE);
+
+ while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
+ if (nand_block_isbad(&nand_info[0], offset)) {
+ offset += blocksize;
+ } else {
+ char_ptr = &buf[amount_saved];
+ if (nand_write(&nand_info[0], offset, &len,
+ char_ptr))
+ return 1;
+ offset += blocksize;
+ amount_saved += len;
+ }
+ }
+ if (amount_saved != CONFIG_ENV_SIZE)
+ return 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+static unsigned char env_flags;
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ int ret = 0;
+ nand_erase_options_t nand_erase_options;
+
+ nand_erase_options.length = CONFIG_ENV_RANGE;
+ nand_erase_options.quiet = 0;
+ nand_erase_options.jffs2 = 0;
+ nand_erase_options.scrub = 0;
+
+ if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
+ return 1;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+ env_new.flags = ++env_flags; /* increase the serial */
+
+ if(gd->env_valid == 1) {
+ puts("Erasing redundant NAND...\n");
+ nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ return 1;
+
+ puts("Writing to redundant NAND... ");
+ ret = writeenv(CONFIG_ENV_OFFSET_REDUND,
+ (u_char *)&env_new);
+ } else {
+ puts("Erasing NAND...\n");
+ nand_erase_options.offset = CONFIG_ENV_OFFSET;
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ return 1;
+
+ puts("Writing to NAND... ");
+ ret = writeenv(CONFIG_ENV_OFFSET,
+ (u_char *)&env_new);
+ }
+ if (ret) {
+ puts("FAILED!\n");
+ return 1;
+ }
+
+ puts("done\n");
+
+ gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
+
+ return ret;
+}
+#else /* ! CONFIG_ENV_OFFSET_REDUND */
+int saveenv(void)
+{
+ int ret = 0;
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ nand_erase_options_t nand_erase_options;
+
+ nand_erase_options.length = CONFIG_ENV_RANGE;
+ nand_erase_options.quiet = 0;
+ nand_erase_options.jffs2 = 0;
+ nand_erase_options.scrub = 0;
+ nand_erase_options.offset = CONFIG_ENV_OFFSET;
+
+ if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
+ return 1;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+ puts("Erasing Nand...\n");
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ return 1;
+
+ puts("Writing to Nand... ");
+ if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
+ puts("FAILED!\n");
+ return 1;
+ }
+
+ puts("done\n");
+ return ret;
+}
+#endif /* CONFIG_ENV_OFFSET_REDUND */
+#endif /* CMD_SAVEENV */
+
+int readenv(size_t offset, u_char * buf)
+{
+ size_t end = offset + CONFIG_ENV_RANGE;
+ size_t amount_loaded = 0;
+ size_t blocksize, len;
+
+ u_char *char_ptr;
+
+ /* fail if no nand detected */
+ if (nand_info[0].type == 0)
+ return 1;
+
+ blocksize = nand_info[0].erasesize;
+ if (!blocksize)
+ return 1;
+ len = min(blocksize, CONFIG_ENV_SIZE);
+
+ while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
+ if (nand_block_isbad(&nand_info[0], offset)) {
+ offset += blocksize;
+ } else {
+ char_ptr = &buf[amount_loaded];
+ if (nand_read_skip_bad(&nand_info[0], offset, &len, char_ptr))
+ return 1;
+ offset += blocksize;
+ amount_loaded += len;
+ }
+ }
+ if (amount_loaded != CONFIG_ENV_SIZE)
+ return 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
+{
+ struct mtd_oob_ops ops;
+ uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+ int ret;
+
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooboffs = 0;
+ ops.ooblen = ENV_OFFSET_SIZE;
+ ops.oobbuf = (void *) oob_buf;
+
+ ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
+ if (ret) {
+ printf("error reading OOB block 0\n");
+ return ret;
+ }
+
+ if (oob_buf[0] == ENV_OOB_MARKER) {
+ *result = oob_buf[1] * nand->erasesize;
+ } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
+ *result = oob_buf[1];
+ } else {
+ printf("No dynamic environment marker in OOB block 0\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+void env_relocate_spec(void)
+{
+#if !defined(ENV_IS_EMBEDDED)
+ int crc1_ok = 0, crc2_ok = 0;
+ env_t *ep, *tmp_env1, *tmp_env2;
+
+ tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
+ tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
+
+ if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) {
+ puts("Can't allocate buffers for environment\n");
+ free(tmp_env1);
+ free(tmp_env2);
+ set_default_env("!malloc() failed");
+ return;
+ }
+
+ if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
+ puts("No Valid Environment Area found\n");
+
+ if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
+ puts("No Valid Redundant Environment Area found\n");
+
+ crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
+ crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
+
+ if (!crc1_ok && !crc2_ok) {
+ free(tmp_env1);
+ free(tmp_env2);
+ set_default_env("!bad CRC");
+ return;
+ } else if (crc1_ok && !crc2_ok) {
+ gd->env_valid = 1;
+ } else if (!crc1_ok && crc2_ok) {
+ gd->env_valid = 2;
+ } else {
+ /* both ok - check serial */
+ if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
+ gd->env_valid = 2;
+ else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
+ gd->env_valid = 1;
+ else if (tmp_env1->flags > tmp_env2->flags)
+ gd->env_valid = 1;
+ else if (tmp_env2->flags > tmp_env1->flags)
+ gd->env_valid = 2;
+ else /* flags are equal - almost impossible */
+ gd->env_valid = 1;
+
+ }
+
+ free(env_ptr);
+
+ if (gd->env_valid == 1)
+ ep = tmp_env1;
+ else
+ ep = tmp_env2;
+
+ env_flags = ep->flags;
+ env_import((char *)ep, 0);
+
+ free(tmp_env1);
+ free(tmp_env2);
+
+#endif /* ! ENV_IS_EMBEDDED */
+}
+#else /* ! CONFIG_ENV_OFFSET_REDUND */
+/*
+ * The legacy NAND code saved the environment in the first NAND
+ * device i.e., nand_dev_desc + 0. This is also the behaviour using
+ * the new NAND code.
+ */
+void env_relocate_spec (void)
+{
+#if !defined(ENV_IS_EMBEDDED)
+ int ret;
+ char buf[CONFIG_ENV_SIZE];
+
+#if defined(CONFIG_ENV_OFFSET_OOB)
+ ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
+ /*
+ * If unable to read environment offset from NAND OOB then fall through
+ * to the normal environment reading code below
+ */
+ if (!ret) {
+ printf("Found Environment offset in OOB..\n");
+ } else {
+ set_default_env("!no env offset in OOB");
+ return;
+ }
+#endif
+
+ ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
+ if (ret) {
+ set_default_env("!readenv() failed");
+ return;
+ }
+
+ env_import(buf, 1);
+#endif /* ! ENV_IS_EMBEDDED */
+}
+#endif /* CONFIG_ENV_OFFSET_REDUND */
diff --git a/u-boot/common/env_nowhere.c b/u-boot/common/env_nowhere.c
new file mode 100644
index 0000000..75ef78d
--- /dev/null
+++ b/u-boot/common/env_nowhere.c
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+
+ * 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 <environment.h>
+#include <linux/stddef.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+env_t *env_ptr = NULL;
+
+extern uchar default_environment[];
+
+void env_relocate_spec(void)
+{
+}
+
+uchar env_get_char_spec(int index)
+{
+ return ( *((uchar *)(gd->env_addr + index)) );
+}
+
+/*
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited
+ */
+int env_init(void)
+{
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+
+ return (0);
+}
diff --git a/u-boot/common/env_nvram.c b/u-boot/common/env_nvram.c
new file mode 100644
index 0000000..544ce47
--- /dev/null
+++ b/u-boot/common/env_nvram.c
@@ -0,0 +1,140 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+
+ * 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
+ */
+
+/*
+ * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
+ *
+ * It might not be possible in all cases to use 'memcpy()' to copy
+ * the environment to NVRAM, as the NVRAM might not be mapped into
+ * the memory space. (I.e. this is the case for the BAB750). In those
+ * cases it might be possible to access the NVRAM using a different
+ * method. For example, the RTC on the BAB750 is accessible in IO
+ * space using its address and data registers. To enable usage of
+ * NVRAM in those cases I invented the functions 'nvram_read()' and
+ * 'nvram_write()', which will be activated upon the configuration
+ * #define CONFIG_SYS_NVRAM_ACCESS_ROUTINE. Note, that those functions are
+ * strongly dependent on the used HW, and must be redefined for each
+ * board that wants to use them.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <search.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
+extern void *nvram_read(void *dest, const long src, size_t count);
+extern void nvram_write(long dest, const void *src, size_t count);
+env_t *env_ptr = NULL;
+#else
+env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
+#endif
+
+char * env_name_spec = "NVRAM";
+
+extern uchar default_environment[];
+
+uchar env_get_char_spec(int index)
+{
+#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
+ uchar c;
+
+ nvram_read(&c, CONFIG_ENV_ADDR+index, 1);
+
+ return c;
+#else
+ return *((uchar *)(gd->env_addr + index));
+#endif
+}
+
+void env_relocate_spec(void)
+{
+ char buf[CONFIG_ENV_SIZE];
+
+#if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
+ nvram_read(buf, CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
+#else
+ memcpy(buf, (void*)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
+#endif
+ env_import(buf, 1);
+}
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ int rcode = 0;
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
+ nvram_write(CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE);
+#else
+ if (memcpy((char *)CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE) == NULL)
+ rcode = 1;
+#endif
+ return rcode;
+}
+
+
+/*
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited
+ */
+int env_init(void)
+{
+#if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
+ ulong crc;
+ uchar data[ENV_SIZE];
+
+ nvram_read(&crc, CONFIG_ENV_ADDR, sizeof(ulong));
+ nvram_read(data, CONFIG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
+
+ if (crc32(0, data, ENV_SIZE) == crc) {
+ gd->env_addr = (ulong)CONFIG_ENV_ADDR + sizeof(long);
+#else
+ if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+ gd->env_addr = (ulong)&(env_ptr->data);
+#endif
+ gd->env_valid = 1;
+ } else {
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+ }
+ return (0);
+}
diff --git a/u-boot/common/env_onenand.c b/u-boot/common/env_onenand.c
new file mode 100644
index 0000000..5e04a06
--- /dev/null
+++ b/u-boot/common/env_onenand.c
@@ -0,0 +1,151 @@
+/*
+ * (C) Copyright 2010 DENX Software Engineering
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * (C) Copyright 2005-2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <search.h>
+#include <errno.h>
+
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
+
+/* References to names in env_common.c */
+extern uchar default_environment[];
+
+char *env_name_spec = "OneNAND";
+
+#define ONENAND_MAX_ENV_SIZE 4096
+#define ONENAND_ENV_SIZE(mtd) (ONENAND_MAX_ENV_SIZE - ENV_HEADER_SIZE)
+
+#ifdef ENV_IS_EMBEDDED
+extern uchar environment[];
+#endif /* ENV_IS_EMBEDDED */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+uchar env_get_char_spec(int index)
+{
+ return (*((uchar *)(gd->env_addr + index)));
+}
+
+void env_relocate_spec(void)
+{
+ struct mtd_info *mtd = &onenand_mtd;
+#ifdef CONFIG_ENV_ADDR_FLEX
+ struct onenand_chip *this = &onenand_chip;
+#endif
+ int rc;
+ size_t retlen;
+#ifdef ENV_IS_EMBEDDED
+ char *buf = (char *)&environment[0];
+#else
+ loff_t env_addr = CONFIG_ENV_ADDR;
+ char onenand_env[ONENAND_MAX_ENV_SIZE];
+ char *buf = (char *)&onenand_env[0];
+#endif /* ENV_IS_EMBEDDED */
+
+#ifndef ENV_IS_EMBEDDED
+# ifdef CONFIG_ENV_ADDR_FLEX
+ if (FLEXONENAND(this))
+ env_addr = CONFIG_ENV_ADDR_FLEX;
+# endif
+ /* Check OneNAND exist */
+ if (mtd->writesize)
+ /* Ignore read fail */
+ mtd->read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
+ &retlen, (u_char *)buf);
+ else
+ mtd->writesize = MAX_ONENAND_PAGESIZE;
+#endif /* !ENV_IS_EMBEDDED */
+
+ rc = env_import(buf, 1);
+ if (rc)
+ gd->env_valid = 1;
+}
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ struct mtd_info *mtd = &onenand_mtd;
+#ifdef CONFIG_ENV_ADDR_FLEX
+ struct onenand_chip *this = &onenand_chip;
+#endif
+ loff_t env_addr = CONFIG_ENV_ADDR;
+ size_t retlen;
+ struct erase_info instr = {
+ .callback = NULL,
+ };
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+ instr.len = CONFIG_ENV_SIZE;
+#ifdef CONFIG_ENV_ADDR_FLEX
+ if (FLEXONENAND(this)) {
+ env_addr = CONFIG_ENV_ADDR_FLEX;
+ instr.len = CONFIG_ENV_SIZE_FLEX;
+ instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
+ 1 : 0;
+ }
+#endif
+ instr.addr = env_addr;
+ instr.mtd = mtd;
+ if (mtd->erase(mtd, &instr)) {
+ printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
+ return 1;
+ }
+
+ if (mtd->write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
+ (u_char *)&env_new)) {
+ printf("OneNAND: write failed at 0x%llx\n", instr.addr);
+ return 2;
+ }
+
+ return 0;
+}
+
+int env_init(void)
+{
+ /* use default */
+ gd->env_addr = (ulong) & default_environment[0];
+ gd->env_valid = 1;
+
+ return 0;
+}
diff --git a/u-boot/common/env_sf.c b/u-boot/common/env_sf.c
new file mode 100644
index 0000000..41cc00a
--- /dev/null
+++ b/u-boot/common/env_sf.c
@@ -0,0 +1,382 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2008 Atmel Corporation
+ *
+ * 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 <environment.h>
+#include <malloc.h>
+#include <spi_flash.h>
+#include <search.h>
+#include <errno.h>
+
+#ifndef CONFIG_ENV_SPI_BUS
+# define CONFIG_ENV_SPI_BUS 0
+#endif
+#ifndef CONFIG_ENV_SPI_CS
+# define CONFIG_ENV_SPI_CS 0
+#endif
+#ifndef CONFIG_ENV_SPI_MAX_HZ
+# define CONFIG_ENV_SPI_MAX_HZ 1000000
+#endif
+#ifndef CONFIG_ENV_SPI_MODE
+# define CONFIG_ENV_SPI_MODE SPI_MODE_3
+#endif
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+static ulong env_offset = CONFIG_ENV_OFFSET;
+static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND;
+
+#define ACTIVE_FLAG 1
+#define OBSOLETE_FLAG 0
+#endif /* CONFIG_ENV_OFFSET_REDUND */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* references to names in env_common.c */
+extern uchar default_environment[];
+
+char * env_name_spec = "SPI Flash";
+env_t *env_ptr;
+
+static struct spi_flash *env_flash;
+
+uchar env_get_char_spec(int index)
+{
+ return *((uchar *)(gd->env_addr + index));
+}
+
+#if defined(CONFIG_ENV_OFFSET_REDUND)
+
+int saveenv(void)
+{
+ env_t env_new;
+ ssize_t len;
+ char *res;
+ u32 saved_size, saved_offset;
+ char *saved_buffer = NULL;
+ u32 sector = 1;
+ int ret;
+ char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
+
+ if (!env_flash) {
+ env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
+ CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!env_flash) {
+ set_default_env("!spi_flash_probe() failed");
+ return 1;
+ }
+ }
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ return 1;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+ env_new.flags = ACTIVE_FLAG;
+
+ if (gd->env_valid == 1) {
+ env_new_offset = CONFIG_ENV_OFFSET_REDUND;
+ env_offset = CONFIG_ENV_OFFSET;
+ } else {
+ env_new_offset = CONFIG_ENV_OFFSET;
+ env_offset = CONFIG_ENV_OFFSET_REDUND;
+ }
+
+ /* Is the sector larger than the env (i.e. embedded) */
+ if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
+ saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
+ saved_offset = env_new_offset + CONFIG_ENV_SIZE;
+ saved_buffer = malloc(saved_size);
+ if (!saved_buffer) {
+ ret = 1;
+ goto done;
+ }
+ ret = spi_flash_read(env_flash, saved_offset,
+ saved_size, saved_buffer);
+ if (ret)
+ goto done;
+ }
+
+ if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) {
+ sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;
+ if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE)
+ sector++;
+ }
+
+ puts("Erasing SPI flash...");
+ ret = spi_flash_erase(env_flash, env_new_offset,
+ sector * CONFIG_ENV_SECT_SIZE);
+ if (ret)
+ goto done;
+
+ puts("Writing to SPI flash...");
+
+ ret = spi_flash_write(env_flash, env_new_offset,
+ CONFIG_ENV_SIZE, &env_new);
+ if (ret)
+ goto done;
+
+ if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
+ ret = spi_flash_write(env_flash, saved_offset,
+ saved_size, saved_buffer);
+ if (ret)
+ goto done;
+ }
+
+ ret = spi_flash_write(env_flash,
+ env_offset + offsetof(env_t, flags),
+ sizeof(env_new.flags), &flag);
+ if (ret)
+ goto done;
+
+ puts("done\n");
+
+ gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
+
+ printf("Valid environment: %d\n", gd->env_valid);
+
+ done:
+ if (saved_buffer)
+ free(saved_buffer);
+ return ret;
+}
+
+void env_relocate_spec(void)
+{
+ int ret;
+ int crc1_ok = 0, crc2_ok = 0;
+ env_t *tmp_env1 = NULL;
+ env_t *tmp_env2 = NULL;
+ env_t *ep = NULL;
+ uchar flag1, flag2;
+ /* current_env is set only in case both areas are valid! */
+ int current_env = 0;
+
+ tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
+ tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
+
+ if (!tmp_env1 || !tmp_env2) {
+ free(tmp_env1);
+ free(tmp_env2);
+ set_default_env("!malloc() failed");
+ return;
+ }
+
+ env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!env_flash) {
+ set_default_env("!spi_flash_probe() failed");
+ return;
+ }
+
+ ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
+ CONFIG_ENV_SIZE, tmp_env1);
+ if (ret) {
+ set_default_env("!spi_flash_read() failed");
+ goto err_read;
+ }
+
+ if (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc)
+ crc1_ok = 1;
+ flag1 = tmp_env1->flags;
+
+ ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND,
+ CONFIG_ENV_SIZE, tmp_env2);
+ if (!ret) {
+ if (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc)
+ crc2_ok = 1;
+ flag2 = tmp_env2->flags;
+ }
+
+ if (!crc1_ok && !crc2_ok) {
+ free(tmp_env1);
+ free(tmp_env2);
+ set_default_env("!bad CRC");
+ return;
+ } else if (crc1_ok && !crc2_ok) {
+ gd->env_valid = 1;
+ ep = tmp_env1;
+ } else if (!crc1_ok && crc2_ok) {
+ gd->env_valid = 1;
+ } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
+ gd->env_valid = 1;
+ } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
+ gd->env_valid = 2;
+ } else if (flag1 == flag2) {
+ gd->env_valid = 2;
+ } else if (flag1 == 0xFF) {
+ gd->env_valid = 2;
+ } else {
+ /*
+ * this differs from code in env_flash.c, but I think a sane
+ * default path is desirable.
+ */
+ gd->env_valid = 2;
+ }
+
+ free(env_ptr);
+
+ if (gd->env_valid == 1)
+ ep = tmp_env1;
+ else
+ ep = tmp_env2;
+
+ ret = env_import((char *)ep, 0);
+ if (!ret) {
+ error("Cannot import environment: errno = %d\n", errno);
+ set_default_env("env_import failed");
+ }
+
+err_read:
+ spi_flash_free(env_flash);
+ env_flash = NULL;
+out:
+ if (tmp_env1)
+ free(tmp_env1);
+ if (tmp_env2)
+ free(tmp_env2);
+ free(tmp_env1);
+ free(tmp_env2);
+
+ return;
+}
+#else
+int saveenv(void)
+{
+ u32 saved_size, saved_offset;
+ char *saved_buffer = NULL;
+ u32 sector = 1;
+ int ret = 1;
+ env_t env_new;
+ char *res;
+ ssize_t len;
+
+ if (!env_flash) {
+ env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
+ CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!env_flash) {
+ set_default_env("!spi_flash_probe() failed");
+ return 1;
+ }
+ }
+
+ /* Is the sector larger than the env (i.e. embedded) */
+ if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
+ saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
+ saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+ saved_buffer = malloc(saved_size);
+ if (!saved_buffer) {
+ goto done;
+ }
+ ret = spi_flash_read(env_flash, saved_offset,
+ saved_size, saved_buffer);
+ if (ret)
+ goto done;
+ }
+
+ if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) {
+ sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;
+ if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE)
+ sector++;
+ }
+
+ res = (char *)&env_new.data;
+ len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
+ if (len < 0) {
+ error("Cannot export environment: errno = %d\n", errno);
+ goto done;
+ }
+ env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+ puts("Erasing SPI flash...");
+ ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
+ sector * CONFIG_ENV_SECT_SIZE);
+ if (ret)
+ goto done;
+
+ puts("Writing to SPI flash...");
+ ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
+ CONFIG_ENV_SIZE, &env_new);
+ if (ret)
+ goto done;
+
+ if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
+ ret = spi_flash_write(env_flash, saved_offset,
+ saved_size, saved_buffer);
+ if (ret)
+ goto done;
+ }
+
+ ret = 0;
+ puts("done\n");
+
+ done:
+ if (saved_buffer)
+ free(saved_buffer);
+ return ret;
+}
+
+void env_relocate_spec(void)
+{
+ char buf[CONFIG_ENV_SIZE];
+ int ret;
+
+ env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!env_flash) {
+ set_default_env("!spi_flash_probe() failed");
+ return;
+ }
+
+ ret = spi_flash_read(env_flash,
+ CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
+ if (ret) {
+ set_default_env("!spi_flash_read() failed");
+ goto out;
+ }
+
+ ret = env_import(buf, 1);
+
+ if (ret)
+ gd->env_valid = 1;
+out:
+ spi_flash_free(env_flash);
+ env_flash = NULL;
+}
+#endif
+
+int env_init(void)
+{
+ /* SPI flash isn't usable before relocation */
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 1;
+
+ return 0;
+}
diff --git a/u-boot/common/exports.c b/u-boot/common/exports.c
new file mode 100644
index 0000000..3dff735
--- /dev/null
+++ b/u-boot/common/exports.c
@@ -0,0 +1,42 @@
+#include <common.h>
+#include <exports.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__attribute__((unused)) static void dummy(void)
+{
+}
+
+unsigned long get_version(void)
+{
+ return XF_VERSION;
+}
+
+/* Reuse _exports.h with a little trickery to avoid bitrot */
+#define EXPORT_FUNC(sym) gd->jt[XF_##sym] = (void *)sym;
+
+#if !defined(CONFIG_I386) && !defined(CONFIG_PPC)
+# define install_hdlr dummy
+# define free_hdlr dummy
+#else /* kludge for non-standard function naming */
+# define install_hdlr irq_install_handler
+# define free_hdlr irq_free_handler
+#endif
+#ifndef CONFIG_CMD_I2C
+# define i2c_write dummy
+# define i2c_read dummy
+#endif
+#ifndef CONFIG_CMD_SPI
+# define spi_init dummy
+# define spi_setup_slave dummy
+# define spi_free_slave dummy
+# define spi_claim_bus dummy
+# define spi_release_bus dummy
+# define spi_xfer dummy
+#endif
+
+void jumptable_init(void)
+{
+ gd->jt = malloc(XF_MAX * sizeof(void *));
+#include <_exports.h>
+}
diff --git a/u-boot/common/fdt_support.c b/u-boot/common/fdt_support.c
new file mode 100644
index 0000000..6c98e5b
--- /dev/null
+++ b/u-boot/common/fdt_support.c
@@ -0,0 +1,1225 @@
+/*
+ * (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * 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 <stdio_dev.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <asm/global_data.h>
+#include <fdt.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <exports.h>
+
+/*
+ * Global data (for the gd->bd)
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * fdt_getprop_u32_default - Find a node and return it's property or a default
+ *
+ * @fdt: ptr to device tree
+ * @path: path of node
+ * @prop: property name
+ * @dflt: default value if the property isn't found
+ *
+ * Convenience function to find a node and return it's property or a
+ * default value if it doesn't exist.
+ */
+u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop,
+ const u32 dflt)
+{
+ const u32 *val;
+ int off;
+
+ off = fdt_path_offset(fdt, path);
+ if (off < 0)
+ return dflt;
+
+ val = fdt_getprop(fdt, off, prop, NULL);
+ if (val)
+ return *val;
+ else
+ return dflt;
+}
+
+/**
+ * fdt_find_and_setprop: Find a node and set it's property
+ *
+ * @fdt: ptr to device tree
+ * @node: path of node
+ * @prop: property name
+ * @val: ptr to new value
+ * @len: length of new property value
+ * @create: flag to create the property if it doesn't exist
+ *
+ * Convenience function to directly set a property given the path to the node.
+ */
+int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
+ const void *val, int len, int create)
+{
+ int nodeoff = fdt_path_offset(fdt, node);
+
+ if (nodeoff < 0)
+ return nodeoff;
+
+ if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
+ return 0; /* create flag not set; so exit quietly */
+
+ return fdt_setprop(fdt, nodeoff, prop, val, len);
+}
+
+#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
+
+#ifdef CONFIG_SERIAL_MULTI
+static void fdt_fill_multisername(char *sername, size_t maxlen)
+{
+ const char *outname = stdio_devices[stdout]->name;
+
+ if (strcmp(outname, "serial") > 0)
+ strncpy(sername, outname, maxlen);
+
+ /* eserial? */
+ if (strcmp(outname + 1, "serial") > 0)
+ strncpy(sername, outname + 1, maxlen);
+}
+#else
+static inline void fdt_fill_multisername(char *sername, size_t maxlen) {}
+#endif /* CONFIG_SERIAL_MULTI */
+
+static int fdt_fixup_stdout(void *fdt, int chosenoff)
+{
+ int err = 0;
+#ifdef CONFIG_CONS_INDEX
+ int node;
+ char sername[9] = { 0 };
+ const char *path;
+
+ fdt_fill_multisername(sername, sizeof(sername) - 1);
+ if (!sername[0])
+ sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
+
+ err = node = fdt_path_offset(fdt, "/aliases");
+ if (node >= 0) {
+ int len;
+ path = fdt_getprop(fdt, node, sername, &len);
+ if (path) {
+ char *p = malloc(len);
+ err = -FDT_ERR_NOSPACE;
+ if (p) {
+ memcpy(p, path, len);
+ err = fdt_setprop(fdt, chosenoff,
+ "linux,stdout-path", p, len);
+ free(p);
+ }
+ } else {
+ err = len;
+ }
+ }
+#endif
+ if (err < 0)
+ printf("WARNING: could not set linux,stdout-path %s.\n",
+ fdt_strerror(err));
+
+ return err;
+}
+#endif
+
+int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
+{
+ int nodeoffset;
+ int err, j, total;
+ u32 tmp;
+ const char *path;
+ uint64_t addr, size;
+
+ /* Find the "chosen" node. */
+ nodeoffset = fdt_path_offset (fdt, "/chosen");
+
+ /* If there is no "chosen" node in the blob return */
+ if (nodeoffset < 0) {
+ printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
+ return nodeoffset;
+ }
+
+ /* just return if initrd_start/end aren't valid */
+ if ((initrd_start == 0) || (initrd_end == 0))
+ return 0;
+
+ total = fdt_num_mem_rsv(fdt);
+
+ /*
+ * Look for an existing entry and update it. If we don't find
+ * the entry, we will j be the next available slot.
+ */
+ for (j = 0; j < total; j++) {
+ err = fdt_get_mem_rsv(fdt, j, &addr, &size);
+ if (addr == initrd_start) {
+ fdt_del_mem_rsv(fdt, j);
+ break;
+ }
+ }
+
+ err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
+ if (err < 0) {
+ printf("fdt_initrd: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
+ if ((path == NULL) || force) {
+ tmp = __cpu_to_be32(initrd_start);
+ err = fdt_setprop(fdt, nodeoffset,
+ "linux,initrd-start", &tmp, sizeof(tmp));
+ if (err < 0) {
+ printf("WARNING: "
+ "could not set linux,initrd-start %s.\n",
+ fdt_strerror(err));
+ return err;
+ }
+ tmp = __cpu_to_be32(initrd_end);
+ err = fdt_setprop(fdt, nodeoffset,
+ "linux,initrd-end", &tmp, sizeof(tmp));
+ if (err < 0) {
+ printf("WARNING: could not set linux,initrd-end %s.\n",
+ fdt_strerror(err));
+
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int fdt_chosen(void *fdt, int force)
+{
+ int nodeoffset;
+ int err;
+ char *str; /* used to set string properties */
+ const char *path;
+
+ err = fdt_check_header(fdt);
+ if (err < 0) {
+ printf("fdt_chosen: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ /*
+ * Find the "chosen" node.
+ */
+ nodeoffset = fdt_path_offset (fdt, "/chosen");
+
+ /*
+ * If there is no "chosen" node in the blob, create it.
+ */
+ if (nodeoffset < 0) {
+ /*
+ * Create a new node "/chosen" (offset 0 is root level)
+ */
+ nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
+ if (nodeoffset < 0) {
+ printf("WARNING: could not create /chosen %s.\n",
+ fdt_strerror(nodeoffset));
+ return nodeoffset;
+ }
+ }
+
+ /*
+ * Create /chosen properites that don't exist in the fdt.
+ * If the property exists, update it only if the "force" parameter
+ * is true.
+ */
+ str = getenv("bootargs");
+ if (str != NULL) {
+ path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
+ if ((path == NULL) || force) {
+ err = fdt_setprop(fdt, nodeoffset,
+ "bootargs", str, strlen(str)+1);
+ if (err < 0)
+ printf("WARNING: could not set bootargs %s.\n",
+ fdt_strerror(err));
+ }
+ }
+
+#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
+ path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
+ if ((path == NULL) || force)
+ err = fdt_fixup_stdout(fdt, nodeoffset);
+#endif
+
+#ifdef OF_STDOUT_PATH
+ path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
+ if ((path == NULL) || force) {
+ err = fdt_setprop(fdt, nodeoffset,
+ "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
+ if (err < 0)
+ printf("WARNING: could not set linux,stdout-path %s.\n",
+ fdt_strerror(err));
+ }
+#endif
+
+ return err;
+}
+
+void do_fixup_by_path(void *fdt, const char *path, const char *prop,
+ const void *val, int len, int create)
+{
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s/%s' = ", path, prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
+ if (rc)
+ printf("Unable to update property %s:%s, err=%s\n",
+ path, prop, fdt_strerror(rc));
+}
+
+void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
+ u32 val, int create)
+{
+ val = cpu_to_fdt32(val);
+ do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);
+}
+
+void do_fixup_by_prop(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, const void *val, int len,
+ int create)
+{
+ int off;
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s' = ", prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
+ while (off != -FDT_ERR_NOTFOUND) {
+ if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
+ fdt_setprop(fdt, off, prop, val, len);
+ off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
+ }
+}
+
+void do_fixup_by_prop_u32(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, u32 val, int create)
+{
+ val = cpu_to_fdt32(val);
+ do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);
+}
+
+void do_fixup_by_compat(void *fdt, const char *compat,
+ const char *prop, const void *val, int len, int create)
+{
+ int off = -1;
+#if defined(DEBUG)
+ int i;
+ debug("Updating property '%s' = ", prop);
+ for (i = 0; i < len; i++)
+ debug(" %.2x", *(u8*)(val+i));
+ debug("\n");
+#endif
+ off = fdt_node_offset_by_compatible(fdt, -1, compat);
+ while (off != -FDT_ERR_NOTFOUND) {
+ if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
+ fdt_setprop(fdt, off, prop, val, len);
+ off = fdt_node_offset_by_compatible(fdt, off, compat);
+ }
+}
+
+void do_fixup_by_compat_u32(void *fdt, const char *compat,
+ const char *prop, u32 val, int create)
+{
+ val = cpu_to_fdt32(val);
+ do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
+}
+
+/*
+ * Get cells len in bytes
+ * if #NNNN-cells property is 2 then len is 8
+ * otherwise len is 4
+ */
+static int get_cells_len(void *blob, char *nr_cells_name)
+{
+ const u32 *cell;
+
+ cell = fdt_getprop(blob, 0, nr_cells_name, NULL);
+ if (cell && *cell == 2)
+ return 8;
+
+ return 4;
+}
+
+/*
+ * Write a 4 or 8 byte big endian cell
+ */
+static void write_cell(u8 *addr, u64 val, int size)
+{
+ int shift = (size - 1) * 8;
+ while (size-- > 0) {
+ *addr++ = (val >> shift) & 0xff;
+ shift -= 8;
+ }
+}
+
+int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
+{
+ int err, nodeoffset;
+ int addr_cell_len, size_cell_len, len;
+ u8 tmp[banks * 8];
+ int bank;
+
+ err = fdt_check_header(blob);
+ if (err < 0) {
+ printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
+ return err;
+ }
+
+ /* update, or add and update /memory node */
+ nodeoffset = fdt_path_offset(blob, "/memory");
+ if (nodeoffset < 0) {
+ nodeoffset = fdt_add_subnode(blob, 0, "memory");
+ if (nodeoffset < 0)
+ printf("WARNING: could not create /memory: %s.\n",
+ fdt_strerror(nodeoffset));
+ return nodeoffset;
+ }
+ err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
+ sizeof("memory"));
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n", "device_type",
+ fdt_strerror(err));
+ return err;
+ }
+
+ addr_cell_len = get_cells_len(blob, "#address-cells");
+ size_cell_len = get_cells_len(blob, "#size-cells");
+
+ for (bank = 0, len = 0; bank < banks; bank++) {
+ write_cell(tmp + len, start[bank], addr_cell_len);
+ len += addr_cell_len;
+
+ write_cell(tmp + len, size[bank], size_cell_len);
+ len += size_cell_len;
+ }
+
+ err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
+ if (err < 0) {
+ printf("WARNING: could not set %s %s.\n",
+ "reg", fdt_strerror(err));
+ return err;
+ }
+ return 0;
+}
+
+int fdt_fixup_memory(void *blob, u64 start, u64 size)
+{
+ return fdt_fixup_memory_banks(blob, &start, &size, 1);
+}
+
+void fdt_fixup_ethernet(void *fdt)
+{
+ int node, i, j;
+ char enet[16], *tmp, *end;
+ char mac[16] = "ethaddr";
+ const char *path;
+ unsigned char mac_addr[6];
+
+ node = fdt_path_offset(fdt, "/aliases");
+ if (node < 0)
+ return;
+
+ i = 0;
+ while ((tmp = getenv(mac)) != NULL) {
+ sprintf(enet, "ethernet%d", i);
+ path = fdt_getprop(fdt, node, enet, NULL);
+ if (!path) {
+ debug("No alias for %s\n", enet);
+ sprintf(mac, "eth%daddr", ++i);
+ continue;
+ }
+
+ for (j = 0; j < 6; j++) {
+ mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end+1 : end;
+ }
+
+ do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0);
+ do_fixup_by_path(fdt, path, "local-mac-address",
+ &mac_addr, 6, 1);
+
+ sprintf(mac, "eth%daddr", ++i);
+ }
+}
+
+/* Resize the fdt to its actual size + a bit of padding */
+int fdt_resize(void *blob)
+{
+ int i;
+ uint64_t addr, size;
+ int total, ret;
+ uint actualsize;
+
+ if (!blob)
+ return 0;
+
+ total = fdt_num_mem_rsv(blob);
+ for (i = 0; i < total; i++) {
+ fdt_get_mem_rsv(blob, i, &addr, &size);
+ if (addr == (uint64_t)(u32)blob) {
+ fdt_del_mem_rsv(blob, i);
+ break;
+ }
+ }
+
+ /*
+ * Calculate the actual size of the fdt
+ * plus the size needed for 5 fdt_add_mem_rsv, one
+ * for the fdt itself and 4 for a possible initrd
+ * ((initrd-start + initrd-end) * 2 (name & value))
+ */
+ actualsize = fdt_off_dt_strings(blob) +
+ fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
+
+ /* Make it so the fdt ends on a page boundary */
+ actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
+ actualsize = actualsize - ((uint)blob & 0xfff);
+
+ /* Change the fdt header to reflect the correct size */
+ fdt_set_totalsize(blob, actualsize);
+
+ /* Add the new reservation */
+ ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize);
+ if (ret < 0)
+ return ret;
+
+ return actualsize;
+}
+
+#ifdef CONFIG_PCI
+#define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
+
+#define FDT_PCI_PREFETCH (0x40000000)
+#define FDT_PCI_MEM32 (0x02000000)
+#define FDT_PCI_IO (0x01000000)
+#define FDT_PCI_MEM64 (0x03000000)
+
+int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
+
+ int addrcell, sizecell, len, r;
+ u32 *dma_range;
+ /* sized based on pci addr cells, size-cells, & address-cells */
+ u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
+
+ addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
+ sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
+
+ dma_range = &dma_ranges[0];
+ for (r = 0; r < hose->region_count; r++) {
+ u64 bus_start, phys_start, size;
+
+ /* skip if !PCI_REGION_SYS_MEMORY */
+ if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
+ continue;
+
+ bus_start = (u64)hose->regions[r].bus_start;
+ phys_start = (u64)hose->regions[r].phys_start;
+ size = (u64)hose->regions[r].size;
+
+ dma_range[0] = 0;
+ if (size >= 0x100000000ull)
+ dma_range[0] |= FDT_PCI_MEM64;
+ else
+ dma_range[0] |= FDT_PCI_MEM32;
+ if (hose->regions[r].flags & PCI_REGION_PREFETCH)
+ dma_range[0] |= FDT_PCI_PREFETCH;
+#ifdef CONFIG_SYS_PCI_64BIT
+ dma_range[1] = bus_start >> 32;
+#else
+ dma_range[1] = 0;
+#endif
+ dma_range[2] = bus_start & 0xffffffff;
+
+ if (addrcell == 2) {
+ dma_range[3] = phys_start >> 32;
+ dma_range[4] = phys_start & 0xffffffff;
+ } else {
+ dma_range[3] = phys_start & 0xffffffff;
+ }
+
+ if (sizecell == 2) {
+ dma_range[3 + addrcell + 0] = size >> 32;
+ dma_range[3 + addrcell + 1] = size & 0xffffffff;
+ } else {
+ dma_range[3 + addrcell + 0] = size & 0xffffffff;
+ }
+
+ dma_range += (3 + addrcell + sizecell);
+ }
+
+ len = dma_range - &dma_ranges[0];
+ if (len)
+ fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
+/*
+ * Provide a weak default function to return the flash bank size.
+ * There might be multiple non-identical flash chips connected to one
+ * chip-select, so we need to pass an index as well.
+ */
+u32 __flash_get_bank_size(int cs, int idx)
+{
+ extern flash_info_t flash_info[];
+
+ /*
+ * As default, a simple 1:1 mapping is provided. Boards with
+ * a different mapping need to supply a board specific mapping
+ * routine.
+ */
+ return flash_info[cs].size;
+}
+u32 flash_get_bank_size(int cs, int idx)
+ __attribute__((weak, alias("__flash_get_bank_size")));
+
+/*
+ * This function can be used to update the size in the "reg" property
+ * of all NOR FLASH device nodes. This is necessary for boards with
+ * non-fixed NOR FLASH sizes.
+ */
+int fdt_fixup_nor_flash_size(void *blob)
+{
+ char compat[][16] = { "cfi-flash", "jedec-flash" };
+ int off;
+ int len;
+ struct fdt_property *prop;
+ u32 *reg, *reg2;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ off = fdt_node_offset_by_compatible(blob, -1, compat[i]);
+ while (off != -FDT_ERR_NOTFOUND) {
+ int idx;
+
+ /*
+ * Found one compatible node, so fixup the size
+ * int its reg properties
+ */
+ prop = fdt_get_property_w(blob, off, "reg", &len);
+ if (prop) {
+ int tuple_size = 3 * sizeof(reg);
+
+ /*
+ * There might be multiple reg-tuples,
+ * so loop through them all
+ */
+ reg = reg2 = (u32 *)&prop->data[0];
+ for (idx = 0; idx < (len / tuple_size); idx++) {
+ /*
+ * Update size in reg property
+ */
+ reg[2] = flash_get_bank_size(reg[0],
+ idx);
+
+ /*
+ * Point to next reg tuple
+ */
+ reg += 3;
+ }
+
+ fdt_setprop(blob, off, "reg", reg2, len);
+ }
+
+ /* Move to next compatible node */
+ off = fdt_node_offset_by_compatible(blob, off,
+ compat[i]);
+ }
+ }
+
+ return 0;
+}
+#endif
+
+int fdt_increase_size(void *fdt, int add_len)
+{
+ int newlen;
+
+ newlen = fdt_totalsize(fdt) + add_len;
+
+ /* Open in place with a new len */
+ return fdt_open_into(fdt, fdt, newlen);
+}
+
+#ifdef CONFIG_FDT_FIXUP_PARTITIONS
+#include <jffs2/load_kernel.h>
+#include <mtd_node.h>
+
+struct reg_cell {
+ unsigned int r0;
+ unsigned int r1;
+};
+
+int fdt_del_subnodes(const void *blob, int parent_offset)
+{
+ int off, ndepth;
+ int ret;
+
+ for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
+ (off >= 0) && (ndepth > 0);
+ off = fdt_next_node(blob, off, &ndepth)) {
+ if (ndepth == 1) {
+ debug("delete %s: offset: %x\n",
+ fdt_get_name(blob, off, 0), off);
+ ret = fdt_del_node((void *)blob, off);
+ if (ret < 0) {
+ printf("Can't delete node: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ } else {
+ ndepth = 0;
+ off = parent_offset;
+ }
+ }
+ }
+ return 0;
+}
+
+int fdt_del_partitions(void *blob, int parent_offset)
+{
+ const void *prop;
+ int ndepth = 0;
+ int off;
+ int ret;
+
+ off = fdt_next_node(blob, parent_offset, &ndepth);
+ if (off > 0 && ndepth == 1) {
+ prop = fdt_getprop(blob, off, "label", NULL);
+ if (prop == NULL) {
+ /*
+ * Could not find label property, nand {}; node?
+ * Check subnode, delete partitions there if any.
+ */
+ return fdt_del_partitions(blob, off);
+ } else {
+ ret = fdt_del_subnodes(blob, parent_offset);
+ if (ret < 0) {
+ printf("Can't remove subnodes: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+int fdt_node_set_part_info(void *blob, int parent_offset,
+ struct mtd_device *dev)
+{
+ struct list_head *pentry;
+ struct part_info *part;
+ struct reg_cell cell;
+ int off, ndepth = 0;
+ int part_num, ret;
+ char buf[64];
+
+ ret = fdt_del_partitions(blob, parent_offset);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Check if it is nand {}; subnode, adjust
+ * the offset in this case
+ */
+ off = fdt_next_node(blob, parent_offset, &ndepth);
+ if (off > 0 && ndepth == 1)
+ parent_offset = off;
+
+ part_num = 0;
+ list_for_each_prev(pentry, &dev->parts) {
+ int newoff;
+
+ part = list_entry(pentry, struct part_info, link);
+
+ debug("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+ part_num, part->name, part->size,
+ part->offset, part->mask_flags);
+
+ sprintf(buf, "partition@%x", part->offset);
+add_sub:
+ ret = fdt_add_subnode(blob, parent_offset, buf);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_sub;
+ else
+ goto err_size;
+ } else if (ret < 0) {
+ printf("Can't add partition node: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+ newoff = ret;
+
+ /* Check MTD_WRITEABLE_CMD flag */
+ if (part->mask_flags & 1) {
+add_ro:
+ ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_ro;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+ }
+
+ cell.r0 = cpu_to_fdt32(part->offset);
+ cell.r1 = cpu_to_fdt32(part->size);
+add_reg:
+ ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_reg;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+
+add_label:
+ ret = fdt_setprop_string(blob, newoff, "label", part->name);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_label;
+ else
+ goto err_size;
+ } else if (ret < 0)
+ goto err_prop;
+
+ part_num++;
+ }
+ return 0;
+err_size:
+ printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+ return ret;
+err_prop:
+ printf("Can't add property: %s\n", fdt_strerror(ret));
+ return ret;
+}
+
+/*
+ * Update partitions in nor/nand nodes using info from
+ * mtdparts environment variable. The nodes to update are
+ * specified by node_info structure which contains mtd device
+ * type and compatible string: E. g. the board code in
+ * ft_board_setup() could use:
+ *
+ * struct node_info nodes[] = {
+ * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, },
+ * { "cfi-flash", MTD_DEV_TYPE_NOR, },
+ * };
+ *
+ * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+ */
+void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
+{
+ struct node_info *ni = node_info;
+ struct mtd_device *dev;
+ char *parts;
+ int i, idx;
+ int noff;
+
+ parts = getenv("mtdparts");
+ if (!parts)
+ return;
+
+ if (mtdparts_init() != 0)
+ return;
+
+ for (i = 0; i < node_info_size; i++) {
+ idx = 0;
+ noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
+ while (noff != -FDT_ERR_NOTFOUND) {
+ debug("%s: %s, mtd dev type %d\n",
+ fdt_get_name(blob, noff, 0),
+ ni[i].compat, ni[i].type);
+ dev = device_find(ni[i].type, idx++);
+ if (dev) {
+ if (fdt_node_set_part_info(blob, noff, dev))
+ return; /* return on error */
+ }
+
+ /* Jump to next flash node */
+ noff = fdt_node_offset_by_compatible(blob, noff,
+ ni[i].compat);
+ }
+ }
+}
+#endif
+
+void fdt_del_node_and_alias(void *blob, const char *alias)
+{
+ int off = fdt_path_offset(blob, alias);
+
+ if (off < 0)
+ return;
+
+ fdt_del_node(blob, off);
+
+ off = fdt_path_offset(blob, "/aliases");
+ fdt_delprop(blob, off, alias);
+}
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 of_read_number(const __be32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | be32_to_cpu(*(cell++));
+ return r;
+}
+
+#define PRu64 "%llx"
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_BAD_ADDR ((u64)-1)
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, const u32 *addr, int na)
+{
+ printf("%s", s);
+ while(na--)
+ printf(" %08x", *(addr++));
+ printf("\n");
+}
+#else
+static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+#endif
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ void (*count_cells)(void *blob, int parentoffset,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, const u32 *range,
+ int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+};
+
+/* Default translator (generic bus) */
+static void of_bus_default_count_cells(void *blob, int parentoffset,
+ int *addrc, int *sizec)
+{
+ const u32 *prop;
+
+ if (addrc) {
+ prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
+ if (prop)
+ *addrc = be32_to_cpup((u32 *)prop);
+ else
+ *addrc = 2;
+ }
+
+ if (sizec) {
+ prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
+ if (prop)
+ *sizec = be32_to_cpup((u32 *)prop);
+ else
+ *sizec = 1;
+ }
+}
+
+static u64 of_bus_default_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
+
+ debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
+ cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+/* Array of bus specific translators */
+static struct of_bus of_busses[] = {
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ },
+};
+
+static int of_translate_one(void * blob, int parent, struct of_bus *bus,
+ struct of_bus *pbus, u32 *addr,
+ int na, int ns, int pna, const char *rprop)
+{
+ const u32 *ranges;
+ int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /* Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current not cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ */
+ ranges = (u32 *)fdt_getprop(blob, parent, rprop, &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ debug("OF: no ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ debug("OF: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ debug("OF: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("OF: parent translation for:", addr, pna);
+ debug("OF: with offset: "PRu64"\n", offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 __of_translate_address(void *blob, int node_offset, const u32 *in_addr,
+ const char *rprop)
+{
+ int parent;
+ struct of_bus *bus, *pbus;
+ u32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ debug("OF: ** translation for device %s **\n",
+ fdt_get_name(blob, node_offset, NULL));
+
+ /* Get parent & match bus type */
+ parent = fdt_parent_offset(blob, node_offset);
+ if (parent < 0)
+ goto bail;
+ bus = &of_busses[0];
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(blob, parent, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node_offset, NULL));
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ bus->name, na, ns, fdt_get_name(blob, parent, NULL));
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ node_offset = parent;
+ parent = fdt_parent_offset(blob, node_offset);
+
+ /* If root, we have finished */
+ if (parent < 0) {
+ debug("OF: reached root node\n");
+ result = of_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = &of_busses[0];
+ pbus->count_cells(blob, parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node_offset, NULL));
+ break;
+ }
+
+ debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
+
+ /* Apply bus translation */
+ if (of_translate_one(blob, node_offset, bus, pbus,
+ addr, na, ns, pna, rprop))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("OF: one level translation:", addr, na);
+ }
+ bail:
+
+ return result;
+}
+
+u64 fdt_translate_address(void *blob, int node_offset, const u32 *in_addr)
+{
+ return __of_translate_address(blob, node_offset, in_addr, "ranges");
+}
+
+/**
+ * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
+ * who's reg property matches a physical cpu address
+ *
+ * @blob: ptr to device tree
+ * @compat: compatiable string to match
+ * @compat_off: property name
+ *
+ */
+int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
+ phys_addr_t compat_off)
+{
+ int len, off = fdt_node_offset_by_compatible(blob, -1, compat);
+ while (off != -FDT_ERR_NOTFOUND) {
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", &len);
+ if (reg) {
+ if (compat_off == fdt_translate_address(blob, off, reg))
+ return off;
+ }
+ off = fdt_node_offset_by_compatible(blob, off, compat);
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+/**
+ * fdt_alloc_phandle: Return next free phandle value
+ *
+ * @blob: ptr to device tree
+ */
+int fdt_alloc_phandle(void *blob)
+{
+ int offset, len, phandle = 0;
+ const u32 *val;
+
+ for (offset = fdt_next_node(blob, -1, NULL); offset >= 0;
+ offset = fdt_next_node(blob, offset, NULL)) {
+ val = fdt_getprop(blob, offset, "linux,phandle", &len);
+ if (val)
+ phandle = max(*val, phandle);
+ }
+
+ return phandle + 1;
+}
+
+#if defined(CONFIG_VIDEO)
+int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
+{
+ int noff;
+ int ret;
+
+ noff = fdt_node_offset_by_compatible(blob, -1, compat);
+ if (noff != -FDT_ERR_NOTFOUND) {
+ debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat);
+add_edid:
+ ret = fdt_setprop(blob, noff, "edid", edid_buf, 128);
+ if (ret == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (!ret)
+ goto add_edid;
+ else
+ goto err_size;
+ } else if (ret < 0) {
+ printf("Can't add property: %s\n", fdt_strerror(ret));
+ return ret;
+ }
+ }
+ return 0;
+err_size:
+ printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+ return ret;
+}
+#endif
diff --git a/u-boot/common/flash.c b/u-boot/common/flash.c
new file mode 100644
index 0000000..781cb9c
--- /dev/null
+++ b/u-boot/common/flash.c
@@ -0,0 +1,232 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <flash.h>
+
+#if !defined(CONFIG_SYS_NO_FLASH)
+#include <mtd/cfi_flash.h>
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+ ulong b_end;
+ short s_end;
+ int i;
+
+ /* Do nothing if input data is bad. */
+ if (!info || info->sector_count == 0 || info->size == 0 || to < from) {
+ return;
+ }
+
+ s_end = info->sector_count - 1; /* index of last sector */
+ b_end = info->start[0] + info->size - 1; /* bank end address */
+
+ debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",
+ (flag & FLAG_PROTECT_SET) ? "ON" :
+ (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
+ from, to);
+
+ /* There is nothing to do if we have no data about the flash
+ * or the protect range and flash range don't overlap.
+ */
+ if (info->flash_id == FLASH_UNKNOWN ||
+ to < info->start[0] || from > b_end) {
+ return;
+ }
+
+ for (i=0; i<info->sector_count; ++i) {
+ ulong end; /* last address in current sect */
+
+ end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+ /* Update protection if any part of the sector
+ * is in the specified range.
+ */
+ if (from <= end && to >= info->start[i]) {
+ if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 0);
+#else
+ info->protect[i] = 0;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ debug ("protect off %d\n", i);
+ }
+ else if (flag & FLAG_PROTECT_SET) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 1);
+#else
+ info->protect[i] = 1;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ debug ("protect on %d\n", i);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+ flash_info_t *info;
+ int i;
+
+ for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
+ if (info->flash_id != FLASH_UNKNOWN &&
+ addr >= info->start[0] &&
+ /* WARNING - The '- 1' is needed if the flash
+ * is at the end of the address space, since
+ * info->start[0] + info->size wraps back to 0.
+ * Please don't change this unless you understand this.
+ */
+ addr <= info->start[0] + info->size - 1) {
+ return (info);
+ }
+ }
+#endif /* CONFIG_SPD823TS */
+
+ return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK 0 - OK
+ * ERR_TIMOUT 1 - write timeout
+ * ERR_NOT_ERASED 2 - Flash not erased
+ * ERR_PROTECTED 4 - target range includes protected sectors
+ * ERR_INVAL 8 - target address not in Flash memory
+ * ERR_ALIGN 16 - target address not aligned on boundary
+ * (only some targets require alignment)
+ */
+int
+flash_write (char *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+ return (ERR_TIMOUT); /* any other error codes are possible as well */
+#else
+ int i;
+ ulong end = addr + cnt - 1;
+ flash_info_t *info_first = addr2info (addr);
+ flash_info_t *info_last = addr2info (end );
+ flash_info_t *info;
+
+ if (cnt == 0) {
+ return (ERR_OK);
+ }
+
+ if (!info_first || !info_last) {
+ return (ERR_INVAL);
+ }
+
+ for (info = info_first; info <= info_last; ++info) {
+ ulong b_end = info->start[0] + info->size; /* bank end addr */
+ short s_end = info->sector_count - 1;
+ for (i=0; i<info->sector_count; ++i) {
+ ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+ if ((end >= info->start[i]) && (addr < e_addr) &&
+ (info->protect[i] != 0) ) {
+ return (ERR_PROTECTED);
+ }
+ }
+ }
+
+ /* finally write data to flash */
+ for (info = info_first; info <= info_last && cnt>0; ++info) {
+ ulong len;
+
+ len = info->start[0] + info->size - addr;
+ if (len > cnt)
+ len = cnt;
+ if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
+ return (i);
+ }
+ cnt -= len;
+ addr += len;
+ src += len;
+ }
+ return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_perror (int err)
+{
+ switch (err) {
+ case ERR_OK:
+ break;
+ case ERR_TIMOUT:
+ puts ("Timeout writing to Flash\n");
+ break;
+ case ERR_NOT_ERASED:
+ puts ("Flash not Erased\n");
+ break;
+ case ERR_PROTECTED:
+ puts ("Can't write to protected Flash sectors\n");
+ break;
+ case ERR_INVAL:
+ puts ("Outside available Flash\n");
+ break;
+ case ERR_ALIGN:
+ puts ("Start and/or end address not on sector boundary\n");
+ break;
+ case ERR_UNKNOWN_FLASH_VENDOR:
+ puts ("Unknown Vendor of Flash\n");
+ break;
+ case ERR_UNKNOWN_FLASH_TYPE:
+ puts ("Unknown Type of Flash\n");
+ break;
+ case ERR_PROG_ERROR:
+ puts ("General Flash Programming Error\n");
+ break;
+ default:
+ printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+#endif /* !CONFIG_SYS_NO_FLASH */
diff --git a/u-boot/common/hush.c b/u-boot/common/hush.c
new file mode 100644
index 0000000..8021a68
--- /dev/null
+++ b/u-boot/common/hush.c
@@ -0,0 +1,3630 @@
+/*
+ * sh.c -- a prototype Bourne shell grammar parser
+ * Intended to follow the original Thompson and Ritchie
+ * "small and simple is beautiful" philosophy, which
+ * incidentally is a good match to today's BusyBox.
+ *
+ * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
+ *
+ * Credits:
+ * The parser routines proper are all original material, first
+ * written Dec 2000 and Jan 2001 by Larry Doolittle.
+ * The execution engine, the builtins, and much of the underlying
+ * support has been adapted from busybox-0.49pre's lash,
+ * which is Copyright (C) 2000 by Lineo, Inc., and
+ * written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
+ * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
+ * Erik W. Troan, which they placed in the public domain. I don't know
+ * how much of the Johnson/Troan code has survived the repeated rewrites.
+ * Other credits:
+ * simple_itoa() was lifted from boa-0.93.15
+ * b_addchr() derived from similar w_addchar function in glibc-2.2
+ * setup_redirect(), redirect_opt_num(), and big chunks of main()
+ * and many builtins derived from contributions by Erik Andersen
+ * miscellaneous bugfixes from Matt Kraai
+ *
+ * There are two big (and related) architecture differences between
+ * this parser and the lash parser. One is that this version is
+ * actually designed from the ground up to understand nearly all
+ * of the Bourne grammar. The second, consequential change is that
+ * the parser and input reader have been turned inside out. Now,
+ * the parser is in control, and asks for input as needed. The old
+ * way had the input reader in control, and it asked for parsing to
+ * take place as needed. The new way makes it much easier to properly
+ * handle the recursion implicit in the various substitutions, especially
+ * across continuation lines.
+ *
+ * Bash grammar not implemented: (how many of these were in original sh?)
+ * $@ (those sure look like weird quoting rules)
+ * $_
+ * ! negation operator for pipes
+ * &> and >& redirection of stdout+stderr
+ * Brace Expansion
+ * Tilde Expansion
+ * fancy forms of Parameter Expansion
+ * aliases
+ * Arithmetic Expansion
+ * <(list) and >(list) Process Substitution
+ * reserved words: case, esac, select, function
+ * Here Documents ( << word )
+ * Functions
+ * Major bugs:
+ * job handling woefully incomplete and buggy
+ * reserved word execution woefully incomplete and buggy
+ * to-do:
+ * port selected bugfixes from post-0.49 busybox lash - done?
+ * finish implementing reserved words: for, while, until, do, done
+ * change { and } from special chars to reserved words
+ * builtins: break, continue, eval, return, set, trap, ulimit
+ * test magic exec
+ * handle children going into background
+ * clean up recognition of null pipes
+ * check setting of global_argc and global_argv
+ * control-C handling, probably with longjmp
+ * follow IFS rules more precisely, including update semantics
+ * figure out what to do with backslash-newline
+ * explain why we use signal instead of sigaction
+ * propagate syntax errors, die on resource errors?
+ * continuation lines, both explicit and implicit - done?
+ * memory leak finding and plugging - done?
+ * more testing, especially quoting rules and redirection
+ * document how quoting rules not precisely followed for variable assignments
+ * maybe change map[] to use 2-bit entries
+ * (eventually) remove all the printf's
+ *
+ * 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
+ */
+#define __U_BOOT__
+#ifdef __U_BOOT__
+#include <malloc.h> /* malloc, free, realloc*/
+#include <linux/ctype.h> /* isalpha, isdigit */
+#include <common.h> /* readline */
+#include <hush.h>
+#include <command.h> /* find_cmd */
+#endif
+#ifndef __U_BOOT__
+#include <ctype.h> /* isalpha, isdigit */
+#include <unistd.h> /* getpid */
+#include <stdlib.h> /* getenv, atoi */
+#include <string.h> /* strchr */
+#include <stdio.h> /* popen etc. */
+#include <glob.h> /* glob, of course */
+#include <stdarg.h> /* va_list */
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h> /* should be pretty obvious */
+
+#include <sys/stat.h> /* ulimit */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+/* #include <dmalloc.h> */
+
+#if 1
+#include "busybox.h"
+#include "cmdedit.h"
+#else
+#define applet_name "hush"
+#include "standalone.h"
+#define hush_main main
+#undef CONFIG_FEATURE_SH_FANCY_PROMPT
+#define BB_BANNER
+#endif
+#endif
+#define SPECIAL_VAR_SYMBOL 03
+#ifndef __U_BOOT__
+#define FLAG_EXIT_FROM_LOOP 1
+#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
+#define FLAG_REPARSING (1 << 2) /* >= 2nd pass */
+
+#endif
+
+#ifdef __U_BOOT__
+DECLARE_GLOBAL_DATA_PTR;
+
+#define EXIT_SUCCESS 0
+#define EOF -1
+#define syntax() syntax_err()
+#define xstrdup strdup
+#define error_msg printf
+#else
+typedef enum {
+ REDIRECT_INPUT = 1,
+ REDIRECT_OVERWRITE = 2,
+ REDIRECT_APPEND = 3,
+ REDIRECT_HEREIS = 4,
+ REDIRECT_IO = 5
+} redir_type;
+
+/* The descrip member of this structure is only used to make debugging
+ * output pretty */
+struct {int mode; int default_fd; char *descrip;} redir_table[] = {
+ { 0, 0, "()" },
+ { O_RDONLY, 0, "<" },
+ { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
+ { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
+ { O_RDONLY, -1, "<<" },
+ { O_RDWR, 1, "<>" }
+};
+#endif
+
+typedef enum {
+ PIPE_SEQ = 1,
+ PIPE_AND = 2,
+ PIPE_OR = 3,
+ PIPE_BG = 4,
+} pipe_style;
+
+/* might eventually control execution */
+typedef enum {
+ RES_NONE = 0,
+ RES_IF = 1,
+ RES_THEN = 2,
+ RES_ELIF = 3,
+ RES_ELSE = 4,
+ RES_FI = 5,
+ RES_FOR = 6,
+ RES_WHILE = 7,
+ RES_UNTIL = 8,
+ RES_DO = 9,
+ RES_DONE = 10,
+ RES_XXXX = 11,
+ RES_IN = 12,
+ RES_SNTX = 13
+} reserved_style;
+#define FLAG_END (1<<RES_NONE)
+#define FLAG_IF (1<<RES_IF)
+#define FLAG_THEN (1<<RES_THEN)
+#define FLAG_ELIF (1<<RES_ELIF)
+#define FLAG_ELSE (1<<RES_ELSE)
+#define FLAG_FI (1<<RES_FI)
+#define FLAG_FOR (1<<RES_FOR)
+#define FLAG_WHILE (1<<RES_WHILE)
+#define FLAG_UNTIL (1<<RES_UNTIL)
+#define FLAG_DO (1<<RES_DO)
+#define FLAG_DONE (1<<RES_DONE)
+#define FLAG_IN (1<<RES_IN)
+#define FLAG_START (1<<RES_XXXX)
+
+/* This holds pointers to the various results of parsing */
+struct p_context {
+ struct child_prog *child;
+ struct pipe *list_head;
+ struct pipe *pipe;
+#ifndef __U_BOOT__
+ struct redir_struct *pending_redirect;
+#endif
+ reserved_style w;
+ int old_flag; /* for figuring out valid reserved words */
+ struct p_context *stack;
+ int type; /* define type of parser : ";$" common or special symbol */
+ /* How about quoting status? */
+};
+
+#ifndef __U_BOOT__
+struct redir_struct {
+ redir_type type; /* type of redirection */
+ int fd; /* file descriptor being redirected */
+ int dup; /* -1, or file descriptor being duplicated */
+ struct redir_struct *next; /* pointer to the next redirect in the list */
+ glob_t word; /* *word.gl_pathv is the filename */
+};
+#endif
+
+struct child_prog {
+#ifndef __U_BOOT__
+ pid_t pid; /* 0 if exited */
+#endif
+ char **argv; /* program name and arguments */
+#ifdef __U_BOOT__
+ int argc; /* number of program arguments */
+#endif
+ struct pipe *group; /* if non-NULL, first in group or subshell */
+#ifndef __U_BOOT__
+ int subshell; /* flag, non-zero if group must be forked */
+ struct redir_struct *redirects; /* I/O redirections */
+ glob_t glob_result; /* result of parameter globbing */
+ int is_stopped; /* is the program currently running? */
+ struct pipe *family; /* pointer back to the child's parent pipe */
+#endif
+ int sp; /* number of SPECIAL_VAR_SYMBOL */
+ int type;
+};
+
+struct pipe {
+#ifndef __U_BOOT__
+ int jobid; /* job number */
+#endif
+ int num_progs; /* total number of programs in job */
+#ifndef __U_BOOT__
+ int running_progs; /* number of programs running */
+ char *text; /* name of job */
+ char *cmdbuf; /* buffer various argv's point into */
+ pid_t pgrp; /* process group ID for the job */
+#endif
+ struct child_prog *progs; /* array of commands in pipe */
+ struct pipe *next; /* to track background commands */
+#ifndef __U_BOOT__
+ int stopped_progs; /* number of programs alive, but stopped */
+ int job_context; /* bitmask defining current context */
+#endif
+ pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
+ reserved_style r_mode; /* supports if, for, while, until */
+};
+
+#ifndef __U_BOOT__
+struct close_me {
+ int fd;
+ struct close_me *next;
+};
+#endif
+
+struct variables {
+ char *name;
+ char *value;
+ int flg_export;
+ int flg_read_only;
+ struct variables *next;
+};
+
+/* globals, connect us to the outside world
+ * the first three support $?, $#, and $1 */
+#ifndef __U_BOOT__
+char **global_argv;
+unsigned int global_argc;
+#endif
+unsigned int last_return_code;
+int nesting_level;
+#ifndef __U_BOOT__
+extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
+#endif
+
+/* "globals" within this file */
+static uchar *ifs;
+static char map[256];
+#ifndef __U_BOOT__
+static int fake_mode;
+static int interactive;
+static struct close_me *close_me_head;
+static const char *cwd;
+static struct pipe *job_list;
+static unsigned int last_bg_pid;
+static unsigned int last_jobid;
+static unsigned int shell_terminal;
+static char *PS1;
+static char *PS2;
+struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
+struct variables *top_vars = &shell_ver;
+#else
+static int flag_repeat = 0;
+static int do_repeat = 0;
+static struct variables *top_vars = NULL ;
+#endif /*__U_BOOT__ */
+
+#define B_CHUNK (100)
+#define B_NOSPAC 1
+
+typedef struct {
+ char *data;
+ int length;
+ int maxlen;
+ int quote;
+ int nonnull;
+} o_string;
+#define NULL_O_STRING {NULL,0,0,0,0}
+/* used for initialization:
+ o_string foo = NULL_O_STRING; */
+
+/* I can almost use ordinary FILE *. Is open_memstream() universally
+ * available? Where is it documented? */
+struct in_str {
+ const char *p;
+#ifndef __U_BOOT__
+ char peek_buf[2];
+#endif
+ int __promptme;
+ int promptmode;
+#ifndef __U_BOOT__
+ FILE *file;
+#endif
+ int (*get) (struct in_str *);
+ int (*peek) (struct in_str *);
+};
+#define b_getch(input) ((input)->get(input))
+#define b_peek(input) ((input)->peek(input))
+
+#ifndef __U_BOOT__
+#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+
+struct built_in_command {
+ char *cmd; /* name */
+ char *descr; /* description */
+ int (*function) (struct child_prog *); /* function ptr */
+};
+#endif
+
+/* define DEBUG_SHELL for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG_SHELL
+#endif
+
+/* This should be in utility.c */
+#ifdef DEBUG_SHELL
+#ifndef __U_BOOT__
+static void debug_printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+#else
+#define debug_printf(fmt,args...) printf (fmt ,##args)
+#endif
+#else
+static inline void debug_printf(const char *format, ...) { }
+#endif
+#define final_printf debug_printf
+
+#ifdef __U_BOOT__
+static void syntax_err(void) {
+ printf("syntax error\n");
+}
+#else
+static void __syntax(char *file, int line) {
+ error_msg("syntax error %s:%d", file, line);
+}
+#define syntax() __syntax(__FILE__, __LINE__)
+#endif
+
+#ifdef __U_BOOT__
+static void *xmalloc(size_t size);
+static void *xrealloc(void *ptr, size_t size);
+#else
+/* Index of subroutines: */
+/* function prototypes for builtins */
+static int builtin_cd(struct child_prog *child);
+static int builtin_env(struct child_prog *child);
+static int builtin_eval(struct child_prog *child);
+static int builtin_exec(struct child_prog *child);
+static int builtin_exit(struct child_prog *child);
+static int builtin_export(struct child_prog *child);
+static int builtin_fg_bg(struct child_prog *child);
+static int builtin_help(struct child_prog *child);
+static int builtin_jobs(struct child_prog *child);
+static int builtin_pwd(struct child_prog *child);
+static int builtin_read(struct child_prog *child);
+static int builtin_set(struct child_prog *child);
+static int builtin_shift(struct child_prog *child);
+static int builtin_source(struct child_prog *child);
+static int builtin_umask(struct child_prog *child);
+static int builtin_unset(struct child_prog *child);
+static int builtin_not_written(struct child_prog *child);
+#endif
+/* o_string manipulation: */
+static int b_check_space(o_string *o, int len);
+static int b_addchr(o_string *o, int ch);
+static void b_reset(o_string *o);
+static int b_addqchr(o_string *o, int ch, int quote);
+#ifndef __U_BOOT__
+static int b_adduint(o_string *o, unsigned int i);
+#endif
+/* in_str manipulations: */
+static int static_get(struct in_str *i);
+static int static_peek(struct in_str *i);
+static int file_get(struct in_str *i);
+static int file_peek(struct in_str *i);
+#ifndef __U_BOOT__
+static void setup_file_in_str(struct in_str *i, FILE *f);
+#else
+static void setup_file_in_str(struct in_str *i);
+#endif
+static void setup_string_in_str(struct in_str *i, const char *s);
+#ifndef __U_BOOT__
+/* close_me manipulations: */
+static void mark_open(int fd);
+static void mark_closed(int fd);
+static void close_all(void);
+#endif
+/* "run" the final data structures: */
+static char *indenter(int i);
+static int free_pipe_list(struct pipe *head, int indent);
+static int free_pipe(struct pipe *pi, int indent);
+/* really run the final data structures: */
+#ifndef __U_BOOT__
+static int setup_redirects(struct child_prog *prog, int squirrel[]);
+#endif
+static int run_list_real(struct pipe *pi);
+#ifndef __U_BOOT__
+static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
+#endif
+static int run_pipe_real(struct pipe *pi);
+/* extended glob support: */
+#ifndef __U_BOOT__
+static int globhack(const char *src, int flags, glob_t *pglob);
+static int glob_needed(const char *s);
+static int xglob(o_string *dest, int flags, glob_t *pglob);
+#endif
+/* variable assignment: */
+static int is_assignment(const char *s);
+/* data structure manipulation: */
+#ifndef __U_BOOT__
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
+#endif
+static void initialize_context(struct p_context *ctx);
+static int done_word(o_string *dest, struct p_context *ctx);
+static int done_command(struct p_context *ctx);
+static int done_pipe(struct p_context *ctx, pipe_style type);
+/* primary string parsing: */
+#ifndef __U_BOOT__
+static int redirect_dup_num(struct in_str *input);
+static int redirect_opt_num(o_string *o);
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
+static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
+#endif
+static char *lookup_param(char *src);
+static char *make_string(char **inp);
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
+#ifndef __U_BOOT__
+static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
+#endif
+static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
+/* setup: */
+static int parse_stream_outer(struct in_str *inp, int flag);
+#ifndef __U_BOOT__
+static int parse_string_outer(const char *s, int flag);
+static int parse_file_outer(FILE *f);
+#endif
+#ifndef __U_BOOT__
+/* job management: */
+static int checkjobs(struct pipe* fg_pipe);
+static void insert_bg_job(struct pipe *pi);
+static void remove_bg_job(struct pipe *pi);
+#endif
+/* local variable support */
+static char **make_list_in(char **inp, char *name);
+static char *insert_var_value(char *inp);
+static char *get_local_var(const char *var);
+
+#ifndef __U_BOOT__
+/* Table of built-in functions. They can be forked or not, depending on
+ * context: within pipes, they fork. As simple commands, they do not.
+ * When used in non-forking context, they can change global variables
+ * in the parent shell process. If forked, of course they can not.
+ * For example, 'unset foo | whatever' will parse and run, but foo will
+ * still be set at the end. */
+static struct built_in_command bltins[] = {
+ {"bg", "Resume a job in the background", builtin_fg_bg},
+ {"break", "Exit for, while or until loop", builtin_not_written},
+ {"cd", "Change working directory", builtin_cd},
+ {"continue", "Continue for, while or until loop", builtin_not_written},
+ {"env", "Print all environment variables", builtin_env},
+ {"eval", "Construct and run shell command", builtin_eval},
+ {"exec", "Exec command, replacing this shell with the exec'd process",
+ builtin_exec},
+ {"exit", "Exit from shell()", builtin_exit},
+ {"export", "Set environment variable", builtin_export},
+ {"fg", "Bring job into the foreground", builtin_fg_bg},
+ {"jobs", "Lists the active jobs", builtin_jobs},
+ {"pwd", "Print current directory", builtin_pwd},
+ {"read", "Input environment variable", builtin_read},
+ {"return", "Return from a function", builtin_not_written},
+ {"set", "Set/unset shell local variables", builtin_set},
+ {"shift", "Shift positional parameters", builtin_shift},
+ {"trap", "Trap signals", builtin_not_written},
+ {"ulimit","Controls resource limits", builtin_not_written},
+ {"umask","Sets file creation mask", builtin_umask},
+ {"unset", "Unset environment variable", builtin_unset},
+ {".", "Source-in and run commands in a file", builtin_source},
+ {"help", "List shell built-in commands", builtin_help},
+ {NULL, NULL, NULL}
+};
+
+static const char *set_cwd(void)
+{
+ if(cwd==unknown)
+ cwd = NULL; /* xgetcwd(arg) called free(arg) */
+ cwd = xgetcwd((char *)cwd);
+ if (!cwd)
+ cwd = unknown;
+ return cwd;
+}
+
+/* built-in 'eval' handler */
+static int builtin_eval(struct child_prog *child)
+{
+ char *str = NULL;
+ int rcode = EXIT_SUCCESS;
+
+ if (child->argv[1]) {
+ str = make_string(child->argv + 1);
+ parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
+ FLAG_PARSE_SEMICOLON);
+ free(str);
+ rcode = last_return_code;
+ }
+ return rcode;
+}
+
+/* built-in 'cd <path>' handler */
+static int builtin_cd(struct child_prog *child)
+{
+ char *newdir;
+ if (child->argv[1] == NULL)
+ newdir = getenv("HOME");
+ else
+ newdir = child->argv[1];
+ if (chdir(newdir)) {
+ printf("cd: %s: %s\n", newdir, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ set_cwd();
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'env' handler */
+static int builtin_env(struct child_prog *dummy)
+{
+ char **e = environ;
+ if (e == NULL) return EXIT_FAILURE;
+ for (; *e; e++) {
+ puts(*e);
+ }
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'exec' handler */
+static int builtin_exec(struct child_prog *child)
+{
+ if (child->argv[1] == NULL)
+ return EXIT_SUCCESS; /* Really? */
+ child->argv++;
+ pseudo_exec(child);
+ /* never returns */
+}
+
+/* built-in 'exit' handler */
+static int builtin_exit(struct child_prog *child)
+{
+ if (child->argv[1] == NULL)
+ exit(last_return_code);
+ exit (atoi(child->argv[1]));
+}
+
+/* built-in 'export VAR=value' handler */
+static int builtin_export(struct child_prog *child)
+{
+ int res = 0;
+ char *name = child->argv[1];
+
+ if (name == NULL) {
+ return (builtin_env(child));
+ }
+
+ name = strdup(name);
+
+ if(name) {
+ char *value = strchr(name, '=');
+
+ if (!value) {
+ char *tmp;
+ /* They are exporting something without an =VALUE */
+
+ value = get_local_var(name);
+ if (value) {
+ size_t ln = strlen(name);
+
+ tmp = realloc(name, ln+strlen(value)+2);
+ if(tmp==NULL)
+ res = -1;
+ else {
+ sprintf(tmp+ln, "=%s", value);
+ name = tmp;
+ }
+ } else {
+ /* bash does not return an error when trying to export
+ * an undefined variable. Do likewise. */
+ res = 1;
+ }
+ }
+ }
+ if (res<0)
+ perror_msg("export");
+ else if(res==0)
+ res = set_local_var(name, 1);
+ else
+ res = 0;
+ free(name);
+ return res;
+}
+
+/* built-in 'fg' and 'bg' handler */
+static int builtin_fg_bg(struct child_prog *child)
+{
+ int i, jobnum;
+ struct pipe *pi=NULL;
+
+ if (!interactive)
+ return EXIT_FAILURE;
+ /* If they gave us no args, assume they want the last backgrounded task */
+ if (!child->argv[1]) {
+ for (pi = job_list; pi; pi = pi->next) {
+ if (pi->jobid == last_jobid) {
+ break;
+ }
+ }
+ if (!pi) {
+ error_msg("%s: no current job", child->argv[0]);
+ return EXIT_FAILURE;
+ }
+ } else {
+ if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+ error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+ return EXIT_FAILURE;
+ }
+ for (pi = job_list; pi; pi = pi->next) {
+ if (pi->jobid == jobnum) {
+ break;
+ }
+ }
+ if (!pi) {
+ error_msg("%s: %d: no such job", child->argv[0], jobnum);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (*child->argv[0] == 'f') {
+ /* Put the job into the foreground. */
+ tcsetpgrp(shell_terminal, pi->pgrp);
+ }
+
+ /* Restart the processes in the job */
+ for (i = 0; i < pi->num_progs; i++)
+ pi->progs[i].is_stopped = 0;
+
+ if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
+ if (i == ESRCH) {
+ remove_bg_job(pi);
+ } else {
+ perror_msg("kill (SIGCONT)");
+ }
+ }
+
+ pi->stopped_progs = 0;
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'help' handler */
+static int builtin_help(struct child_prog *dummy)
+{
+ struct built_in_command *x;
+
+ printf("\nBuilt-in commands:\n");
+ printf("-------------------\n");
+ for (x = bltins; x->cmd; x++) {
+ if (x->descr==NULL)
+ continue;
+ printf("%s\t%s\n", x->cmd, x->descr);
+ }
+ printf("\n\n");
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'jobs' handler */
+static int builtin_jobs(struct child_prog *child)
+{
+ struct pipe *job;
+ char *status_string;
+
+ for (job = job_list; job; job = job->next) {
+ if (job->running_progs == job->stopped_progs)
+ status_string = "Stopped";
+ else
+ status_string = "Running";
+
+ printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
+ }
+ return EXIT_SUCCESS;
+}
+
+
+/* built-in 'pwd' handler */
+static int builtin_pwd(struct child_prog *dummy)
+{
+ puts(set_cwd());
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'read VAR' handler */
+static int builtin_read(struct child_prog *child)
+{
+ int res;
+
+ if (child->argv[1]) {
+ char string[BUFSIZ];
+ char *var = 0;
+
+ string[0] = 0; /* In case stdin has only EOF */
+ /* read string */
+ fgets(string, sizeof(string), stdin);
+ chomp(string);
+ var = malloc(strlen(child->argv[1])+strlen(string)+2);
+ if(var) {
+ sprintf(var, "%s=%s", child->argv[1], string);
+ res = set_local_var(var, 0);
+ } else
+ res = -1;
+ if (res)
+ fprintf(stderr, "read: %m\n");
+ free(var); /* So not move up to avoid breaking errno */
+ return res;
+ } else {
+ do res=getchar(); while(res!='\n' && res!=EOF);
+ return 0;
+ }
+}
+
+/* built-in 'set VAR=value' handler */
+static int builtin_set(struct child_prog *child)
+{
+ char *temp = child->argv[1];
+ struct variables *e;
+
+ if (temp == NULL)
+ for(e = top_vars; e; e=e->next)
+ printf("%s=%s\n", e->name, e->value);
+ else
+ set_local_var(temp, 0);
+
+ return EXIT_SUCCESS;
+}
+
+
+/* Built-in 'shift' handler */
+static int builtin_shift(struct child_prog *child)
+{
+ int n=1;
+ if (child->argv[1]) {
+ n=atoi(child->argv[1]);
+ }
+ if (n>=0 && n<global_argc) {
+ /* XXX This probably breaks $0 */
+ global_argc -= n;
+ global_argv += n;
+ return EXIT_SUCCESS;
+ } else {
+ return EXIT_FAILURE;
+ }
+}
+
+/* Built-in '.' handler (read-in and execute commands from file) */
+static int builtin_source(struct child_prog *child)
+{
+ FILE *input;
+ int status;
+
+ if (child->argv[1] == NULL)
+ return EXIT_FAILURE;
+
+ /* XXX search through $PATH is missing */
+ input = fopen(child->argv[1], "r");
+ if (!input) {
+ error_msg("Couldn't open file '%s'", child->argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ /* Now run the file */
+ /* XXX argv and argc are broken; need to save old global_argv
+ * (pointer only is OK!) on this stack frame,
+ * set global_argv=child->argv+1, recurse, and restore. */
+ mark_open(fileno(input));
+ status = parse_file_outer(input);
+ mark_closed(fileno(input));
+ fclose(input);
+ return (status);
+}
+
+static int builtin_umask(struct child_prog *child)
+{
+ mode_t new_umask;
+ const char *arg = child->argv[1];
+ char *end;
+ if (arg) {
+ new_umask=strtoul(arg, &end, 8);
+ if (*end!='\0' || end == arg) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
+ }
+ umask(new_umask);
+ return EXIT_SUCCESS;
+}
+
+/* built-in 'unset VAR' handler */
+static int builtin_unset(struct child_prog *child)
+{
+ /* bash returned already true */
+ unset_local_var(child->argv[1]);
+ return EXIT_SUCCESS;
+}
+
+static int builtin_not_written(struct child_prog *child)
+{
+ printf("builtin_%s not written\n",child->argv[0]);
+ return EXIT_FAILURE;
+}
+#endif
+
+static int b_check_space(o_string *o, int len)
+{
+ /* It would be easy to drop a more restrictive policy
+ * in here, such as setting a maximum string length */
+ if (o->length + len > o->maxlen) {
+ char *old_data = o->data;
+ /* assert (data == NULL || o->maxlen != 0); */
+ o->maxlen += max(2*len, B_CHUNK);
+ o->data = realloc(o->data, 1 + o->maxlen);
+ if (o->data == NULL) {
+ free(old_data);
+ }
+ }
+ return o->data == NULL;
+}
+
+static int b_addchr(o_string *o, int ch)
+{
+ debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
+ if (b_check_space(o, 1)) return B_NOSPAC;
+ o->data[o->length] = ch;
+ o->length++;
+ o->data[o->length] = '\0';
+ return 0;
+}
+
+static void b_reset(o_string *o)
+{
+ o->length = 0;
+ o->nonnull = 0;
+ if (o->data != NULL) *o->data = '\0';
+}
+
+static void b_free(o_string *o)
+{
+ b_reset(o);
+ free(o->data);
+ o->data = NULL;
+ o->maxlen = 0;
+}
+
+/* My analysis of quoting semantics tells me that state information
+ * is associated with a destination, not a source.
+ */
+static int b_addqchr(o_string *o, int ch, int quote)
+{
+ if (quote && strchr("*?[\\",ch)) {
+ int rc;
+ rc = b_addchr(o, '\\');
+ if (rc) return rc;
+ }
+ return b_addchr(o, ch);
+}
+
+/* belongs in utility.c */
+char *simple_itoa(unsigned int i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ static char local[22];
+ char *p = &local[21];
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
+
+#ifndef __U_BOOT__
+static int b_adduint(o_string *o, unsigned int i)
+{
+ int r;
+ char *p = simple_itoa(i);
+ /* no escape checking necessary */
+ do r=b_addchr(o, *p++); while (r==0 && *p);
+ return r;
+}
+#endif
+
+static int static_get(struct in_str *i)
+{
+ int ch = *i->p++;
+ if (ch=='\0') return EOF;
+ return ch;
+}
+
+static int static_peek(struct in_str *i)
+{
+ return *i->p;
+}
+
+#ifndef __U_BOOT__
+static inline void cmdedit_set_initial_prompt(void)
+{
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
+ PS1 = NULL;
+#else
+ PS1 = getenv("PS1");
+ if(PS1==0)
+ PS1 = "\\w \\$ ";
+#endif
+}
+
+static inline void setup_prompt_string(int promptmode, char **prompt_str)
+{
+ debug_printf("setup_prompt_string %d ",promptmode);
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
+ /* Set up the prompt */
+ if (promptmode == 1) {
+ free(PS1);
+ PS1=xmalloc(strlen(cwd)+4);
+ sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
+ *prompt_str = PS1;
+ } else {
+ *prompt_str = PS2;
+ }
+#else
+ *prompt_str = (promptmode==1)? PS1 : PS2;
+#endif
+ debug_printf("result %s\n",*prompt_str);
+}
+#endif
+
+static void get_user_input(struct in_str *i)
+{
+#ifndef __U_BOOT__
+ char *prompt_str;
+ static char the_command[BUFSIZ];
+
+ setup_prompt_string(i->promptmode, &prompt_str);
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
+ /*
+ ** enable command line editing only while a command line
+ ** is actually being read; otherwise, we'll end up bequeathing
+ ** atexit() handlers and other unwanted stuff to our
+ ** child processes (rob@sysgo.de)
+ */
+ cmdedit_read_input(prompt_str, the_command);
+#else
+ fputs(prompt_str, stdout);
+ fflush(stdout);
+ the_command[0]=fgetc(i->file);
+ the_command[1]='\0';
+#endif
+ fflush(stdout);
+ i->p = the_command;
+#else
+ extern char console_buffer[];
+ int n;
+ static char the_command[CONFIG_SYS_CBSIZE];
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+# ifndef CONFIG_RESET_TO_RETRY
+# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# endif
+ reset_cmd_timeout();
+#endif
+ i->__promptme = 1;
+ if (i->promptmode == 1) {
+ n = readline(CONFIG_SYS_PROMPT);
+ } else {
+ n = readline(CONFIG_SYS_PROMPT_HUSH_PS2);
+ }
+#ifdef CONFIG_BOOT_RETRY_TIME
+ if (n == -2) {
+ puts("\nTimeout waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ do_reset(NULL, 0, 0, NULL);
+# else
+# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# endif
+ }
+#endif
+ if (n == -1 ) {
+ flag_repeat = 0;
+ i->__promptme = 0;
+ }
+ n = strlen(console_buffer);
+ console_buffer[n] = '\n';
+ console_buffer[n+1]= '\0';
+ if (had_ctrlc()) flag_repeat = 0;
+ clear_ctrlc();
+ do_repeat = 0;
+ if (i->promptmode == 1) {
+ if (console_buffer[0] == '\n'&& flag_repeat == 0) {
+ strcpy(the_command,console_buffer);
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ strcpy(the_command,console_buffer);
+ flag_repeat = 1;
+ }
+ else {
+ do_repeat = 1;
+ }
+ }
+ i->p = the_command;
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ if (strlen(the_command) + strlen(console_buffer)
+ < CONFIG_SYS_CBSIZE) {
+ n = strlen(the_command);
+ the_command[n-1] = ' ';
+ strcpy(&the_command[n],console_buffer);
+ }
+ else {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ flag_repeat = 0;
+ }
+ }
+ if (i->__promptme == 0) {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ }
+ i->p = console_buffer;
+ }
+#endif
+}
+
+/* This is the magic location that prints prompts
+ * and gets data back from the user */
+static int file_get(struct in_str *i)
+{
+ int ch;
+
+ ch = 0;
+ /* If there is data waiting, eat it up */
+ if (i->p && *i->p) {
+ ch = *i->p++;
+ } else {
+ /* need to double check i->file because we might be doing something
+ * more complicated by now, like sourcing or substituting. */
+#ifndef __U_BOOT__
+ if (i->__promptme && interactive && i->file == stdin) {
+ while(! i->p || (interactive && strlen(i->p)==0) ) {
+#else
+ while(! i->p || strlen(i->p)==0 ) {
+#endif
+ get_user_input(i);
+ }
+ i->promptmode=2;
+#ifndef __U_BOOT__
+ i->__promptme = 0;
+#endif
+ if (i->p && *i->p) {
+ ch = *i->p++;
+ }
+#ifndef __U_BOOT__
+ } else {
+ ch = fgetc(i->file);
+ }
+
+#endif
+ debug_printf("b_getch: got a %d\n", ch);
+ }
+#ifndef __U_BOOT__
+ if (ch == '\n') i->__promptme=1;
+#endif
+ return ch;
+}
+
+/* All the callers guarantee this routine will never be
+ * used right after a newline, so prompting is not needed.
+ */
+static int file_peek(struct in_str *i)
+{
+#ifndef __U_BOOT__
+ if (i->p && *i->p) {
+#endif
+ return *i->p;
+#ifndef __U_BOOT__
+ } else {
+ i->peek_buf[0] = fgetc(i->file);
+ i->peek_buf[1] = '\0';
+ i->p = i->peek_buf;
+ debug_printf("b_peek: got a %d\n", *i->p);
+ return *i->p;
+ }
+#endif
+}
+
+#ifndef __U_BOOT__
+static void setup_file_in_str(struct in_str *i, FILE *f)
+#else
+static void setup_file_in_str(struct in_str *i)
+#endif
+{
+ i->peek = file_peek;
+ i->get = file_get;
+ i->__promptme=1;
+ i->promptmode=1;
+#ifndef __U_BOOT__
+ i->file = f;
+#endif
+ i->p = NULL;
+}
+
+static void setup_string_in_str(struct in_str *i, const char *s)
+{
+ i->peek = static_peek;
+ i->get = static_get;
+ i->__promptme=1;
+ i->promptmode=1;
+ i->p = s;
+}
+
+#ifndef __U_BOOT__
+static void mark_open(int fd)
+{
+ struct close_me *new = xmalloc(sizeof(struct close_me));
+ new->fd = fd;
+ new->next = close_me_head;
+ close_me_head = new;
+}
+
+static void mark_closed(int fd)
+{
+ struct close_me *tmp;
+ if (close_me_head == NULL || close_me_head->fd != fd)
+ error_msg_and_die("corrupt close_me");
+ tmp = close_me_head;
+ close_me_head = close_me_head->next;
+ free(tmp);
+}
+
+static void close_all(void)
+{
+ struct close_me *c;
+ for (c=close_me_head; c; c=c->next) {
+ close(c->fd);
+ }
+ close_me_head = NULL;
+}
+
+/* squirrel != NULL means we squirrel away copies of stdin, stdout,
+ * and stderr if they are redirected. */
+static int setup_redirects(struct child_prog *prog, int squirrel[])
+{
+ int openfd, mode;
+ struct redir_struct *redir;
+
+ for (redir=prog->redirects; redir; redir=redir->next) {
+ if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
+ /* something went wrong in the parse. Pretend it didn't happen */
+ continue;
+ }
+ if (redir->dup == -1) {
+ mode=redir_table[redir->type].mode;
+ openfd = open(redir->word.gl_pathv[0], mode, 0666);
+ if (openfd < 0) {
+ /* this could get lost if stderr has been redirected, but
+ bash and ash both lose it as well (though zsh doesn't!) */
+ perror_msg("error opening %s", redir->word.gl_pathv[0]);
+ return 1;
+ }
+ } else {
+ openfd = redir->dup;
+ }
+
+ if (openfd != redir->fd) {
+ if (squirrel && redir->fd < 3) {
+ squirrel[redir->fd] = dup(redir->fd);
+ }
+ if (openfd == -3) {
+ close(openfd);
+ } else {
+ dup2(openfd, redir->fd);
+ if (redir->dup == -1)
+ close (openfd);
+ }
+ }
+ }
+ return 0;
+}
+
+static void restore_redirects(int squirrel[])
+{
+ int i, fd;
+ for (i=0; i<3; i++) {
+ fd = squirrel[i];
+ if (fd != -1) {
+ /* No error checking. I sure wouldn't know what
+ * to do with an error if I found one! */
+ dup2(fd, i);
+ close(fd);
+ }
+ }
+}
+
+/* never returns */
+/* XXX no exit() here. If you don't exec, use _exit instead.
+ * The at_exit handlers apparently confuse the calling process,
+ * in particular stdin handling. Not sure why? */
+static void pseudo_exec(struct child_prog *child)
+{
+ int i, rcode;
+ char *p;
+ struct built_in_command *x;
+ if (child->argv) {
+ for (i=0; is_assignment(child->argv[i]); i++) {
+ debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
+ p = insert_var_value(child->argv[i]);
+ putenv(strdup(p));
+ if (p != child->argv[i]) free(p);
+ }
+ child->argv+=i; /* XXX this hack isn't so horrible, since we are about
+ to exit, and therefore don't need to keep data
+ structures consistent for free() use. */
+ /* If a variable is assigned in a forest, and nobody listens,
+ * was it ever really set?
+ */
+ if (child->argv[0] == NULL) {
+ _exit(EXIT_SUCCESS);
+ }
+
+ /*
+ * Check if the command matches any of the builtins.
+ * Depending on context, this might be redundant. But it's
+ * easier to waste a few CPU cycles than it is to figure out
+ * if this is one of those cases.
+ */
+ for (x = bltins; x->cmd; x++) {
+ if (strcmp(child->argv[0], x->cmd) == 0 ) {
+ debug_printf("builtin exec %s\n", child->argv[0]);
+ rcode = x->function(child);
+ fflush(stdout);
+ _exit(rcode);
+ }
+ }
+
+ /* Check if the command matches any busybox internal commands
+ * ("applets") here.
+ * FIXME: This feature is not 100% safe, since
+ * BusyBox is not fully reentrant, so we have no guarantee the things
+ * from the .bss are still zeroed, or that things from .data are still
+ * at their defaults. We could exec ourself from /proc/self/exe, but I
+ * really dislike relying on /proc for things. We could exec ourself
+ * from global_argv[0], but if we are in a chroot, we may not be able
+ * to find ourself... */
+#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+ {
+ int argc_l;
+ char** argv_l=child->argv;
+ char *name = child->argv[0];
+
+#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
+ /* Following discussions from November 2000 on the busybox mailing
+ * list, the default configuration, (without
+ * get_last_path_component()) lets the user force use of an
+ * external command by specifying the full (with slashes) filename.
+ * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN then applets
+ * _aways_ override external commands, so if you want to run
+ * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
+ * filesystem and is _not_ busybox. Some systems may want this,
+ * most do not. */
+ name = get_last_path_component(name);
+#endif
+ /* Count argc for use in a second... */
+ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+ optind = 1;
+ debug_printf("running applet %s\n", name);
+ run_applet_by_name(name, argc_l, child->argv);
+ }
+#endif
+ debug_printf("exec of %s\n",child->argv[0]);
+ execvp(child->argv[0],child->argv);
+ perror_msg("couldn't exec: %s",child->argv[0]);
+ _exit(1);
+ } else if (child->group) {
+ debug_printf("runtime nesting to group\n");
+ interactive=0; /* crucial!!!! */
+ rcode = run_list_real(child->group);
+ /* OK to leak memory by not calling free_pipe_list,
+ * since this process is about to exit */
+ _exit(rcode);
+ } else {
+ /* Can happen. See what bash does with ">foo" by itself. */
+ debug_printf("trying to pseudo_exec null command\n");
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+static void insert_bg_job(struct pipe *pi)
+{
+ struct pipe *thejob;
+
+ /* Linear search for the ID of the job to use */
+ pi->jobid = 1;
+ for (thejob = job_list; thejob; thejob = thejob->next)
+ if (thejob->jobid >= pi->jobid)
+ pi->jobid = thejob->jobid + 1;
+
+ /* add thejob to the list of running jobs */
+ if (!job_list) {
+ thejob = job_list = xmalloc(sizeof(*thejob));
+ } else {
+ for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
+ thejob->next = xmalloc(sizeof(*thejob));
+ thejob = thejob->next;
+ }
+
+ /* physically copy the struct job */
+ memcpy(thejob, pi, sizeof(struct pipe));
+ thejob->next = NULL;
+ thejob->running_progs = thejob->num_progs;
+ thejob->stopped_progs = 0;
+ thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
+
+ /*if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) */
+ {
+ char *bar=thejob->text;
+ char **foo=pi->progs[0].argv;
+ while(foo && *foo) {
+ bar += sprintf(bar, "%s ", *foo++);
+ }
+ }
+
+ /* we don't wait for background thejobs to return -- append it
+ to the list of backgrounded thejobs and leave it alone */
+ printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
+ last_bg_pid = thejob->progs[0].pid;
+ last_jobid = thejob->jobid;
+}
+
+/* remove a backgrounded job */
+static void remove_bg_job(struct pipe *pi)
+{
+ struct pipe *prev_pipe;
+
+ if (pi == job_list) {
+ job_list = pi->next;
+ } else {
+ prev_pipe = job_list;
+ while (prev_pipe->next != pi)
+ prev_pipe = prev_pipe->next;
+ prev_pipe->next = pi->next;
+ }
+ if (job_list)
+ last_jobid = job_list->jobid;
+ else
+ last_jobid = 0;
+
+ pi->stopped_progs = 0;
+ free_pipe(pi, 0);
+ free(pi);
+}
+
+/* Checks to see if any processes have exited -- if they
+ have, figure out why and see if a job has completed */
+static int checkjobs(struct pipe* fg_pipe)
+{
+ int attributes;
+ int status;
+ int prognum = 0;
+ struct pipe *pi;
+ pid_t childpid;
+
+ attributes = WUNTRACED;
+ if (fg_pipe==NULL) {
+ attributes |= WNOHANG;
+ }
+
+ while ((childpid = waitpid(-1, &status, attributes)) > 0) {
+ if (fg_pipe) {
+ int i, rcode = 0;
+ for (i=0; i < fg_pipe->num_progs; i++) {
+ if (fg_pipe->progs[i].pid == childpid) {
+ if (i==fg_pipe->num_progs-1)
+ rcode=WEXITSTATUS(status);
+ (fg_pipe->num_progs)--;
+ return(rcode);
+ }
+ }
+ }
+
+ for (pi = job_list; pi; pi = pi->next) {
+ prognum = 0;
+ while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
+ prognum++;
+ }
+ if (prognum < pi->num_progs)
+ break;
+ }
+
+ if(pi==NULL) {
+ debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
+ continue;
+ }
+
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ /* child exited */
+ pi->running_progs--;
+ pi->progs[prognum].pid = 0;
+
+ if (!pi->running_progs) {
+ printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
+ remove_bg_job(pi);
+ }
+ } else {
+ /* child stopped */
+ pi->stopped_progs++;
+ pi->progs[prognum].is_stopped = 1;
+
+#if 0
+ /* Printing this stuff is a pain, since it tends to
+ * overwrite the prompt an inconveinient moments. So
+ * don't do that. */
+ if (pi->stopped_progs == pi->num_progs) {
+ printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
+ }
+#endif
+ }
+ }
+
+ if (childpid == -1 && errno != ECHILD)
+ perror_msg("waitpid");
+
+ /* move the shell to the foreground */
+ /*if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) */
+ /* perror_msg("tcsetpgrp-2"); */
+ return -1;
+}
+
+/* Figure out our controlling tty, checking in order stderr,
+ * stdin, and stdout. If check_pgrp is set, also check that
+ * we belong to the foreground process group associated with
+ * that tty. The value of shell_terminal is needed in order to call
+ * tcsetpgrp(shell_terminal, ...); */
+void controlling_tty(int check_pgrp)
+{
+ pid_t curpgrp;
+
+ if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
+ && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
+ && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
+ goto shell_terminal_error;
+
+ if (check_pgrp && curpgrp != getpgid(0))
+ goto shell_terminal_error;
+
+ return;
+
+shell_terminal_error:
+ shell_terminal = -1;
+ return;
+}
+#endif
+
+/* run_pipe_real() starts all the jobs, but doesn't wait for anything
+ * to finish. See checkjobs().
+ *
+ * return code is normally -1, when the caller has to wait for children
+ * to finish to determine the exit status of the pipe. If the pipe
+ * is a simple builtin command, however, the action is done by the
+ * time run_pipe_real returns, and the exit code is provided as the
+ * return value.
+ *
+ * The input of the pipe is always stdin, the output is always
+ * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
+ * because it tries to avoid running the command substitution in
+ * subshell, when that is in fact necessary. The subshell process
+ * now has its stdout directed to the input of the appropriate pipe,
+ * so this routine is noticeably simpler.
+ */
+static int run_pipe_real(struct pipe *pi)
+{
+ int i;
+#ifndef __U_BOOT__
+ int nextin, nextout;
+ int pipefds[2]; /* pipefds[0] is for reading */
+ struct child_prog *child;
+ struct built_in_command *x;
+ char *p;
+# if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &i;
+ (void) &nextin;
+ (void) &nextout;
+ (void) &child;
+# endif
+#else
+ int nextin;
+ int flag = do_repeat ? CMD_FLAG_REPEAT : 0;
+ struct child_prog *child;
+ cmd_tbl_t *cmdtp;
+ char *p;
+# if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &i;
+ (void) &nextin;
+ (void) &child;
+# endif
+#endif /* __U_BOOT__ */
+
+ nextin = 0;
+#ifndef __U_BOOT__
+ pi->pgrp = -1;
+#endif
+
+ /* Check if this is a simple builtin (not part of a pipe).
+ * Builtins within pipes have to fork anyway, and are handled in
+ * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
+ */
+ if (pi->num_progs == 1) child = & (pi->progs[0]);
+#ifndef __U_BOOT__
+ if (pi->num_progs == 1 && child->group && child->subshell == 0) {
+ int squirrel[] = {-1, -1, -1};
+ int rcode;
+ debug_printf("non-subshell grouping\n");
+ setup_redirects(child, squirrel);
+ /* XXX could we merge code with following builtin case,
+ * by creating a pseudo builtin that calls run_list_real? */
+ rcode = run_list_real(child->group);
+ restore_redirects(squirrel);
+#else
+ if (pi->num_progs == 1 && child->group) {
+ int rcode;
+ debug_printf("non-subshell grouping\n");
+ rcode = run_list_real(child->group);
+#endif
+ return rcode;
+ } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
+ for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
+ if (i!=0 && child->argv[i]==NULL) {
+ /* assignments, but no command: set the local environment */
+ for (i=0; child->argv[i]!=NULL; i++) {
+
+ /* Ok, this case is tricky. We have to decide if this is a
+ * local variable, or an already exported variable. If it is
+ * already exported, we have to export the new value. If it is
+ * not exported, we need only set this as a local variable.
+ * This junk is all to decide whether or not to export this
+ * variable. */
+ int export_me=0;
+ char *name, *value;
+ name = xstrdup(child->argv[i]);
+ debug_printf("Local environment set: %s\n", name);
+ value = strchr(name, '=');
+ if (value)
+ *value=0;
+#ifndef __U_BOOT__
+ if ( get_local_var(name)) {
+ export_me=1;
+ }
+#endif
+ free(name);
+ p = insert_var_value(child->argv[i]);
+ set_local_var(p, export_me);
+ if (p != child->argv[i]) free(p);
+ }
+ return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
+ }
+ for (i = 0; is_assignment(child->argv[i]); i++) {
+ p = insert_var_value(child->argv[i]);
+#ifndef __U_BOOT__
+ putenv(strdup(p));
+#else
+ set_local_var(p, 0);
+#endif
+ if (p != child->argv[i]) {
+ child->sp--;
+ free(p);
+ }
+ }
+ if (child->sp) {
+ char * str = NULL;
+
+ str = make_string((child->argv + i));
+ parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
+ free(str);
+ return last_return_code;
+ }
+#ifndef __U_BOOT__
+ for (x = bltins; x->cmd; x++) {
+ if (strcmp(child->argv[i], x->cmd) == 0 ) {
+ int squirrel[] = {-1, -1, -1};
+ int rcode;
+ if (x->function == builtin_exec && child->argv[i+1]==NULL) {
+ debug_printf("magic exec\n");
+ setup_redirects(child,NULL);
+ return EXIT_SUCCESS;
+ }
+ debug_printf("builtin inline %s\n", child->argv[0]);
+ /* XXX setup_redirects acts on file descriptors, not FILEs.
+ * This is perfect for work that comes after exec().
+ * Is it really safe for inline use? Experimentally,
+ * things seem to work with glibc. */
+ setup_redirects(child, squirrel);
+#else
+ /* check ";", because ,example , argv consist from
+ * "help;flinfo" must not execute
+ */
+ if (strchr(child->argv[i], ';')) {
+ printf ("Unknown command '%s' - try 'help' or use 'run' command\n",
+ child->argv[i]);
+ return -1;
+ }
+ /* Look up command in command table */
+
+
+ if ((cmdtp = find_cmd(child->argv[i])) == NULL) {
+ printf ("Unknown command '%s' - try 'help'\n", child->argv[i]);
+ return -1; /* give up after bad command */
+ } else {
+ int rcode;
+#if defined(CONFIG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ if (cmdtp->cmd == do_bootd) {
+ if (flag & CMD_FLAG_BOOTD) {
+ printf ("'bootd' recursion detected\n");
+ return -1;
+ }
+ else
+ flag |= CMD_FLAG_BOOTD;
+ }
+#endif
+ /* found - check max args */
+ if ((child->argc - i) > cmdtp->maxargs)
+ return cmd_usage(cmdtp);
+#endif
+ child->argv+=i; /* XXX horrible hack */
+#ifndef __U_BOOT__
+ rcode = x->function(child);
+#else
+ /* OK - call function to do the command */
+
+ rcode = (cmdtp->cmd)
+(cmdtp, flag,child->argc-i,&child->argv[i]);
+ if ( !cmdtp->repeatable )
+ flag_repeat = 0;
+
+
+#endif
+ child->argv-=i; /* XXX restore hack so free() can work right */
+#ifndef __U_BOOT__
+
+ restore_redirects(squirrel);
+#endif
+
+ return rcode;
+ }
+ }
+#ifndef __U_BOOT__
+ }
+
+ for (i = 0; i < pi->num_progs; i++) {
+ child = & (pi->progs[i]);
+
+ /* pipes are inserted between pairs of commands */
+ if ((i + 1) < pi->num_progs) {
+ if (pipe(pipefds)<0) perror_msg_and_die("pipe");
+ nextout = pipefds[1];
+ } else {
+ nextout=1;
+ pipefds[0] = -1;
+ }
+
+ /* XXX test for failed fork()? */
+ if (!(child->pid = fork())) {
+ /* Set the handling for job control signals back to the default. */
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGTSTP, SIG_DFL);
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+
+ close_all();
+
+ if (nextin != 0) {
+ dup2(nextin, 0);
+ close(nextin);
+ }
+ if (nextout != 1) {
+ dup2(nextout, 1);
+ close(nextout);
+ }
+ if (pipefds[0]!=-1) {
+ close(pipefds[0]); /* opposite end of our output pipe */
+ }
+
+ /* Like bash, explicit redirects override pipes,
+ * and the pipe fd is available for dup'ing. */
+ setup_redirects(child,NULL);
+
+ if (interactive && pi->followup!=PIPE_BG) {
+ /* If we (the child) win the race, put ourselves in the process
+ * group whose leader is the first process in this pipe. */
+ if (pi->pgrp < 0) {
+ pi->pgrp = getpid();
+ }
+ if (setpgid(0, pi->pgrp) == 0) {
+ tcsetpgrp(2, pi->pgrp);
+ }
+ }
+
+ pseudo_exec(child);
+ }
+
+
+ /* put our child in the process group whose leader is the
+ first process in this pipe */
+ if (pi->pgrp < 0) {
+ pi->pgrp = child->pid;
+ }
+ /* Don't check for errors. The child may be dead already,
+ * in which case setpgid returns error code EACCES. */
+ setpgid(child->pid, pi->pgrp);
+
+ if (nextin != 0)
+ close(nextin);
+ if (nextout != 1)
+ close(nextout);
+
+ /* If there isn't another process, nextin is garbage
+ but it doesn't matter */
+ nextin = pipefds[0];
+ }
+#endif
+ return -1;
+}
+
+static int run_list_real(struct pipe *pi)
+{
+ char *save_name = NULL;
+ char **list = NULL;
+ char **save_list = NULL;
+ struct pipe *rpipe;
+ int flag_rep = 0;
+#ifndef __U_BOOT__
+ int save_num_progs;
+#endif
+ int rcode=0, flag_skip=1;
+ int flag_restore = 0;
+ int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
+ reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
+ /* check syntax for "for" */
+ for (rpipe = pi; rpipe; rpipe = rpipe->next) {
+ if ((rpipe->r_mode == RES_IN ||
+ rpipe->r_mode == RES_FOR) &&
+ (rpipe->next == NULL)) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ return 1;
+ }
+ if ((rpipe->r_mode == RES_IN &&
+ (rpipe->next->r_mode == RES_IN &&
+ rpipe->next->progs->argv != NULL))||
+ (rpipe->r_mode == RES_FOR &&
+ rpipe->next->r_mode != RES_IN)) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ return 1;
+ }
+ }
+ for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
+ if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
+ pi->r_mode == RES_FOR) {
+#ifdef __U_BOOT__
+ /* check Ctrl-C */
+ ctrlc();
+ if ((had_ctrlc())) {
+ return 1;
+ }
+#endif
+ flag_restore = 0;
+ if (!rpipe) {
+ flag_rep = 0;
+ rpipe = pi;
+ }
+ }
+ rmode = pi->r_mode;
+ debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
+ if (rmode == skip_more_in_this_rmode && flag_skip) {
+ if (pi->followup == PIPE_SEQ) flag_skip=0;
+ continue;
+ }
+ flag_skip = 1;
+ skip_more_in_this_rmode = RES_XXXX;
+ if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
+ if (rmode == RES_THEN && if_code) continue;
+ if (rmode == RES_ELSE && !if_code) continue;
+ if (rmode == RES_ELIF && !if_code) break;
+ if (rmode == RES_FOR && pi->num_progs) {
+ if (!list) {
+ /* if no variable values after "in" we skip "for" */
+ if (!pi->next->progs->argv) continue;
+ /* create list of variable values */
+ list = make_list_in(pi->next->progs->argv,
+ pi->progs->argv[0]);
+ save_list = list;
+ save_name = pi->progs->argv[0];
+ pi->progs->argv[0] = NULL;
+ flag_rep = 1;
+ }
+ if (!(*list)) {
+ free(pi->progs->argv[0]);
+ free(save_list);
+ list = NULL;
+ flag_rep = 0;
+ pi->progs->argv[0] = save_name;
+#ifndef __U_BOOT__
+ pi->progs->glob_result.gl_pathv[0] =
+ pi->progs->argv[0];
+#endif
+ continue;
+ } else {
+ /* insert new value from list for variable */
+ if (pi->progs->argv[0])
+ free(pi->progs->argv[0]);
+ pi->progs->argv[0] = *list++;
+#ifndef __U_BOOT__
+ pi->progs->glob_result.gl_pathv[0] =
+ pi->progs->argv[0];
+#endif
+ }
+ }
+ if (rmode == RES_IN) continue;
+ if (rmode == RES_DO) {
+ if (!flag_rep) continue;
+ }
+ if ((rmode == RES_DONE)) {
+ if (flag_rep) {
+ flag_restore = 1;
+ } else {
+ rpipe = NULL;
+ }
+ }
+ if (pi->num_progs == 0) continue;
+#ifndef __U_BOOT__
+ save_num_progs = pi->num_progs; /* save number of programs */
+#endif
+ rcode = run_pipe_real(pi);
+ debug_printf("run_pipe_real returned %d\n",rcode);
+#ifndef __U_BOOT__
+ if (rcode!=-1) {
+ /* We only ran a builtin: rcode was set by the return value
+ * of run_pipe_real(), and we don't need to wait for anything. */
+ } else if (pi->followup==PIPE_BG) {
+ /* XXX check bash's behavior with nontrivial pipes */
+ /* XXX compute jobid */
+ /* XXX what does bash do with attempts to background builtins? */
+ insert_bg_job(pi);
+ rcode = EXIT_SUCCESS;
+ } else {
+ if (interactive) {
+ /* move the new process group into the foreground */
+ if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
+ perror_msg("tcsetpgrp-3");
+ rcode = checkjobs(pi);
+ /* move the shell to the foreground */
+ if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
+ perror_msg("tcsetpgrp-4");
+ } else {
+ rcode = checkjobs(pi);
+ }
+ debug_printf("checkjobs returned %d\n",rcode);
+ }
+ last_return_code=rcode;
+#else
+ if (rcode < -1) {
+ last_return_code = -rcode - 2;
+ return -2; /* exit */
+ }
+ last_return_code=(rcode == 0) ? 0 : 1;
+#endif
+#ifndef __U_BOOT__
+ pi->num_progs = save_num_progs; /* restore number of programs */
+#endif
+ if ( rmode == RES_IF || rmode == RES_ELIF )
+ next_if_code=rcode; /* can be overwritten a number of times */
+ if (rmode == RES_WHILE)
+ flag_rep = !last_return_code;
+ if (rmode == RES_UNTIL)
+ flag_rep = last_return_code;
+ if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
+ (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
+ skip_more_in_this_rmode=rmode;
+#ifndef __U_BOOT__
+ checkjobs(NULL);
+#endif
+ }
+ return rcode;
+}
+
+/* broken, of course, but OK for testing */
+static char *indenter(int i)
+{
+ static char blanks[]=" ";
+ return &blanks[sizeof(blanks)-i-1];
+}
+
+/* return code is the exit status of the pipe */
+static int free_pipe(struct pipe *pi, int indent)
+{
+ char **p;
+ struct child_prog *child;
+#ifndef __U_BOOT__
+ struct redir_struct *r, *rnext;
+#endif
+ int a, i, ret_code=0;
+ char *ind = indenter(indent);
+
+#ifndef __U_BOOT__
+ if (pi->stopped_progs > 0)
+ return ret_code;
+ final_printf("%s run pipe: (pid %d)\n",ind,getpid());
+#endif
+ for (i=0; i<pi->num_progs; i++) {
+ child = &pi->progs[i];
+ final_printf("%s command %d:\n",ind,i);
+ if (child->argv) {
+ for (a=0,p=child->argv; *p; a++,p++) {
+ final_printf("%s argv[%d] = %s\n",ind,a,*p);
+ }
+#ifndef __U_BOOT__
+ globfree(&child->glob_result);
+#else
+ for (a = 0; a < child->argc; a++) {
+ free(child->argv[a]);
+ }
+ free(child->argv);
+ child->argc = 0;
+#endif
+ child->argv=NULL;
+ } else if (child->group) {
+#ifndef __U_BOOT__
+ final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
+#endif
+ ret_code = free_pipe_list(child->group,indent+3);
+ final_printf("%s end group\n",ind);
+ } else {
+ final_printf("%s (nil)\n",ind);
+ }
+#ifndef __U_BOOT__
+ for (r=child->redirects; r; r=rnext) {
+ final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
+ if (r->dup == -1) {
+ /* guard against the case >$FOO, where foo is unset or blank */
+ if (r->word.gl_pathv) {
+ final_printf(" %s\n", *r->word.gl_pathv);
+ globfree(&r->word);
+ }
+ } else {
+ final_printf("&%d\n", r->dup);
+ }
+ rnext=r->next;
+ free(r);
+ }
+ child->redirects=NULL;
+#endif
+ }
+ free(pi->progs); /* children are an array, they get freed all at once */
+ pi->progs=NULL;
+ return ret_code;
+}
+
+static int free_pipe_list(struct pipe *head, int indent)
+{
+ int rcode=0; /* if list has no members */
+ struct pipe *pi, *next;
+ char *ind = indenter(indent);
+ for (pi=head; pi; pi=next) {
+ final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
+ rcode = free_pipe(pi, indent);
+ final_printf("%s pipe followup code %d\n", ind, pi->followup);
+ next=pi->next;
+ pi->next=NULL;
+ free(pi);
+ }
+ return rcode;
+}
+
+/* Select which version we will use */
+static int run_list(struct pipe *pi)
+{
+ int rcode=0;
+#ifndef __U_BOOT__
+ if (fake_mode==0) {
+#endif
+ rcode = run_list_real(pi);
+#ifndef __U_BOOT__
+ }
+#endif
+ /* free_pipe_list has the side effect of clearing memory
+ * In the long run that function can be merged with run_list_real,
+ * but doing that now would hobble the debugging effort. */
+ free_pipe_list(pi,0);
+ return rcode;
+}
+
+/* The API for glob is arguably broken. This routine pushes a non-matching
+ * string into the output structure, removing non-backslashed backslashes.
+ * If someone can prove me wrong, by performing this function within the
+ * original glob(3) api, feel free to rewrite this routine into oblivion.
+ * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
+ * XXX broken if the last character is '\\', check that before calling.
+ */
+#ifndef __U_BOOT__
+static int globhack(const char *src, int flags, glob_t *pglob)
+{
+ int cnt=0, pathc;
+ const char *s;
+ char *dest;
+ for (cnt=1, s=src; s && *s; s++) {
+ if (*s == '\\') s++;
+ cnt++;
+ }
+ dest = malloc(cnt);
+ if (!dest) return GLOB_NOSPACE;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathv=NULL;
+ pglob->gl_pathc=0;
+ pglob->gl_offs=0;
+ pglob->gl_offs=0;
+ }
+ pathc = ++pglob->gl_pathc;
+ pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
+ if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
+ pglob->gl_pathv[pathc-1]=dest;
+ pglob->gl_pathv[pathc]=NULL;
+ for (s=src; s && *s; s++, dest++) {
+ if (*s == '\\') s++;
+ *dest = *s;
+ }
+ *dest='\0';
+ return 0;
+}
+
+/* XXX broken if the last character is '\\', check that before calling */
+static int glob_needed(const char *s)
+{
+ for (; *s; s++) {
+ if (*s == '\\') s++;
+ if (strchr("*[?",*s)) return 1;
+ }
+ return 0;
+}
+
+#if 0
+static void globprint(glob_t *pglob)
+{
+ int i;
+ debug_printf("glob_t at %p:\n", pglob);
+ debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",
+ pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
+ for (i=0; i<pglob->gl_pathc; i++)
+ debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
+ pglob->gl_pathv[i], pglob->gl_pathv[i]);
+}
+#endif
+
+static int xglob(o_string *dest, int flags, glob_t *pglob)
+{
+ int gr;
+
+ /* short-circuit for null word */
+ /* we can code this better when the debug_printf's are gone */
+ if (dest->length == 0) {
+ if (dest->nonnull) {
+ /* bash man page calls this an "explicit" null */
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ } else {
+ return 0;
+ }
+ } else if (glob_needed(dest->data)) {
+ gr = glob(dest->data, flags, NULL, pglob);
+ debug_printf("glob returned %d\n",gr);
+ if (gr == GLOB_NOMATCH) {
+ /* quote removal, or more accurately, backslash removal */
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ }
+ } else {
+ gr = globhack(dest->data, flags, pglob);
+ debug_printf("globhack returned %d\n",gr);
+ }
+ if (gr == GLOB_NOSPACE)
+ error_msg_and_die("out of memory during glob");
+ if (gr != 0) { /* GLOB_ABORTED ? */
+ error_msg("glob(3) error %d",gr);
+ }
+ /* globprint(glob_target); */
+ return gr;
+}
+#endif
+
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch);
+#endif
+
+/* This is used to get/check local shell variables */
+static char *get_local_var(const char *s)
+{
+ struct variables *cur;
+
+ if (!s)
+ return NULL;
+
+#ifdef __U_BOOT__
+ if (*s == '$')
+ return get_dollar_var(s[1]);
+#endif
+
+ for (cur = top_vars; cur; cur=cur->next)
+ if(strcmp(cur->name, s)==0)
+ return cur->value;
+ return NULL;
+}
+
+/* This is used to set local shell variables
+ flg_export==0 if only local (not exporting) variable
+ flg_export==1 if "new" exporting environ
+ flg_export>1 if current startup environ (not call putenv()) */
+int set_local_var(const char *s, int flg_export)
+{
+ char *name, *value;
+ int result=0;
+ struct variables *cur;
+
+#ifdef __U_BOOT__
+ /* might be possible! */
+ if (!isalpha(*s))
+ return -1;
+#endif
+
+ name=strdup(s);
+
+#ifdef __U_BOOT__
+ if (getenv(name) != NULL) {
+ printf ("ERROR: "
+ "There is a global environment variable with the same name.\n");
+ free(name);
+ return -1;
+ }
+#endif
+ /* Assume when we enter this function that we are already in
+ * NAME=VALUE format. So the first order of business is to
+ * split 's' on the '=' into 'name' and 'value' */
+ value = strchr(name, '=');
+ if (value==0 && ++value==0) {
+ free(name);
+ return -1;
+ }
+ *value++ = 0;
+
+ for(cur = top_vars; cur; cur = cur->next) {
+ if(strcmp(cur->name, name)==0)
+ break;
+ }
+
+ if(cur) {
+ if(strcmp(cur->value, value)==0) {
+ if(flg_export>0 && cur->flg_export==0)
+ cur->flg_export=flg_export;
+ else
+ result++;
+ } else {
+ if(cur->flg_read_only) {
+ error_msg("%s: readonly variable", name);
+ result = -1;
+ } else {
+ if(flg_export>0 || cur->flg_export>1)
+ cur->flg_export=1;
+ free(cur->value);
+
+ cur->value = strdup(value);
+ }
+ }
+ } else {
+ cur = malloc(sizeof(struct variables));
+ if(!cur) {
+ result = -1;
+ } else {
+ cur->name = strdup(name);
+ if(cur->name == 0) {
+ free(cur);
+ result = -1;
+ } else {
+ struct variables *bottom = top_vars;
+ cur->value = strdup(value);
+ cur->next = 0;
+ cur->flg_export = flg_export;
+ cur->flg_read_only = 0;
+ while(bottom->next) bottom=bottom->next;
+ bottom->next = cur;
+ }
+ }
+ }
+
+#ifndef __U_BOOT__
+ if(result==0 && cur->flg_export==1) {
+ *(value-1) = '=';
+ result = putenv(name);
+ } else {
+#endif
+ free(name);
+#ifndef __U_BOOT__
+ if(result>0) /* equivalent to previous set */
+ result = 0;
+ }
+#endif
+ return result;
+}
+
+void unset_local_var(const char *name)
+{
+ struct variables *cur;
+
+ if (name) {
+ for (cur = top_vars; cur; cur=cur->next) {
+ if(strcmp(cur->name, name)==0)
+ break;
+ }
+ if(cur!=0) {
+ struct variables *next = top_vars;
+ if(cur->flg_read_only) {
+ error_msg("%s: readonly variable", name);
+ return;
+ } else {
+#ifndef __U_BOOT__
+ if(cur->flg_export)
+ unsetenv(cur->name);
+#endif
+ free(cur->name);
+ free(cur->value);
+ while (next->next != cur)
+ next = next->next;
+ next->next = cur->next;
+ }
+ free(cur);
+ }
+ }
+}
+
+static int is_assignment(const char *s)
+{
+ if (s == NULL)
+ return 0;
+
+ if (!isalpha(*s)) return 0;
+ ++s;
+ while(isalnum(*s) || *s=='_') ++s;
+ return *s=='=';
+}
+
+#ifndef __U_BOOT__
+/* the src parameter allows us to peek forward to a possible &n syntax
+ * for file descriptor duplication, e.g., "2>&1".
+ * Return code is 0 normally, 1 if a syntax error is detected in src.
+ * Resource errors (in xmalloc) cause the process to exit */
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
+ struct in_str *input)
+{
+ struct child_prog *child=ctx->child;
+ struct redir_struct *redir = child->redirects;
+ struct redir_struct *last_redir=NULL;
+
+ /* Create a new redir_struct and drop it onto the end of the linked list */
+ while(redir) {
+ last_redir=redir;
+ redir=redir->next;
+ }
+ redir = xmalloc(sizeof(struct redir_struct));
+ redir->next=NULL;
+ redir->word.gl_pathv=NULL;
+ if (last_redir) {
+ last_redir->next=redir;
+ } else {
+ child->redirects=redir;
+ }
+
+ redir->type=style;
+ redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
+
+ debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
+
+ /* Check for a '2>&1' type redirect */
+ redir->dup = redirect_dup_num(input);
+ if (redir->dup == -2) return 1; /* syntax error */
+ if (redir->dup != -1) {
+ /* Erik had a check here that the file descriptor in question
+ * is legit; I postpone that to "run time"
+ * A "-" representation of "close me" shows up as a -3 here */
+ debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
+ } else {
+ /* We do _not_ try to open the file that src points to,
+ * since we need to return and let src be expanded first.
+ * Set ctx->pending_redirect, so we know what to do at the
+ * end of the next parsed word.
+ */
+ ctx->pending_redirect = redir;
+ }
+ return 0;
+}
+#endif
+
+struct pipe *new_pipe(void) {
+ struct pipe *pi;
+ pi = xmalloc(sizeof(struct pipe));
+ pi->num_progs = 0;
+ pi->progs = NULL;
+ pi->next = NULL;
+ pi->followup = 0; /* invalid */
+ pi->r_mode = RES_NONE;
+ return pi;
+}
+
+static void initialize_context(struct p_context *ctx)
+{
+ ctx->pipe=NULL;
+#ifndef __U_BOOT__
+ ctx->pending_redirect=NULL;
+#endif
+ ctx->child=NULL;
+ ctx->list_head=new_pipe();
+ ctx->pipe=ctx->list_head;
+ ctx->w=RES_NONE;
+ ctx->stack=NULL;
+#ifdef __U_BOOT__
+ ctx->old_flag=0;
+#endif
+ done_command(ctx); /* creates the memory for working child */
+}
+
+/* normal return is 0
+ * if a reserved word is found, and processed, return 1
+ * should handle if, then, elif, else, fi, for, while, until, do, done.
+ * case, function, and select are obnoxious, save those for later.
+ */
+struct reserved_combo {
+ char *literal;
+ int code;
+ long flag;
+};
+/* Mostly a list of accepted follow-up reserved words.
+ * FLAG_END means we are done with the sequence, and are ready
+ * to turn the compound list into a command.
+ * FLAG_START means the word must start a new compound list.
+ */
+static struct reserved_combo reserved_list[] = {
+ { "if", RES_IF, FLAG_THEN | FLAG_START },
+ { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
+ { "elif", RES_ELIF, FLAG_THEN },
+ { "else", RES_ELSE, FLAG_FI },
+ { "fi", RES_FI, FLAG_END },
+ { "for", RES_FOR, FLAG_IN | FLAG_START },
+ { "while", RES_WHILE, FLAG_DO | FLAG_START },
+ { "until", RES_UNTIL, FLAG_DO | FLAG_START },
+ { "in", RES_IN, FLAG_DO },
+ { "do", RES_DO, FLAG_DONE },
+ { "done", RES_DONE, FLAG_END }
+};
+#define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo))
+
+int reserved_word(o_string *dest, struct p_context *ctx)
+{
+ struct reserved_combo *r;
+ for (r=reserved_list;
+ r<reserved_list+NRES; r++) {
+ if (strcmp(dest->data, r->literal) == 0) {
+ debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
+ if (r->flag & FLAG_START) {
+ struct p_context *new = xmalloc(sizeof(struct p_context));
+ debug_printf("push stack\n");
+ if (ctx->w == RES_IN || ctx->w == RES_FOR) {
+ syntax();
+ free(new);
+ ctx->w = RES_SNTX;
+ b_reset(dest);
+ return 1;
+ }
+ *new = *ctx; /* physical copy */
+ initialize_context(ctx);
+ ctx->stack=new;
+ } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
+ syntax();
+ ctx->w = RES_SNTX;
+ b_reset(dest);
+ return 1;
+ }
+ ctx->w=r->code;
+ ctx->old_flag = r->flag;
+ if (ctx->old_flag & FLAG_END) {
+ struct p_context *old;
+ debug_printf("pop stack\n");
+ done_pipe(ctx,PIPE_SEQ);
+ old = ctx->stack;
+ old->child->group = ctx->list_head;
+#ifndef __U_BOOT__
+ old->child->subshell = 0;
+#endif
+ *ctx = *old; /* physical copy */
+ free(old);
+ }
+ b_reset (dest);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* normal return is 0.
+ * Syntax or xglob errors return 1. */
+static int done_word(o_string *dest, struct p_context *ctx)
+{
+ struct child_prog *child=ctx->child;
+#ifndef __U_BOOT__
+ glob_t *glob_target;
+ int gr, flags = 0;
+#else
+ char *str, *s;
+ int argc, cnt;
+#endif
+
+ debug_printf("done_word: %s %p\n", dest->data, child);
+ if (dest->length == 0 && !dest->nonnull) {
+ debug_printf(" true null, ignored\n");
+ return 0;
+ }
+#ifndef __U_BOOT__
+ if (ctx->pending_redirect) {
+ glob_target = &ctx->pending_redirect->word;
+ } else {
+#endif
+ if (child->group) {
+ syntax();
+ return 1; /* syntax error, groups and arglists don't mix */
+ }
+ if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
+ debug_printf("checking %s for reserved-ness\n",dest->data);
+ if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
+ }
+#ifndef __U_BOOT__
+ glob_target = &child->glob_result;
+ if (child->argv) flags |= GLOB_APPEND;
+#else
+ for (cnt = 1, s = dest->data; s && *s; s++) {
+ if (*s == '\\') s++;
+ cnt++;
+ }
+ str = malloc(cnt);
+ if (!str) return 1;
+ if ( child->argv == NULL) {
+ child->argc=0;
+ }
+ argc = ++child->argc;
+ child->argv = realloc(child->argv, (argc+1)*sizeof(*child->argv));
+ if (child->argv == NULL) return 1;
+ child->argv[argc-1]=str;
+ child->argv[argc]=NULL;
+ for (s = dest->data; s && *s; s++,str++) {
+ if (*s == '\\') s++;
+ *str = *s;
+ }
+ *str = '\0';
+#endif
+#ifndef __U_BOOT__
+ }
+ gr = xglob(dest, flags, glob_target);
+ if (gr != 0) return 1;
+#endif
+
+ b_reset(dest);
+#ifndef __U_BOOT__
+ if (ctx->pending_redirect) {
+ ctx->pending_redirect=NULL;
+ if (glob_target->gl_pathc != 1) {
+ error_msg("ambiguous redirect");
+ return 1;
+ }
+ } else {
+ child->argv = glob_target->gl_pathv;
+ }
+#endif
+ if (ctx->w == RES_FOR) {
+ done_word(dest,ctx);
+ done_pipe(ctx,PIPE_SEQ);
+ }
+ return 0;
+}
+
+/* The only possible error here is out of memory, in which case
+ * xmalloc exits. */
+static int done_command(struct p_context *ctx)
+{
+ /* The child is really already in the pipe structure, so
+ * advance the pipe counter and make a new, null child.
+ * Only real trickiness here is that the uncommitted
+ * child structure, to which ctx->child points, is not
+ * counted in pi->num_progs. */
+ struct pipe *pi=ctx->pipe;
+ struct child_prog *prog=ctx->child;
+
+ if (prog && prog->group == NULL
+ && prog->argv == NULL
+#ifndef __U_BOOT__
+ && prog->redirects == NULL) {
+#else
+ ) {
+#endif
+ debug_printf("done_command: skipping null command\n");
+ return 0;
+ } else if (prog) {
+ pi->num_progs++;
+ debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
+ } else {
+ debug_printf("done_command: initializing\n");
+ }
+ pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
+
+ prog = pi->progs + pi->num_progs;
+#ifndef __U_BOOT__
+ prog->redirects = NULL;
+#endif
+ prog->argv = NULL;
+#ifndef __U_BOOT__
+ prog->is_stopped = 0;
+#endif
+ prog->group = NULL;
+#ifndef __U_BOOT__
+ prog->glob_result.gl_pathv = NULL;
+ prog->family = pi;
+#endif
+ prog->sp = 0;
+ ctx->child = prog;
+ prog->type = ctx->type;
+
+ /* but ctx->pipe and ctx->list_head remain unchanged */
+ return 0;
+}
+
+static int done_pipe(struct p_context *ctx, pipe_style type)
+{
+ struct pipe *new_p;
+ done_command(ctx); /* implicit closure of previous command */
+ debug_printf("done_pipe, type %d\n", type);
+ ctx->pipe->followup = type;
+ ctx->pipe->r_mode = ctx->w;
+ new_p=new_pipe();
+ ctx->pipe->next = new_p;
+ ctx->pipe = new_p;
+ ctx->child = NULL;
+ done_command(ctx); /* set up new pipe to accept commands */
+ return 0;
+}
+
+#ifndef __U_BOOT__
+/* peek ahead in the in_str to find out if we have a "&n" construct,
+ * as in "2>&1", that represents duplicating a file descriptor.
+ * returns either -2 (syntax error), -1 (no &), or the number found.
+ */
+static int redirect_dup_num(struct in_str *input)
+{
+ int ch, d=0, ok=0;
+ ch = b_peek(input);
+ if (ch != '&') return -1;
+
+ b_getch(input); /* get the & */
+ ch=b_peek(input);
+ if (ch == '-') {
+ b_getch(input);
+ return -3; /* "-" represents "close me" */
+ }
+ while (isdigit(ch)) {
+ d = d*10+(ch-'0');
+ ok=1;
+ b_getch(input);
+ ch = b_peek(input);
+ }
+ if (ok) return d;
+
+ error_msg("ambiguous redirect");
+ return -2;
+}
+
+/* If a redirect is immediately preceded by a number, that number is
+ * supposed to tell which file descriptor to redirect. This routine
+ * looks for such preceding numbers. In an ideal world this routine
+ * needs to handle all the following classes of redirects...
+ * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo
+ * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo
+ * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
+ * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo
+ * A -1 output from this program means no valid number was found, so the
+ * caller should use the appropriate default for this redirection.
+ */
+static int redirect_opt_num(o_string *o)
+{
+ int num;
+
+ if (o->length==0) return -1;
+ for(num=0; num<o->length; num++) {
+ if (!isdigit(*(o->data+num))) {
+ return -1;
+ }
+ }
+ /* reuse num (and save an int) */
+ num=atoi(o->data);
+ b_reset(o);
+ return num;
+}
+
+FILE *generate_stream_from_list(struct pipe *head)
+{
+ FILE *pf;
+#if 1
+ int pid, channel[2];
+ if (pipe(channel)<0) perror_msg_and_die("pipe");
+ pid=fork();
+ if (pid<0) {
+ perror_msg_and_die("fork");
+ } else if (pid==0) {
+ close(channel[0]);
+ if (channel[1] != 1) {
+ dup2(channel[1],1);
+ close(channel[1]);
+ }
+#if 0
+#define SURROGATE "surrogate response"
+ write(1,SURROGATE,sizeof(SURROGATE));
+ _exit(run_list(head));
+#else
+ _exit(run_list_real(head)); /* leaks memory */
+#endif
+ }
+ debug_printf("forked child %d\n",pid);
+ close(channel[1]);
+ pf = fdopen(channel[0],"r");
+ debug_printf("pipe on FILE *%p\n",pf);
+#else
+ free_pipe_list(head,0);
+ pf=popen("echo surrogate response","r");
+ debug_printf("started fake pipe on FILE *%p\n",pf);
+#endif
+ return pf;
+}
+
+/* this version hacked for testing purposes */
+/* return code is exit status of the process that is run. */
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
+{
+ int retcode;
+ o_string result=NULL_O_STRING;
+ struct p_context inner;
+ FILE *p;
+ struct in_str pipe_str;
+ initialize_context(&inner);
+
+ /* recursion to generate command */
+ retcode = parse_stream(&result, &inner, input, subst_end);
+ if (retcode != 0) return retcode; /* syntax error or EOF */
+ done_word(&result, &inner);
+ done_pipe(&inner, PIPE_SEQ);
+ b_free(&result);
+
+ p=generate_stream_from_list(inner.list_head);
+ if (p==NULL) return 1;
+ mark_open(fileno(p));
+ setup_file_in_str(&pipe_str, p);
+
+ /* now send results of command back into original context */
+ retcode = parse_stream(dest, ctx, &pipe_str, '\0');
+ /* XXX In case of a syntax error, should we try to kill the child?
+ * That would be tough to do right, so just read until EOF. */
+ if (retcode == 1) {
+ while (b_getch(&pipe_str)!=EOF) { /* discard */ };
+ }
+
+ debug_printf("done reading from pipe, pclose()ing\n");
+ /* This is the step that wait()s for the child. Should be pretty
+ * safe, since we just read an EOF from its stdout. We could try
+ * to better, by using wait(), and keeping track of background jobs
+ * at the same time. That would be a lot of work, and contrary
+ * to the KISS philosophy of this program. */
+ mark_closed(fileno(p));
+ retcode=pclose(p);
+ free_pipe_list(inner.list_head,0);
+ debug_printf("pclosed, retcode=%d\n",retcode);
+ /* XXX this process fails to trim a single trailing newline */
+ return retcode;
+}
+
+static int parse_group(o_string *dest, struct p_context *ctx,
+ struct in_str *input, int ch)
+{
+ int rcode, endch=0;
+ struct p_context sub;
+ struct child_prog *child = ctx->child;
+ if (child->argv) {
+ syntax();
+ return 1; /* syntax error, groups and arglists don't mix */
+ }
+ initialize_context(&sub);
+ switch(ch) {
+ case '(': endch=')'; child->subshell=1; break;
+ case '{': endch='}'; break;
+ default: syntax(); /* really logic error */
+ }
+ rcode=parse_stream(dest,&sub,input,endch);
+ done_word(dest,&sub); /* finish off the final word in the subcontext */
+ done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */
+ child->group = sub.list_head;
+ return rcode;
+ /* child remains "open", available for possible redirects */
+}
+#endif
+
+/* basically useful version until someone wants to get fancier,
+ * see the bash man page under "Parameter Expansion" */
+static char *lookup_param(char *src)
+{
+ char *p;
+
+ if (!src)
+ return NULL;
+
+ p = getenv(src);
+ if (!p)
+ p = get_local_var(src);
+
+ return p;
+}
+
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch)
+{
+ static char buf[40];
+
+ buf[0] = '\0';
+ switch (ch) {
+ case '?':
+ sprintf(buf, "%u", (unsigned int)last_return_code);
+ break;
+ default:
+ return NULL;
+ }
+ return buf;
+}
+#endif
+
+/* return code: 0 for OK, 1 for syntax error */
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
+{
+#ifndef __U_BOOT__
+ int i, advance=0;
+#else
+ int advance=0;
+#endif
+#ifndef __U_BOOT__
+ char sep[]=" ";
+#endif
+ int ch = input->peek(input); /* first character after the $ */
+ debug_printf("handle_dollar: ch=%c\n",ch);
+ if (isalpha(ch)) {
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ ctx->child->sp++;
+ while(ch=b_peek(input),isalnum(ch) || ch=='_') {
+ b_getch(input);
+ b_addchr(dest,ch);
+ }
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#ifndef __U_BOOT__
+ } else if (isdigit(ch)) {
+ i = ch-'0'; /* XXX is $0 special? */
+ if (i<global_argc) {
+ parse_string(dest, ctx, global_argv[i]); /* recursion */
+ }
+ advance = 1;
+#endif
+ } else switch (ch) {
+#ifndef __U_BOOT__
+ case '$':
+ b_adduint(dest,getpid());
+ advance = 1;
+ break;
+ case '!':
+ if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
+ advance = 1;
+ break;
+#endif
+ case '?':
+#ifndef __U_BOOT__
+ b_adduint(dest,last_return_code);
+#else
+ ctx->child->sp++;
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ b_addchr(dest, '$');
+ b_addchr(dest, '?');
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#endif
+ advance = 1;
+ break;
+#ifndef __U_BOOT__
+ case '#':
+ b_adduint(dest,global_argc ? global_argc-1 : 0);
+ advance = 1;
+ break;
+#endif
+ case '{':
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ ctx->child->sp++;
+ b_getch(input);
+ /* XXX maybe someone will try to escape the '}' */
+ while(ch=b_getch(input),ch!=EOF && ch!='}') {
+ b_addchr(dest,ch);
+ }
+ if (ch != '}') {
+ syntax();
+ return 1;
+ }
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ break;
+#ifndef __U_BOOT__
+ case '(':
+ b_getch(input);
+ process_command_subs(dest, ctx, input, ')');
+ break;
+ case '*':
+ sep[0]=ifs[0];
+ for (i=1; i<global_argc; i++) {
+ parse_string(dest, ctx, global_argv[i]);
+ if (i+1 < global_argc) parse_string(dest, ctx, sep);
+ }
+ break;
+ case '@':
+ case '-':
+ case '_':
+ /* still unhandled, but should be eventually */
+ error_msg("unhandled syntax: $%c",ch);
+ return 1;
+ break;
+#endif
+ default:
+ b_addqchr(dest,'$',dest->quote);
+ }
+ /* Eat the character if the flag was set. If the compiler
+ * is smart enough, we could substitute "b_getch(input);"
+ * for all the "advance = 1;" above, and also end up with
+ * a nice size-optimized program. Hah! That'll be the day.
+ */
+ if (advance) b_getch(input);
+ return 0;
+}
+
+#ifndef __U_BOOT__
+int parse_string(o_string *dest, struct p_context *ctx, const char *src)
+{
+ struct in_str foo;
+ setup_string_in_str(&foo, src);
+ return parse_stream(dest, ctx, &foo, '\0');
+}
+#endif
+
+/* return code is 0 for normal exit, 1 for syntax error */
+int parse_stream(o_string *dest, struct p_context *ctx,
+ struct in_str *input, int end_trigger)
+{
+ unsigned int ch, m;
+#ifndef __U_BOOT__
+ int redir_fd;
+ redir_type redir_style;
+#endif
+ int next;
+
+ /* Only double-quote state is handled in the state variable dest->quote.
+ * A single-quote triggers a bypass of the main loop until its mate is
+ * found. When recursing, quote state is passed in via dest->quote. */
+
+ debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
+ while ((ch=b_getch(input))!=EOF) {
+ m = map[ch];
+#ifdef __U_BOOT__
+ if (input->__promptme == 0) return 1;
+#endif
+ next = (ch == '\n') ? 0 : b_peek(input);
+
+ debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
+ ch >= ' ' ? ch : '.', ch, m,
+ dest->quote, ctx->stack == NULL ? '*' : '.');
+
+ if (m==0 || ((m==1 || m==2) && dest->quote)) {
+ b_addqchr(dest, ch, dest->quote);
+ } else {
+ if (m==2) { /* unquoted IFS */
+ if (done_word(dest, ctx)) {
+ return 1;
+ }
+ /* If we aren't performing a substitution, treat a newline as a
+ * command separator. */
+ if (end_trigger != '\0' && ch=='\n')
+ done_pipe(ctx,PIPE_SEQ);
+ }
+ if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
+ debug_printf("leaving parse_stream (triggered)\n");
+ return 0;
+ }
+#if 0
+ if (ch=='\n') {
+ /* Yahoo! Time to run with it! */
+ done_pipe(ctx,PIPE_SEQ);
+ run_list(ctx->list_head);
+ initialize_context(ctx);
+ }
+#endif
+ if (m!=2) switch (ch) {
+ case '#':
+ if (dest->length == 0 && !dest->quote) {
+ while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
+ } else {
+ b_addqchr(dest, ch, dest->quote);
+ }
+ break;
+ case '\\':
+ if (next == EOF) {
+ syntax();
+ return 1;
+ }
+ b_addqchr(dest, '\\', dest->quote);
+ b_addqchr(dest, b_getch(input), dest->quote);
+ break;
+ case '$':
+ if (handle_dollar(dest, ctx, input)!=0) return 1;
+ break;
+ case '\'':
+ dest->nonnull = 1;
+ while(ch=b_getch(input),ch!=EOF && ch!='\'') {
+#ifdef __U_BOOT__
+ if(input->__promptme == 0) return 1;
+#endif
+ b_addchr(dest,ch);
+ }
+ if (ch==EOF) {
+ syntax();
+ return 1;
+ }
+ break;
+ case '"':
+ dest->nonnull = 1;
+ dest->quote = !dest->quote;
+ break;
+#ifndef __U_BOOT__
+ case '`':
+ process_command_subs(dest, ctx, input, '`');
+ break;
+ case '>':
+ redir_fd = redirect_opt_num(dest);
+ done_word(dest, ctx);
+ redir_style=REDIRECT_OVERWRITE;
+ if (next == '>') {
+ redir_style=REDIRECT_APPEND;
+ b_getch(input);
+ } else if (next == '(') {
+ syntax(); /* until we support >(list) Process Substitution */
+ return 1;
+ }
+ setup_redirect(ctx, redir_fd, redir_style, input);
+ break;
+ case '<':
+ redir_fd = redirect_opt_num(dest);
+ done_word(dest, ctx);
+ redir_style=REDIRECT_INPUT;
+ if (next == '<') {
+ redir_style=REDIRECT_HEREIS;
+ b_getch(input);
+ } else if (next == '>') {
+ redir_style=REDIRECT_IO;
+ b_getch(input);
+ } else if (next == '(') {
+ syntax(); /* until we support <(list) Process Substitution */
+ return 1;
+ }
+ setup_redirect(ctx, redir_fd, redir_style, input);
+ break;
+#endif
+ case ';':
+ done_word(dest, ctx);
+ done_pipe(ctx,PIPE_SEQ);
+ break;
+ case '&':
+ done_word(dest, ctx);
+ if (next=='&') {
+ b_getch(input);
+ done_pipe(ctx,PIPE_AND);
+ } else {
+#ifndef __U_BOOT__
+ done_pipe(ctx,PIPE_BG);
+#else
+ syntax_err();
+ return 1;
+#endif
+ }
+ break;
+ case '|':
+ done_word(dest, ctx);
+ if (next=='|') {
+ b_getch(input);
+ done_pipe(ctx,PIPE_OR);
+ } else {
+ /* we could pick up a file descriptor choice here
+ * with redirect_opt_num(), but bash doesn't do it.
+ * "echo foo 2| cat" yields "foo 2". */
+#ifndef __U_BOOT__
+ done_command(ctx);
+#else
+ syntax_err();
+ return 1;
+#endif
+ }
+ break;
+#ifndef __U_BOOT__
+ case '(':
+ case '{':
+ if (parse_group(dest, ctx, input, ch)!=0) return 1;
+ break;
+ case ')':
+ case '}':
+ syntax(); /* Proper use of this character caught by end_trigger */
+ return 1;
+ break;
+#endif
+ default:
+ syntax(); /* this is really an internal logic error */
+ return 1;
+ }
+ }
+ }
+ /* complain if quote? No, maybe we just finished a command substitution
+ * that was quoted. Example:
+ * $ echo "`cat foo` plus more"
+ * and we just got the EOF generated by the subshell that ran "cat foo"
+ * The only real complaint is if we got an EOF when end_trigger != '\0',
+ * that is, we were really supposed to get end_trigger, and never got
+ * one before the EOF. Can't use the standard "syntax error" return code,
+ * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
+ debug_printf("leaving parse_stream (EOF)\n");
+ if (end_trigger != '\0') return -1;
+ return 0;
+}
+
+void mapset(const unsigned char *set, int code)
+{
+ const unsigned char *s;
+ for (s=set; *s; s++) map[*s] = code;
+}
+
+void update_ifs_map(void)
+{
+ /* char *ifs and char map[256] are both globals. */
+ ifs = (uchar *)getenv("IFS");
+ if (ifs == NULL) ifs=(uchar *)" \t\n";
+ /* Precompute a list of 'flow through' behavior so it can be treated
+ * quickly up front. Computation is necessary because of IFS.
+ * Special case handling of IFS == " \t\n" is not implemented.
+ * The map[] array only really needs two bits each, and on most machines
+ * that would be faster because of the reduced L1 cache footprint.
+ */
+ memset(map,0,sizeof(map)); /* most characters flow through always */
+#ifndef __U_BOOT__
+ mapset((uchar *)"\\$'\"`", 3); /* never flow through */
+ mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */
+#else
+ mapset((uchar *)"\\$'\"", 3); /* never flow through */
+ mapset((uchar *)";&|#", 1); /* flow through if quoted */
+#endif
+ mapset(ifs, 2); /* also flow through if quoted */
+}
+
+/* most recursion does not come through here, the exeception is
+ * from builtin_source() */
+int parse_stream_outer(struct in_str *inp, int flag)
+{
+
+ struct p_context ctx;
+ o_string temp=NULL_O_STRING;
+ int rcode;
+#ifdef __U_BOOT__
+ int code = 0;
+#endif
+ do {
+ ctx.type = flag;
+ initialize_context(&ctx);
+ update_ifs_map();
+ if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset((uchar *)";$&|", 0);
+ inp->promptmode=1;
+ rcode = parse_stream(&temp, &ctx, inp, '\n');
+#ifdef __U_BOOT__
+ if (rcode == 1) flag_repeat = 0;
+#endif
+ if (rcode != 1 && ctx.old_flag != 0) {
+ syntax();
+#ifdef __U_BOOT__
+ flag_repeat = 0;
+#endif
+ }
+ if (rcode != 1 && ctx.old_flag == 0) {
+ done_word(&temp, &ctx);
+ done_pipe(&ctx,PIPE_SEQ);
+#ifndef __U_BOOT__
+ run_list(ctx.list_head);
+#else
+ code = run_list(ctx.list_head);
+ if (code == -2) { /* exit */
+ b_free(&temp);
+ code = 0;
+ /* XXX hackish way to not allow exit from main loop */
+ if (inp->peek == file_peek) {
+ printf("exit not allowed from main input shell.\n");
+ continue;
+ }
+ break;
+ }
+ if (code == -1)
+ flag_repeat = 0;
+#endif
+ } else {
+ if (ctx.old_flag != 0) {
+ free(ctx.stack);
+ b_reset(&temp);
+ }
+#ifdef __U_BOOT__
+ if (inp->__promptme == 0) printf("<INTERRUPT>\n");
+ inp->__promptme = 1;
+#endif
+ temp.nonnull = 0;
+ temp.quote = 0;
+ inp->p = NULL;
+ free_pipe_list(ctx.list_head,0);
+ }
+ b_free(&temp);
+ } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
+#ifndef __U_BOOT__
+ return 0;
+#else
+ return (code != 0) ? 1 : 0;
+#endif /* __U_BOOT__ */
+}
+
+#ifndef __U_BOOT__
+static int parse_string_outer(const char *s, int flag)
+#else
+int parse_string_outer(char *s, int flag)
+#endif /* __U_BOOT__ */
+{
+ struct in_str input;
+#ifdef __U_BOOT__
+ char *p = NULL;
+ int rcode;
+ if ( !s || !*s)
+ return 1;
+ if (!(p = strchr(s, '\n')) || *++p) {
+ p = xmalloc(strlen(s) + 2);
+ strcpy(p, s);
+ strcat(p, "\n");
+ setup_string_in_str(&input, p);
+ rcode = parse_stream_outer(&input, flag);
+ free(p);
+ return rcode;
+ } else {
+#endif
+ setup_string_in_str(&input, s);
+ return parse_stream_outer(&input, flag);
+#ifdef __U_BOOT__
+ }
+#endif
+}
+
+#ifndef __U_BOOT__
+static int parse_file_outer(FILE *f)
+#else
+int parse_file_outer(void)
+#endif
+{
+ int rcode;
+ struct in_str input;
+#ifndef __U_BOOT__
+ setup_file_in_str(&input, f);
+#else
+ setup_file_in_str(&input);
+#endif
+ rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
+ return rcode;
+}
+
+#ifdef __U_BOOT__
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+static void u_boot_hush_reloc(void)
+{
+ unsigned long addr;
+ struct reserved_combo *r;
+
+ for (r=reserved_list; r<reserved_list+NRES; r++) {
+ addr = (ulong) (r->literal) + gd->reloc_off;
+ r->literal = (char *)addr;
+ }
+}
+#endif
+
+int u_boot_hush_start(void)
+{
+ if (top_vars == NULL) {
+ top_vars = malloc(sizeof(struct variables));
+ top_vars->name = "HUSH_VERSION";
+ top_vars->value = "0.01";
+ top_vars->next = 0;
+ top_vars->flg_export = 0;
+ top_vars->flg_read_only = 1;
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ u_boot_hush_reloc();
+#endif
+ }
+ return 0;
+}
+
+static void *xmalloc(size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = malloc(size))) {
+ printf("ERROR : memory not allocated\n");
+ for(;;);
+ }
+ return p;
+}
+
+static void *xrealloc(void *ptr, size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = realloc(ptr, size))) {
+ printf("ERROR : memory not allocated\n");
+ for(;;);
+ }
+ return p;
+}
+#endif /* __U_BOOT__ */
+
+#ifndef __U_BOOT__
+/* Make sure we have a controlling tty. If we get started under a job
+ * aware app (like bash for example), make sure we are now in charge so
+ * we don't fight over who gets the foreground */
+static void setup_job_control(void)
+{
+ static pid_t shell_pgrp;
+ /* Loop until we are in the foreground. */
+ while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
+ kill (- shell_pgrp, SIGTTIN);
+
+ /* Ignore interactive and job-control signals. */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+ /* Put ourselves in our own process group. */
+ setsid();
+ shell_pgrp = getpid ();
+ setpgid (shell_pgrp, shell_pgrp);
+
+ /* Grab control of the terminal. */
+ tcsetpgrp(shell_terminal, shell_pgrp);
+}
+
+int hush_main(int argc, char * const *argv)
+{
+ int opt;
+ FILE *input;
+ char **e = environ;
+
+ /* XXX what should these be while sourcing /etc/profile? */
+ global_argc = argc;
+ global_argv = argv;
+
+ /* (re?) initialize globals. Sometimes hush_main() ends up calling
+ * hush_main(), therefore we cannot rely on the BSS to zero out this
+ * stuff. Reset these to 0 every time. */
+ ifs = NULL;
+ /* map[] is taken care of with call to update_ifs_map() */
+ fake_mode = 0;
+ interactive = 0;
+ close_me_head = NULL;
+ last_bg_pid = 0;
+ job_list = NULL;
+ last_jobid = 0;
+
+ /* Initialize some more globals to non-zero values */
+ set_cwd();
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
+ cmdedit_set_initial_prompt();
+#else
+ PS1 = NULL;
+#endif
+ PS2 = "> ";
+
+ /* initialize our shell local variables with the values
+ * currently living in the environment */
+ if (e) {
+ for (; *e; e++)
+ set_local_var(*e, 2); /* without call putenv() */
+ }
+
+ last_return_code=EXIT_SUCCESS;
+
+
+ if (argv[0] && argv[0][0] == '-') {
+ debug_printf("\nsourcing /etc/profile\n");
+ if ((input = fopen("/etc/profile", "r")) != NULL) {
+ mark_open(fileno(input));
+ parse_file_outer(input);
+ mark_closed(fileno(input));
+ fclose(input);
+ }
+ }
+ input=stdin;
+
+ while ((opt = getopt(argc, argv, "c:xif")) > 0) {
+ switch (opt) {
+ case 'c':
+ {
+ global_argv = argv+optind;
+ global_argc = argc-optind;
+ opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
+ goto final_return;
+ }
+ break;
+ case 'i':
+ interactive++;
+ break;
+ case 'f':
+ fake_mode++;
+ break;
+ default:
+#ifndef BB_VER
+ fprintf(stderr, "Usage: sh [FILE]...\n"
+ " or: sh -c command [args]...\n\n");
+ exit(EXIT_FAILURE);
+#else
+ show_usage();
+#endif
+ }
+ }
+ /* A shell is interactive if the `-i' flag was given, or if all of
+ * the following conditions are met:
+ * no -c command
+ * no arguments remaining or the -s flag given
+ * standard input is a terminal
+ * standard output is a terminal
+ * Refer to Posix.2, the description of the `sh' utility. */
+ if (argv[optind]==NULL && input==stdin &&
+ isatty(fileno(stdin)) && isatty(fileno(stdout))) {
+ interactive++;
+ }
+
+ debug_printf("\ninteractive=%d\n", interactive);
+ if (interactive) {
+ /* Looks like they want an interactive shell */
+#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
+ printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
+ printf( "Enter 'help' for a list of built-in commands.\n\n");
+#endif
+ setup_job_control();
+ }
+
+ if (argv[optind]==NULL) {
+ opt=parse_file_outer(stdin);
+ goto final_return;
+ }
+
+ debug_printf("\nrunning script '%s'\n", argv[optind]);
+ global_argv = argv+optind;
+ global_argc = argc-optind;
+ input = xfopen(argv[optind], "r");
+ opt = parse_file_outer(input);
+
+#ifdef CONFIG_FEATURE_CLEAN_UP
+ fclose(input);
+ if (cwd && cwd != unknown)
+ free((char*)cwd);
+ {
+ struct variables *cur, *tmp;
+ for(cur = top_vars; cur; cur = tmp) {
+ tmp = cur->next;
+ if (!cur->flg_read_only) {
+ free(cur->name);
+ free(cur->value);
+ free(cur);
+ }
+ }
+ }
+#endif
+
+final_return:
+ return(opt?opt:last_return_code);
+}
+#endif
+
+static char *insert_var_value(char *inp)
+{
+ int res_str_len = 0;
+ int len;
+ int done = 0;
+ char *p, *p1, *res_str = NULL;
+
+ while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
+ if (p != inp) {
+ len = p - inp;
+ res_str = xrealloc(res_str, (res_str_len + len));
+ strncpy((res_str + res_str_len), inp, len);
+ res_str_len += len;
+ }
+ inp = ++p;
+ p = strchr(inp, SPECIAL_VAR_SYMBOL);
+ *p = '\0';
+ if ((p1 = lookup_param(inp))) {
+ len = res_str_len + strlen(p1);
+ res_str = xrealloc(res_str, (1 + len));
+ strcpy((res_str + res_str_len), p1);
+ res_str_len = len;
+ }
+ *p = SPECIAL_VAR_SYMBOL;
+ inp = ++p;
+ done = 1;
+ }
+ if (done) {
+ res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
+ strcpy((res_str + res_str_len), inp);
+ while ((p = strchr(res_str, '\n'))) {
+ *p = ' ';
+ }
+ }
+ return (res_str == NULL) ? inp : res_str;
+}
+
+static char **make_list_in(char **inp, char *name)
+{
+ int len, i;
+ int name_len = strlen(name);
+ int n = 0;
+ char **list;
+ char *p1, *p2, *p3;
+
+ /* create list of variable values */
+ list = xmalloc(sizeof(*list));
+ for (i = 0; inp[i]; i++) {
+ p3 = insert_var_value(inp[i]);
+ p1 = p3;
+ while (*p1) {
+ if ((*p1 == ' ')) {
+ p1++;
+ continue;
+ }
+ if ((p2 = strchr(p1, ' '))) {
+ len = p2 - p1;
+ } else {
+ len = strlen(p1);
+ p2 = p1 + len;
+ }
+ /* we use n + 2 in realloc for list,because we add
+ * new element and then we will add NULL element */
+ list = xrealloc(list, sizeof(*list) * (n + 2));
+ list[n] = xmalloc(2 + name_len + len);
+ strcpy(list[n], name);
+ strcat(list[n], "=");
+ strncat(list[n], p1, len);
+ list[n++][name_len + len + 1] = '\0';
+ p1 = p2;
+ }
+ if (p3 != inp[i]) free(p3);
+ }
+ list[n] = NULL;
+ return list;
+}
+
+/* Make new string for parser */
+static char * make_string(char ** inp)
+{
+ char *p;
+ char *str = NULL;
+ int n;
+ int len = 2;
+
+ for (n = 0; inp[n]; n++) {
+ p = insert_var_value(inp[n]);
+ str = xrealloc(str, (len + strlen(p)));
+ if (n) {
+ strcat(str, " ");
+ } else {
+ *str = '\0';
+ }
+ strcat(str, p);
+ len = strlen(str) + 3;
+ if (p != inp[n]) free(p);
+ }
+ len = strlen(str);
+ *(str + len) = '\n';
+ *(str + len + 1) = '\0';
+ return str;
+}
+
+#ifdef __U_BOOT__
+int do_showvar (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i, k;
+ int rcode = 0;
+ struct variables *cur;
+
+ if (argc == 1) { /* Print all env variables */
+ for (cur = top_vars; cur; cur = cur->next) {
+ printf ("%s=%s\n", cur->name, cur->value);
+ if (ctrlc ()) {
+ puts ("\n ** Abort\n");
+ return 1;
+ }
+ }
+ return 0;
+ }
+ for (i = 1; i < argc; ++i) { /* print single env variables */
+ char *name = argv[i];
+
+ k = -1;
+ for (cur = top_vars; cur; cur = cur->next) {
+ if(strcmp (cur->name, name) == 0) {
+ k = 0;
+ printf ("%s=%s\n", cur->name, cur->value);
+ }
+ if (ctrlc ()) {
+ puts ("\n ** Abort\n");
+ return 1;
+ }
+ }
+ if (k < 0) {
+ printf ("## Error: \"%s\" not defined\n", name);
+ rcode ++;
+ }
+ }
+ return rcode;
+}
+
+U_BOOT_CMD(
+ showvar, CONFIG_SYS_MAXARGS, 1, do_showvar,
+ "print local hushshell variables",
+ "\n - print values of all hushshell variables\n"
+ "showvar name ...\n"
+ " - print value of hushshell variable 'name'"
+);
+
+#endif
+/****************************************************************************/
diff --git a/u-boot/common/hwconfig.c b/u-boot/common/hwconfig.c
new file mode 100644
index 0000000..e47d4d7
--- /dev/null
+++ b/u-boot/common/hwconfig.c
@@ -0,0 +1,288 @@
+/*
+ * An inteface for configuring a hardware via u-boot environment.
+ *
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#ifndef HWCONFIG_TEST
+#include <config.h>
+#include <common.h>
+#include <exports.h>
+#include <hwconfig.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* HWCONFIG_TEST */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *hwconfig_parse(const char *opts, size_t maxlen,
+ const char *opt, char *stopchs, char eqch,
+ size_t *arglen)
+{
+ size_t optlen = strlen(opt);
+ char *str;
+ const char *start = opts;
+ const char *end;
+
+next:
+ str = strstr(opts, opt);
+ end = str + optlen;
+ if (end - start > maxlen)
+ return NULL;
+
+ if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) &&
+ (strpbrk(end, stopchs) == end || *end == eqch ||
+ *end == '\0')) {
+ const char *arg_end;
+
+ if (!arglen)
+ return str;
+
+ if (*end != eqch)
+ return NULL;
+
+ arg_end = strpbrk(str, stopchs);
+ if (!arg_end)
+ *arglen = min(maxlen, strlen(str)) - optlen - 1;
+ else
+ *arglen = arg_end - end - 1;
+
+ return end + 1;
+ } else if (str) {
+ opts = end;
+ goto next;
+ }
+ return NULL;
+}
+
+const char cpu_hwconfig[] __attribute__((weak)) = "";
+const char board_hwconfig[] __attribute__((weak)) = "";
+
+static const char *__hwconfig(const char *opt, size_t *arglen,
+ const char *env_hwconfig)
+{
+ const char *ret;
+
+ /* if we are passed a buffer use it, otherwise try the environment */
+ if (!env_hwconfig) {
+ if (!(gd->flags & GD_FLG_ENV_READY)) {
+ printf("WARNING: Calling __hwconfig without a buffer "
+ "and before environment is ready\n");
+ return NULL;
+ }
+ env_hwconfig = getenv("hwconfig");
+ }
+
+ if (env_hwconfig) {
+ ret = hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
+ opt, ";", ':', arglen);
+ if (ret)
+ return ret;
+ }
+
+ ret = hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
+ opt, ";", ':', arglen);
+ if (ret)
+ return ret;
+
+ return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
+ opt, ";", ':', arglen);
+}
+
+/*
+ * hwconfig_f - query if a particular hwconfig option is specified
+ * @opt: a string representing an option
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call can be used to find out whether U-Boot should configure
+ * a particular hardware option.
+ *
+ * Returns non-zero value if the hardware option can be used and thus
+ * should be configured, 0 otherwise.
+ *
+ * This function also returns non-zero value if CONFIG_HWCONFIG is
+ * undefined.
+ *
+ * Returning non-zero value without CONFIG_HWCONFIG has its crucial
+ * purpose: the hwconfig() call should be a "transparent" interface,
+ * e.g. if a board doesn't need hwconfig facility, then we assume
+ * that the board file only calls things that are actually used, so
+ * hwconfig() will always return true result.
+ */
+int hwconfig_f(const char *opt, char *buf)
+{
+ return !!__hwconfig(opt, NULL, buf);
+}
+
+/*
+ * hwconfig_arg_f - get hwconfig option's argument
+ * @opt: a string representing an option
+ * @arglen: a pointer to an allocated size_t variable
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * Unlike hwconfig_f() function, this function returns a pointer to the
+ * start of the hwconfig arguments, if option is not found or it has
+ * no specified arguments, the function returns NULL pointer.
+ *
+ * If CONFIG_HWCONFIG is undefined, the function returns "", and
+ * arglen is set to 0.
+ */
+const char *hwconfig_arg_f(const char *opt, size_t *arglen, char *buf)
+{
+ return __hwconfig(opt, arglen, buf);
+}
+
+/*
+ * hwconfig_arg_cmp_f - compare hwconfig option's argument
+ * @opt: a string representing an option
+ * @arg: a string for comparing an option's argument
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_f, but instead of returning
+ * hwconfig argument and its length, it is comparing it to @arg.
+ *
+ * Returns non-zero value if @arg matches, 0 otherwise.
+ *
+ * If CONFIG_HWCONFIG is undefined, the function returns a non-zero
+ * value, i.e. the argument matches.
+ */
+int hwconfig_arg_cmp_f(const char *opt, const char *arg, char *buf)
+{
+ const char *argstr;
+ size_t arglen;
+
+ argstr = hwconfig_arg_f(opt, &arglen, buf);
+ if (!argstr || arglen != strlen(arg))
+ return 0;
+
+ return !strncmp(argstr, arg, arglen);
+}
+
+/*
+ * hwconfig_sub_f - query if a particular hwconfig sub-option is specified
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_f(), except that it takes additional
+ * argument @subopt. In this example:
+ * "dr_usb:mode=peripheral"
+ * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its
+ * argument.
+ */
+int hwconfig_sub_f(const char *opt, const char *subopt, char *buf)
+{
+ size_t arglen;
+ const char *arg;
+
+ arg = __hwconfig(opt, &arglen, buf);
+ if (!arg)
+ return 0;
+ return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL);
+}
+
+/*
+ * hwconfig_subarg_f - get hwconfig sub-option's argument
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @subarglen: a pointer to an allocated size_t variable
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_f(), except that it takes an
+ * additional argument @subopt, and so works with sub-options.
+ */
+const char *hwconfig_subarg_f(const char *opt, const char *subopt,
+ size_t *subarglen, char *buf)
+{
+ size_t arglen;
+ const char *arg;
+
+ arg = __hwconfig(opt, &arglen, buf);
+ if (!arg)
+ return NULL;
+ return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen);
+}
+
+/*
+ * hwconfig_arg_cmp_f - compare hwconfig sub-option's argument
+ * @opt: a string representing an option
+ * @subopt: a string representing a sub-option
+ * @subarg: a string for comparing an sub-option's argument
+ * @buf: if non-NULL use this buffer to parse, otherwise try env
+ *
+ * This call is similar to hwconfig_arg_cmp_f, except that it takes an
+ * additional argument @subopt, and so works with sub-options.
+ */
+int hwconfig_subarg_cmp_f(const char *opt, const char *subopt,
+ const char *subarg, char *buf)
+{
+ const char *argstr;
+ size_t arglen;
+
+ argstr = hwconfig_subarg_f(opt, subopt, &arglen, buf);
+ if (!argstr || arglen != strlen(subarg))
+ return 0;
+
+ return !strncmp(argstr, subarg, arglen);
+}
+
+#ifdef HWCONFIG_TEST
+int main()
+{
+ const char *ret;
+ size_t len;
+
+ setenv("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;"
+ "key3;:,:=;key4", 1);
+
+ ret = hwconfig_arg("key1", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 29);
+ assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2"));
+ assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len));
+
+ ret = hwconfig_subarg("key1", "subkey1", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_subarg_cmp("key1", "subkey1", "value1"));
+ assert(!strncmp(ret, "value1", len));
+
+ ret = hwconfig_subarg("key1", "subkey2", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_subarg_cmp("key1", "subkey2", "value2"));
+ assert(!strncmp(ret, "value2", len));
+
+ ret = hwconfig_arg("key2", &len);
+ printf("%zd %.*s\n", len, (int)len, ret);
+ assert(len == 6);
+ assert(hwconfig_arg_cmp("key2", "value3"));
+ assert(!strncmp(ret, "value3", len));
+
+ assert(hwconfig("key3"));
+ assert(hwconfig_arg("key4", &len) == NULL);
+ assert(hwconfig_arg("bogus", &len) == NULL);
+
+ unsetenv("hwconfig");
+
+ assert(hwconfig(NULL) == 0);
+ assert(hwconfig("") == 0);
+ assert(hwconfig("key3") == 0);
+
+ return 0;
+}
+#endif /* HWCONFIG_TEST */
diff --git a/u-boot/common/image.c b/u-boot/common/image.c
new file mode 100644
index 0000000..f63a2ff
--- /dev/null
+++ b/u-boot/common/image.c
@@ -0,0 +1,3062 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <watchdog.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+#include <status_led.h>
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+#include <dataflash.h>
+#endif
+
+#ifdef CONFIG_LOGBUFFER
+#include <logbuff.h>
+#endif
+
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE)
+#include <rtc.h>
+#endif
+
+#include <image.h>
+
+#if defined(CONFIG_FIT) || defined (CONFIG_OF_LIBFDT)
+#include <fdt.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#if defined(CONFIG_FIT)
+#include <u-boot/md5.h>
+#include <sha1.h>
+
+static int fit_check_ramdisk (const void *fit, int os_noffset,
+ uint8_t arch, int verify);
+#endif
+
+#ifdef CONFIG_CMD_BDI
+extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const image_header_t* image_get_ramdisk (ulong rd_addr, uint8_t arch,
+ int verify);
+#else
+#include "mkimage.h"
+#include <u-boot/md5.h>
+#include <time.h>
+#include <image.h>
+#endif /* !USE_HOSTCC*/
+
+static const table_entry_t uimage_arch[] = {
+ { IH_ARCH_INVALID, NULL, "Invalid ARCH", },
+ { IH_ARCH_ALPHA, "alpha", "Alpha", },
+ { IH_ARCH_ARM, "arm", "ARM", },
+ { IH_ARCH_I386, "x86", "Intel x86", },
+ { IH_ARCH_IA64, "ia64", "IA64", },
+ { IH_ARCH_M68K, "m68k", "M68K", },
+ { IH_ARCH_MICROBLAZE, "microblaze", "MicroBlaze", },
+ { IH_ARCH_MIPS, "mips", "MIPS", },
+ { IH_ARCH_MIPS64, "mips64", "MIPS 64 Bit", },
+ { IH_ARCH_NIOS2, "nios2", "NIOS II", },
+ { IH_ARCH_PPC, "powerpc", "PowerPC", },
+ { IH_ARCH_PPC, "ppc", "PowerPC", },
+ { IH_ARCH_S390, "s390", "IBM S390", },
+ { IH_ARCH_SH, "sh", "SuperH", },
+ { IH_ARCH_SPARC, "sparc", "SPARC", },
+ { IH_ARCH_SPARC64, "sparc64", "SPARC 64 Bit", },
+ { IH_ARCH_BLACKFIN, "blackfin", "Blackfin", },
+ { IH_ARCH_AVR32, "avr32", "AVR32", },
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_os[] = {
+ { IH_OS_INVALID, NULL, "Invalid OS", },
+ { IH_OS_LINUX, "linux", "Linux", },
+#if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
+ { IH_OS_LYNXOS, "lynxos", "LynxOS", },
+#endif
+ { IH_OS_NETBSD, "netbsd", "NetBSD", },
+ { IH_OS_OSE, "ose", "Enea OSE", },
+ { IH_OS_RTEMS, "rtems", "RTEMS", },
+ { IH_OS_U_BOOT, "u-boot", "U-Boot", },
+#if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
+ { IH_OS_QNX, "qnx", "QNX", },
+ { IH_OS_VXWORKS, "vxworks", "VxWorks", },
+#endif
+#if defined(CONFIG_INTEGRITY) || defined(USE_HOSTCC)
+ { IH_OS_INTEGRITY,"integrity", "INTEGRITY", },
+#endif
+#ifdef USE_HOSTCC
+ { IH_OS_4_4BSD, "4_4bsd", "4_4BSD", },
+ { IH_OS_DELL, "dell", "Dell", },
+ { IH_OS_ESIX, "esix", "Esix", },
+ { IH_OS_FREEBSD, "freebsd", "FreeBSD", },
+ { IH_OS_IRIX, "irix", "Irix", },
+ { IH_OS_NCR, "ncr", "NCR", },
+ { IH_OS_OPENBSD, "openbsd", "OpenBSD", },
+ { IH_OS_PSOS, "psos", "pSOS", },
+ { IH_OS_SCO, "sco", "SCO", },
+ { IH_OS_SOLARIS, "solaris", "Solaris", },
+ { IH_OS_SVR4, "svr4", "SVR4", },
+#endif
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_type[] = {
+ { IH_TYPE_INVALID, NULL, "Invalid Image", },
+ { IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image", },
+ { IH_TYPE_FIRMWARE, "firmware", "Firmware", },
+ { IH_TYPE_KERNEL, "kernel", "Kernel Image", },
+ { IH_TYPE_MULTI, "multi", "Multi-File Image", },
+ { IH_TYPE_RAMDISK, "ramdisk", "RAMDisk Image", },
+ { IH_TYPE_SCRIPT, "script", "Script", },
+ { IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
+ { IH_TYPE_FLATDT, "flat_dt", "Flat Device Tree", },
+ { IH_TYPE_KWBIMAGE, "kwbimage", "Kirkwood Boot Image",},
+ { IH_TYPE_IMXIMAGE, "imximage", "Freescale i.MX Boot Image",},
+ { -1, "", "", },
+};
+
+static const table_entry_t uimage_comp[] = {
+ { IH_COMP_NONE, "none", "uncompressed", },
+ { IH_COMP_BZIP2, "bzip2", "bzip2 compressed", },
+ { IH_COMP_GZIP, "gzip", "gzip compressed", },
+ { IH_COMP_LZMA, "lzma", "lzma compressed", },
+ { IH_COMP_LZO, "lzo", "lzo compressed", },
+ { -1, "", "", },
+};
+
+uint32_t crc32 (uint32_t, const unsigned char *, uint);
+uint32_t crc32_wd (uint32_t, const unsigned char *, uint, uint);
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+static void genimg_print_time (time_t timestamp);
+#endif
+
+/*****************************************************************************/
+/* Legacy format routines */
+/*****************************************************************************/
+int image_check_hcrc (const image_header_t *hdr)
+{
+ ulong hcrc;
+ ulong len = image_get_header_size ();
+ image_header_t header;
+
+ /* Copy header so we can blank CRC field for re-calculation */
+ memmove (&header, (char *)hdr, image_get_header_size ());
+ image_set_hcrc (&header, 0);
+
+ hcrc = crc32 (0, (unsigned char *)&header, len);
+
+ return (hcrc == image_get_hcrc (hdr));
+}
+
+int image_check_dcrc (const image_header_t *hdr)
+{
+ ulong data = image_get_data (hdr);
+ ulong len = image_get_data_size (hdr);
+ ulong dcrc = crc32_wd (0, (unsigned char *)data, len, CHUNKSZ_CRC32);
+
+ return (dcrc == image_get_dcrc (hdr));
+}
+
+/**
+ * image_multi_count - get component (sub-image) count
+ * @hdr: pointer to the header of the multi component image
+ *
+ * image_multi_count() returns number of components in a multi
+ * component image.
+ *
+ * Note: no checking of the image type is done, caller must pass
+ * a valid multi component image.
+ *
+ * returns:
+ * number of components
+ */
+ulong image_multi_count (const image_header_t *hdr)
+{
+ ulong i, count = 0;
+ uint32_t *size;
+
+ /* get start of the image payload, which in case of multi
+ * component images that points to a table of component sizes */
+ size = (uint32_t *)image_get_data (hdr);
+
+ /* count non empty slots */
+ for (i = 0; size[i]; ++i)
+ count++;
+
+ return count;
+}
+
+/**
+ * image_multi_getimg - get component data address and size
+ * @hdr: pointer to the header of the multi component image
+ * @idx: index of the requested component
+ * @data: pointer to a ulong variable, will hold component data address
+ * @len: pointer to a ulong variable, will hold component size
+ *
+ * image_multi_getimg() returns size and data address for the requested
+ * component in a multi component image.
+ *
+ * Note: no checking of the image type is done, caller must pass
+ * a valid multi component image.
+ *
+ * returns:
+ * data address and size of the component, if idx is valid
+ * 0 in data and len, if idx is out of range
+ */
+void image_multi_getimg (const image_header_t *hdr, ulong idx,
+ ulong *data, ulong *len)
+{
+ int i;
+ uint32_t *size;
+ ulong offset, count, img_data;
+
+ /* get number of component */
+ count = image_multi_count (hdr);
+
+ /* get start of the image payload, which in case of multi
+ * component images that points to a table of component sizes */
+ size = (uint32_t *)image_get_data (hdr);
+
+ /* get address of the proper component data start, which means
+ * skipping sizes table (add 1 for last, null entry) */
+ img_data = image_get_data (hdr) + (count + 1) * sizeof (uint32_t);
+
+ if (idx < count) {
+ *len = uimage_to_cpu (size[idx]);
+ offset = 0;
+
+ /* go over all indices preceding requested component idx */
+ for (i = 0; i < idx; i++) {
+ /* add up i-th component size, rounding up to 4 bytes */
+ offset += (uimage_to_cpu (size[i]) + 3) & ~3 ;
+ }
+
+ /* calculate idx-th component data address */
+ *data = img_data + offset;
+ } else {
+ *len = 0;
+ *data = 0;
+ }
+}
+
+static void image_print_type (const image_header_t *hdr)
+{
+ const char *os, *arch, *type, *comp;
+
+ os = genimg_get_os_name (image_get_os (hdr));
+ arch = genimg_get_arch_name (image_get_arch (hdr));
+ type = genimg_get_type_name (image_get_type (hdr));
+ comp = genimg_get_comp_name (image_get_comp (hdr));
+
+ printf ("%s %s %s (%s)\n", arch, os, type, comp);
+}
+
+/**
+ * image_print_contents - prints out the contents of the legacy format image
+ * @ptr: pointer to the legacy format image header
+ * @p: pointer to prefix string
+ *
+ * image_print_contents() formats a multi line legacy image contents description.
+ * The routine prints out all header fields followed by the size/offset data
+ * for MULTI/SCRIPT images.
+ *
+ * returns:
+ * no returned results
+ */
+void image_print_contents (const void *ptr)
+{
+ const image_header_t *hdr = (const image_header_t *)ptr;
+ const char *p;
+
+#ifdef USE_HOSTCC
+ p = "";
+#else
+ p = " ";
+#endif
+
+ printf ("%sImage Name: %.*s\n", p, IH_NMLEN, image_get_name (hdr));
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+ printf ("%sCreated: ", p);
+ genimg_print_time ((time_t)image_get_time (hdr));
+#endif
+ printf ("%sImage Type: ", p);
+ image_print_type (hdr);
+ printf ("%sData Size: ", p);
+ genimg_print_size (image_get_data_size (hdr));
+ printf ("%sLoad Address: %08x\n", p, image_get_load (hdr));
+ printf ("%sEntry Point: %08x\n", p, image_get_ep (hdr));
+
+ if (image_check_type (hdr, IH_TYPE_MULTI) ||
+ image_check_type (hdr, IH_TYPE_SCRIPT)) {
+ int i;
+ ulong data, len;
+ ulong count = image_multi_count (hdr);
+
+ printf ("%sContents:\n", p);
+ for (i = 0; i < count; i++) {
+ image_multi_getimg (hdr, i, &data, &len);
+
+ printf ("%s Image %d: ", p, i);
+ genimg_print_size (len);
+
+ if (image_check_type (hdr, IH_TYPE_SCRIPT) && i > 0) {
+ /*
+ * the user may need to know offsets
+ * if planning to do something with
+ * multiple files
+ */
+ printf ("%s Offset = 0x%08lx\n", p, data);
+ }
+ }
+ }
+}
+
+
+#ifndef USE_HOSTCC
+/**
+ * image_get_ramdisk - get and verify ramdisk image
+ * @rd_addr: ramdisk image start address
+ * @arch: expected ramdisk architecture
+ * @verify: checksum verification flag
+ *
+ * image_get_ramdisk() returns a pointer to the verified ramdisk image
+ * header. Routine receives image start address and expected architecture
+ * flag. Verification done covers data and header integrity and os/type/arch
+ * fields checking.
+ *
+ * If dataflash support is enabled routine checks for dataflash addresses
+ * and handles required dataflash reads.
+ *
+ * returns:
+ * pointer to a ramdisk image header, if image was found and valid
+ * otherwise, return NULL
+ */
+static const image_header_t *image_get_ramdisk (ulong rd_addr, uint8_t arch,
+ int verify)
+{
+ const image_header_t *rd_hdr = (const image_header_t *)rd_addr;
+
+ if (!image_check_magic (rd_hdr)) {
+ puts ("Bad Magic Number\n");
+ show_boot_progress (-10);
+ return NULL;
+ }
+
+ if (!image_check_hcrc (rd_hdr)) {
+ puts ("Bad Header Checksum\n");
+ show_boot_progress (-11);
+ return NULL;
+ }
+
+ show_boot_progress (10);
+ image_print_contents (rd_hdr);
+
+ if (verify) {
+ puts(" Verifying Checksum ... ");
+ if (!image_check_dcrc (rd_hdr)) {
+ puts ("Bad Data CRC\n");
+ show_boot_progress (-12);
+ return NULL;
+ }
+ puts("OK\n");
+ }
+
+ show_boot_progress (11);
+
+ if (!image_check_os (rd_hdr, IH_OS_LINUX) ||
+ !image_check_arch (rd_hdr, arch) ||
+ !image_check_type (rd_hdr, IH_TYPE_RAMDISK)) {
+ printf ("No Linux %s Ramdisk Image\n",
+ genimg_get_arch_name(arch));
+ show_boot_progress (-13);
+ return NULL;
+ }
+
+ return rd_hdr;
+}
+#endif /* !USE_HOSTCC */
+
+/*****************************************************************************/
+/* Shared dual-format routines */
+/*****************************************************************************/
+#ifndef USE_HOSTCC
+int getenv_yesno (char *var)
+{
+ char *s = getenv (var);
+ return (s && (*s == 'n')) ? 0 : 1;
+}
+
+ulong getenv_bootm_low(void)
+{
+ char *s = getenv ("bootm_low");
+ if (s) {
+ ulong tmp = simple_strtoul (s, NULL, 16);
+ return tmp;
+ }
+
+#if defined(CONFIG_SYS_SDRAM_BASE)
+ return CONFIG_SYS_SDRAM_BASE;
+#elif defined(CONFIG_ARM)
+ return gd->bd->bi_dram[0].start;
+#else
+ return 0;
+#endif
+}
+
+phys_size_t getenv_bootm_size(void)
+{
+ phys_size_t tmp;
+ char *s = getenv ("bootm_size");
+ if (s) {
+ tmp = (phys_size_t)simple_strtoull (s, NULL, 16);
+ return tmp;
+ }
+ s = getenv("bootm_low");
+ if (s)
+ tmp = (phys_size_t)simple_strtoull (s, NULL, 16);
+ else
+ tmp = 0;
+
+
+#if defined(CONFIG_ARM)
+ return gd->bd->bi_dram[0].size - tmp;
+#else
+ return gd->bd->bi_memsize - tmp;
+#endif
+}
+
+void memmove_wd (void *to, void *from, size_t len, ulong chunksz)
+{
+ if (to == from)
+ return;
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+ while (len > 0) {
+ size_t tail = (len > chunksz) ? chunksz : len;
+ WATCHDOG_RESET ();
+ memmove (to, from, tail);
+ to += tail;
+ from += tail;
+ len -= tail;
+ }
+#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
+ memmove (to, from, len);
+#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
+}
+#endif /* !USE_HOSTCC */
+
+void genimg_print_size (uint32_t size)
+{
+#ifndef USE_HOSTCC
+ printf ("%d Bytes = ", size);
+ print_size (size, "\n");
+#else
+ printf ("%d Bytes = %.2f kB = %.2f MB\n",
+ size, (double)size / 1.024e3,
+ (double)size / 1.048576e6);
+#endif
+}
+
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+static void genimg_print_time (time_t timestamp)
+{
+#ifndef USE_HOSTCC
+ struct rtc_time tm;
+
+ to_tm (timestamp, &tm);
+ printf ("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
+ tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+#else
+ printf ("%s", ctime(&timestamp));
+#endif
+}
+#endif /* CONFIG_TIMESTAMP || CONFIG_CMD_DATE || USE_HOSTCC */
+
+/**
+ * get_table_entry_name - translate entry id to long name
+ * @table: pointer to a translation table for entries of a specific type
+ * @msg: message to be returned when translation fails
+ * @id: entry id to be translated
+ *
+ * get_table_entry_name() will go over translation table trying to find
+ * entry that matches given id. If matching entry is found, its long
+ * name is returned to the caller.
+ *
+ * returns:
+ * long entry name if translation succeeds
+ * msg otherwise
+ */
+char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
+{
+ for (; table->id >= 0; ++table) {
+ if (table->id == id)
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+ return table->lname;
+#else
+ return table->lname + gd->reloc_off;
+#endif
+ }
+ return (msg);
+}
+
+const char *genimg_get_os_name (uint8_t os)
+{
+ return (get_table_entry_name (uimage_os, "Unknown OS", os));
+}
+
+const char *genimg_get_arch_name (uint8_t arch)
+{
+ return (get_table_entry_name (uimage_arch, "Unknown Architecture", arch));
+}
+
+const char *genimg_get_type_name (uint8_t type)
+{
+ return (get_table_entry_name (uimage_type, "Unknown Image", type));
+}
+
+const char *genimg_get_comp_name (uint8_t comp)
+{
+ return (get_table_entry_name (uimage_comp, "Unknown Compression", comp));
+}
+
+/**
+ * get_table_entry_id - translate short entry name to id
+ * @table: pointer to a translation table for entries of a specific type
+ * @table_name: to be used in case of error
+ * @name: entry short name to be translated
+ *
+ * get_table_entry_id() will go over translation table trying to find
+ * entry that matches given short name. If matching entry is found,
+ * its id returned to the caller.
+ *
+ * returns:
+ * entry id if translation succeeds
+ * -1 otherwise
+ */
+int get_table_entry_id(const table_entry_t *table,
+ const char *table_name, const char *name)
+{
+ const table_entry_t *t;
+#ifdef USE_HOSTCC
+ int first = 1;
+
+ for (t = table; t->id >= 0; ++t) {
+ if (t->sname && strcasecmp(t->sname, name) == 0)
+ return (t->id);
+ }
+
+ fprintf (stderr, "\nInvalid %s Type - valid names are", table_name);
+ for (t = table; t->id >= 0; ++t) {
+ if (t->sname == NULL)
+ continue;
+ fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname);
+ first = 0;
+ }
+ fprintf (stderr, "\n");
+#else
+ for (t = table; t->id >= 0; ++t) {
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ if (t->sname && strcmp(t->sname + gd->reloc_off, name) == 0)
+#else
+ if (t->sname && strcmp(t->sname, name) == 0)
+#endif
+ return (t->id);
+ }
+ debug ("Invalid %s Type: %s\n", table_name, name);
+#endif /* USE_HOSTCC */
+ return (-1);
+}
+
+int genimg_get_os_id (const char *name)
+{
+ return (get_table_entry_id (uimage_os, "OS", name));
+}
+
+int genimg_get_arch_id (const char *name)
+{
+ return (get_table_entry_id (uimage_arch, "CPU", name));
+}
+
+int genimg_get_type_id (const char *name)
+{
+ return (get_table_entry_id (uimage_type, "Image", name));
+}
+
+int genimg_get_comp_id (const char *name)
+{
+ return (get_table_entry_id (uimage_comp, "Compression", name));
+}
+
+#ifndef USE_HOSTCC
+/**
+ * genimg_get_format - get image format type
+ * @img_addr: image start address
+ *
+ * genimg_get_format() checks whether provided address points to a valid
+ * legacy or FIT image.
+ *
+ * New uImage format and FDT blob are based on a libfdt. FDT blob
+ * may be passed directly or embedded in a FIT image. In both situations
+ * genimg_get_format() must be able to dectect libfdt header.
+ *
+ * returns:
+ * image format type or IMAGE_FORMAT_INVALID if no image is present
+ */
+int genimg_get_format (void *img_addr)
+{
+ ulong format = IMAGE_FORMAT_INVALID;
+ const image_header_t *hdr;
+#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
+ char *fit_hdr;
+#endif
+
+ hdr = (const image_header_t *)img_addr;
+ if (image_check_magic(hdr))
+ format = IMAGE_FORMAT_LEGACY;
+#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
+ else {
+ fit_hdr = (char *)img_addr;
+ if (fdt_check_header (fit_hdr) == 0)
+ format = IMAGE_FORMAT_FIT;
+ }
+#endif
+
+ return format;
+}
+
+/**
+ * genimg_get_image - get image from special storage (if necessary)
+ * @img_addr: image start address
+ *
+ * genimg_get_image() checks if provided image start adddress is located
+ * in a dataflash storage. If so, image is moved to a system RAM memory.
+ *
+ * returns:
+ * image start address after possible relocation from special storage
+ */
+ulong genimg_get_image (ulong img_addr)
+{
+ ulong ram_addr = img_addr;
+
+#ifdef CONFIG_HAS_DATAFLASH
+ ulong h_size, d_size;
+
+ if (addr_dataflash (img_addr)){
+ /* ger RAM address */
+ ram_addr = CONFIG_SYS_LOAD_ADDR;
+
+ /* get header size */
+ h_size = image_get_header_size ();
+#if defined(CONFIG_FIT)
+ if (sizeof(struct fdt_header) > h_size)
+ h_size = sizeof(struct fdt_header);
+#endif
+
+ /* read in header */
+ debug (" Reading image header from dataflash address "
+ "%08lx to RAM address %08lx\n", img_addr, ram_addr);
+
+ read_dataflash (img_addr, h_size, (char *)ram_addr);
+
+ /* get data size */
+ switch (genimg_get_format ((void *)ram_addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ d_size = image_get_data_size ((const image_header_t *)ram_addr);
+ debug (" Legacy format image found at 0x%08lx, size 0x%08lx\n",
+ ram_addr, d_size);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ d_size = fit_get_size ((const void *)ram_addr) - h_size;
+ debug (" FIT/FDT format image found at 0x%08lx, size 0x%08lx\n",
+ ram_addr, d_size);
+ break;
+#endif
+ default:
+ printf (" No valid image found at 0x%08lx\n", img_addr);
+ return ram_addr;
+ }
+
+ /* read in image data */
+ debug (" Reading image remaining data from dataflash address "
+ "%08lx to RAM address %08lx\n", img_addr + h_size,
+ ram_addr + h_size);
+
+ read_dataflash (img_addr + h_size, d_size,
+ (char *)(ram_addr + h_size));
+
+ }
+#endif /* CONFIG_HAS_DATAFLASH */
+
+ return ram_addr;
+}
+
+/**
+ * fit_has_config - check if there is a valid FIT configuration
+ * @images: pointer to the bootm command headers structure
+ *
+ * fit_has_config() checks if there is a FIT configuration in use
+ * (if FTI support is present).
+ *
+ * returns:
+ * 0, no FIT support or no configuration found
+ * 1, configuration found
+ */
+int genimg_has_config (bootm_headers_t *images)
+{
+#if defined(CONFIG_FIT)
+ if (images->fit_uname_cfg)
+ return 1;
+#endif
+ return 0;
+}
+
+/**
+ * boot_get_ramdisk - main ramdisk handling routine
+ * @argc: command argument count
+ * @argv: command argument list
+ * @images: pointer to the bootm images structure
+ * @arch: expected ramdisk architecture
+ * @rd_start: pointer to a ulong variable, will hold ramdisk start address
+ * @rd_end: pointer to a ulong variable, will hold ramdisk end
+ *
+ * boot_get_ramdisk() is responsible for finding a valid ramdisk image.
+ * Curently supported are the following ramdisk sources:
+ * - multicomponent kernel/ramdisk image,
+ * - commandline provided address of decicated ramdisk image.
+ *
+ * returns:
+ * 0, if ramdisk image was found and valid, or skiped
+ * rd_start and rd_end are set to ramdisk start/end addresses if
+ * ramdisk image is found and valid
+ *
+ * 1, if ramdisk image is found but corrupted, or invalid
+ * rd_start and rd_end are set to 0 if no ramdisk exists
+ */
+int boot_get_ramdisk (int argc, char * const argv[], bootm_headers_t *images,
+ uint8_t arch, ulong *rd_start, ulong *rd_end)
+{
+ ulong rd_addr, rd_load;
+ ulong rd_data, rd_len;
+ const image_header_t *rd_hdr;
+#if defined(CONFIG_FIT)
+ void *fit_hdr;
+ const char *fit_uname_config = NULL;
+ const char *fit_uname_ramdisk = NULL;
+ ulong default_addr;
+ int rd_noffset;
+ int cfg_noffset;
+ const void *data;
+ size_t size;
+#endif
+
+ *rd_start = 0;
+ *rd_end = 0;
+
+ /*
+ * Look for a '-' which indicates to ignore the
+ * ramdisk argument
+ */
+ if ((argc >= 3) && (strcmp(argv[2], "-") == 0)) {
+ debug ("## Skipping init Ramdisk\n");
+ rd_len = rd_data = 0;
+ } else if (argc >= 3 || genimg_has_config (images)) {
+#if defined(CONFIG_FIT)
+ if (argc >= 3) {
+ /*
+ * If the init ramdisk comes from the FIT image and
+ * the FIT image address is omitted in the command
+ * line argument, try to use os FIT image address or
+ * default load address.
+ */
+ if (images->fit_uname_os)
+ default_addr = (ulong)images->fit_hdr_os;
+ else
+ default_addr = load_addr;
+
+ if (fit_parse_conf (argv[2], default_addr,
+ &rd_addr, &fit_uname_config)) {
+ debug ("* ramdisk: config '%s' from image at 0x%08lx\n",
+ fit_uname_config, rd_addr);
+ } else if (fit_parse_subimage (argv[2], default_addr,
+ &rd_addr, &fit_uname_ramdisk)) {
+ debug ("* ramdisk: subimage '%s' from image at 0x%08lx\n",
+ fit_uname_ramdisk, rd_addr);
+ } else
+#endif
+ {
+ rd_addr = simple_strtoul(argv[2], NULL, 16);
+ debug ("* ramdisk: cmdline image address = 0x%08lx\n",
+ rd_addr);
+ }
+#if defined(CONFIG_FIT)
+ } else {
+ /* use FIT configuration provided in first bootm
+ * command argument
+ */
+ rd_addr = (ulong)images->fit_hdr_os;
+ fit_uname_config = images->fit_uname_cfg;
+ debug ("* ramdisk: using config '%s' from image at 0x%08lx\n",
+ fit_uname_config, rd_addr);
+
+ /*
+ * Check whether configuration has ramdisk defined,
+ * if not, don't try to use it, quit silently.
+ */
+ fit_hdr = (void *)rd_addr;
+ cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);
+ if (cfg_noffset < 0) {
+ debug ("* ramdisk: no such config\n");
+ return 1;
+ }
+
+ rd_noffset = fit_conf_get_ramdisk_node (fit_hdr, cfg_noffset);
+ if (rd_noffset < 0) {
+ debug ("* ramdisk: no ramdisk in config\n");
+ return 0;
+ }
+ }
+#endif
+
+ /* copy from dataflash if needed */
+ rd_addr = genimg_get_image (rd_addr);
+
+ /*
+ * Check if there is an initrd image at the
+ * address provided in the second bootm argument
+ * check image type, for FIT images get FIT node.
+ */
+ switch (genimg_get_format ((void *)rd_addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ printf ("## Loading init Ramdisk from Legacy "
+ "Image at %08lx ...\n", rd_addr);
+
+ show_boot_progress (9);
+ rd_hdr = image_get_ramdisk (rd_addr, arch,
+ images->verify);
+
+ if (rd_hdr == NULL)
+ return 1;
+
+ rd_data = image_get_data (rd_hdr);
+ rd_len = image_get_data_size (rd_hdr);
+ rd_load = image_get_load (rd_hdr);
+ break;
+#if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = (void *)rd_addr;
+ printf ("## Loading init Ramdisk from FIT "
+ "Image at %08lx ...\n", rd_addr);
+
+ show_boot_progress (120);
+ if (!fit_check_format (fit_hdr)) {
+ puts ("Bad FIT ramdisk image format!\n");
+ show_boot_progress (-120);
+ return 1;
+ }
+ show_boot_progress (121);
+
+ if (!fit_uname_ramdisk) {
+ /*
+ * no ramdisk image node unit name, try to get config
+ * node first. If config unit node name is NULL
+ * fit_conf_get_node() will try to find default config node
+ */
+ show_boot_progress (122);
+ cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);
+ if (cfg_noffset < 0) {
+ puts ("Could not find configuration node\n");
+ show_boot_progress (-122);
+ return 1;
+ }
+ fit_uname_config = fdt_get_name (fit_hdr, cfg_noffset, NULL);
+ printf (" Using '%s' configuration\n", fit_uname_config);
+
+ rd_noffset = fit_conf_get_ramdisk_node (fit_hdr, cfg_noffset);
+ fit_uname_ramdisk = fit_get_name (fit_hdr, rd_noffset, NULL);
+ } else {
+ /* get ramdisk component image node offset */
+ show_boot_progress (123);
+ rd_noffset = fit_image_get_node (fit_hdr, fit_uname_ramdisk);
+ }
+ if (rd_noffset < 0) {
+ puts ("Could not find subimage node\n");
+ show_boot_progress (-124);
+ return 1;
+ }
+
+ printf (" Trying '%s' ramdisk subimage\n", fit_uname_ramdisk);
+
+ show_boot_progress (125);
+ if (!fit_check_ramdisk (fit_hdr, rd_noffset, arch, images->verify))
+ return 1;
+
+ /* get ramdisk image data address and length */
+ if (fit_image_get_data (fit_hdr, rd_noffset, &data, &size)) {
+ puts ("Could not find ramdisk subimage data!\n");
+ show_boot_progress (-127);
+ return 1;
+ }
+ show_boot_progress (128);
+
+ rd_data = (ulong)data;
+ rd_len = size;
+
+ if (fit_image_get_load (fit_hdr, rd_noffset, &rd_load)) {
+ puts ("Can't get ramdisk subimage load address!\n");
+ show_boot_progress (-129);
+ return 1;
+ }
+ show_boot_progress (129);
+
+ images->fit_hdr_rd = fit_hdr;
+ images->fit_uname_rd = fit_uname_ramdisk;
+ images->fit_noffset_rd = rd_noffset;
+ break;
+#endif
+ default:
+ puts ("Wrong Ramdisk Image Format\n");
+ rd_data = rd_len = rd_load = 0;
+ return 1;
+ }
+
+#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
+ /*
+ * We need to copy the ramdisk to SRAM to let Linux boot
+ */
+ if (rd_data) {
+ memmove ((void *)rd_load, (uchar *)rd_data, rd_len);
+ rd_data = rd_load;
+ }
+#endif /* CONFIG_B2 || CONFIG_EVB4510 || CONFIG_ARMADILLO */
+
+ } else if (images->legacy_hdr_valid &&
+ image_check_type (&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
+ /*
+ * Now check if we have a legacy mult-component image,
+ * get second entry data start address and len.
+ */
+ show_boot_progress (13);
+ printf ("## Loading init Ramdisk from multi component "
+ "Legacy Image at %08lx ...\n",
+ (ulong)images->legacy_hdr_os);
+
+ image_multi_getimg (images->legacy_hdr_os, 1, &rd_data, &rd_len);
+ } else {
+ /*
+ * no initrd image
+ */
+ show_boot_progress (14);
+ rd_len = rd_data = 0;
+ }
+
+ if (!rd_data) {
+ debug ("## No init Ramdisk\n");
+ } else {
+ *rd_start = rd_data;
+ *rd_end = rd_data + rd_len;
+ }
+ debug (" ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
+ *rd_start, *rd_end);
+
+ return 0;
+}
+
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+/**
+ * boot_ramdisk_high - relocate init ramdisk
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @rd_data: ramdisk data start address
+ * @rd_len: ramdisk data length
+ * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
+ * start address (after possible relocation)
+ * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
+ * end address (after possible relocation)
+ *
+ * boot_ramdisk_high() takes a relocation hint from "initrd_high" environement
+ * variable and if requested ramdisk data is moved to a specified location.
+ *
+ * Initrd_start and initrd_end are set to final (after relocation) ramdisk
+ * start/end addresses if ramdisk image start and len were provided,
+ * otherwise set initrd_start and initrd_end set to zeros.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len,
+ ulong *initrd_start, ulong *initrd_end)
+{
+ char *s;
+ ulong initrd_high;
+ int initrd_copy_to_ram = 1;
+
+ if ((s = getenv ("initrd_high")) != NULL) {
+ /* a value of "no" or a similar string will act like 0,
+ * turning the "load high" feature off. This is intentional.
+ */
+ initrd_high = simple_strtoul (s, NULL, 16);
+ if (initrd_high == ~0)
+ initrd_copy_to_ram = 0;
+ } else {
+ /* not set, no restrictions to load high */
+ initrd_high = ~0;
+ }
+
+
+#ifdef CONFIG_LOGBUFFER
+ /* Prevent initrd from overwriting logbuffer */
+ lmb_reserve(lmb, logbuffer_base() - LOGBUFF_OVERHEAD, LOGBUFF_RESERVE);
+#endif
+
+ debug ("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
+ initrd_high, initrd_copy_to_ram);
+
+ if (rd_data) {
+ if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */
+ debug (" in-place initrd\n");
+ *initrd_start = rd_data;
+ *initrd_end = rd_data + rd_len;
+ lmb_reserve(lmb, rd_data, rd_len);
+ } else {
+ if (initrd_high)
+ *initrd_start = (ulong)lmb_alloc_base (lmb, rd_len, 0x1000, initrd_high);
+ else
+ *initrd_start = (ulong)lmb_alloc (lmb, rd_len, 0x1000);
+
+ if (*initrd_start == 0) {
+ puts ("ramdisk - allocation error\n");
+ goto error;
+ }
+ show_boot_progress (12);
+
+ *initrd_end = *initrd_start + rd_len;
+ printf (" Loading Ramdisk to %08lx, end %08lx ... ",
+ *initrd_start, *initrd_end);
+
+ memmove_wd ((void *)*initrd_start,
+ (void *)rd_data, rd_len, CHUNKSZ);
+
+ puts ("OK\n");
+ }
+ } else {
+ *initrd_start = 0;
+ *initrd_end = 0;
+ }
+ debug (" ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
+ *initrd_start, *initrd_end);
+
+ return 0;
+
+error:
+ return -1;
+}
+#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
+
+#ifdef CONFIG_OF_LIBFDT
+static void fdt_error (const char *msg)
+{
+ puts ("ERROR: ");
+ puts (msg);
+ puts (" - must RESET the board to recover.\n");
+}
+
+static const image_header_t *image_get_fdt (ulong fdt_addr)
+{
+ const image_header_t *fdt_hdr = (const image_header_t *)fdt_addr;
+
+ image_print_contents (fdt_hdr);
+
+ puts (" Verifying Checksum ... ");
+ if (!image_check_hcrc (fdt_hdr)) {
+ fdt_error ("fdt header checksum invalid");
+ return NULL;
+ }
+
+ if (!image_check_dcrc (fdt_hdr)) {
+ fdt_error ("fdt checksum invalid");
+ return NULL;
+ }
+ puts ("OK\n");
+
+ if (!image_check_type (fdt_hdr, IH_TYPE_FLATDT)) {
+ fdt_error ("uImage is not a fdt");
+ return NULL;
+ }
+ if (image_get_comp (fdt_hdr) != IH_COMP_NONE) {
+ fdt_error ("uImage is compressed");
+ return NULL;
+ }
+ if (fdt_check_header ((char *)image_get_data (fdt_hdr)) != 0) {
+ fdt_error ("uImage data is not a fdt");
+ return NULL;
+ }
+ return fdt_hdr;
+}
+
+/**
+ * fit_check_fdt - verify FIT format FDT subimage
+ * @fit_hdr: pointer to the FIT header
+ * fdt_noffset: FDT subimage node offset within FIT image
+ * @verify: data CRC verification flag
+ *
+ * fit_check_fdt() verifies integrity of the FDT subimage and from
+ * specified FIT image.
+ *
+ * returns:
+ * 1, on success
+ * 0, on failure
+ */
+#if defined(CONFIG_FIT)
+static int fit_check_fdt (const void *fit, int fdt_noffset, int verify)
+{
+ fit_image_print (fit, fdt_noffset, " ");
+
+ if (verify) {
+ puts (" Verifying Hash Integrity ... ");
+ if (!fit_image_check_hashes (fit, fdt_noffset)) {
+ fdt_error ("Bad Data Hash");
+ return 0;
+ }
+ puts ("OK\n");
+ }
+
+ if (!fit_image_check_type (fit, fdt_noffset, IH_TYPE_FLATDT)) {
+ fdt_error ("Not a FDT image");
+ return 0;
+ }
+
+ if (!fit_image_check_comp (fit, fdt_noffset, IH_COMP_NONE)) {
+ fdt_error ("FDT image is compressed");
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* CONFIG_FIT */
+
+#ifndef CONFIG_SYS_FDT_PAD
+#define CONFIG_SYS_FDT_PAD 0x3000
+#endif
+
+/**
+ * boot_relocate_fdt - relocate flat device tree
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @bootmap_base: base address of the bootmap region
+ * @of_flat_tree: pointer to a char* variable, will hold fdt start address
+ * @of_size: pointer to a ulong variable, will hold fdt length
+ *
+ * boot_relocate_fdt() allocates a region of memory within the bootmap and
+ * relocates the of_flat_tree into that region, even if the fdt is already in
+ * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
+ * bytes.
+ *
+ * of_flat_tree and of_size are set to final (after relocation) values
+ *
+ * returns:
+ * 0 - success
+ * 1 - failure
+ */
+#if defined(CONFIG_SYS_BOOTMAPSZ)
+int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
+ char **of_flat_tree, ulong *of_size)
+{
+ void *fdt_blob = *of_flat_tree;
+ void *of_start = 0;
+ ulong of_len = 0;
+ int err;
+
+ /* nothing to do */
+ if (*of_size == 0)
+ return 0;
+
+ if (fdt_check_header (fdt_blob) != 0) {
+ fdt_error ("image is not a fdt");
+ goto error;
+ }
+
+ /* position on a 4K boundary before the alloc_current */
+ /* Pad the FDT by a specified amount */
+ of_len = *of_size + CONFIG_SYS_FDT_PAD;
+ of_start = (void *)(unsigned long)lmb_alloc_base(lmb, of_len, 0x1000,
+ (CONFIG_SYS_BOOTMAPSZ + bootmap_base));
+
+ if (of_start == 0) {
+ puts("device tree - allocation error\n");
+ goto error;
+ }
+
+ debug ("## device tree at %p ... %p (len=%ld [0x%lX])\n",
+ fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
+
+ printf (" Loading Device Tree to %p, end %p ... ",
+ of_start, of_start + of_len - 1);
+
+ err = fdt_open_into (fdt_blob, of_start, of_len);
+ if (err != 0) {
+ fdt_error ("fdt move failed");
+ goto error;
+ }
+ puts ("OK\n");
+
+ *of_flat_tree = of_start;
+ *of_size = of_len;
+
+ set_working_fdt_addr(*of_flat_tree);
+ return 0;
+
+error:
+ return 1;
+}
+#endif /* CONFIG_SYS_BOOTMAPSZ */
+
+/**
+ * boot_get_fdt - main fdt handling routine
+ * @argc: command argument count
+ * @argv: command argument list
+ * @images: pointer to the bootm images structure
+ * @of_flat_tree: pointer to a char* variable, will hold fdt start address
+ * @of_size: pointer to a ulong variable, will hold fdt length
+ *
+ * boot_get_fdt() is responsible for finding a valid flat device tree image.
+ * Curently supported are the following ramdisk sources:
+ * - multicomponent kernel/ramdisk image,
+ * - commandline provided address of decicated ramdisk image.
+ *
+ * returns:
+ * 0, if fdt image was found and valid, or skipped
+ * of_flat_tree and of_size are set to fdt start address and length if
+ * fdt image is found and valid
+ *
+ * 1, if fdt image is found but corrupted
+ * of_flat_tree and of_size are set to 0 if no fdt exists
+ */
+int boot_get_fdt (int flag, int argc, char * const argv[], bootm_headers_t *images,
+ char **of_flat_tree, ulong *of_size)
+{
+ const image_header_t *fdt_hdr;
+ ulong fdt_addr;
+ char *fdt_blob = NULL;
+ ulong image_start, image_end;
+ ulong load_start, load_end;
+#if defined(CONFIG_FIT)
+ void *fit_hdr;
+ const char *fit_uname_config = NULL;
+ const char *fit_uname_fdt = NULL;
+ ulong default_addr;
+ int cfg_noffset;
+ int fdt_noffset;
+ const void *data;
+ size_t size;
+#endif
+
+ *of_flat_tree = NULL;
+ *of_size = 0;
+
+ if (argc > 3 || genimg_has_config (images)) {
+#if defined(CONFIG_FIT)
+ if (argc > 3) {
+ /*
+ * If the FDT blob comes from the FIT image and the
+ * FIT image address is omitted in the command line
+ * argument, try to use ramdisk or os FIT image
+ * address or default load address.
+ */
+ if (images->fit_uname_rd)
+ default_addr = (ulong)images->fit_hdr_rd;
+ else if (images->fit_uname_os)
+ default_addr = (ulong)images->fit_hdr_os;
+ else
+ default_addr = load_addr;
+
+ if (fit_parse_conf (argv[3], default_addr,
+ &fdt_addr, &fit_uname_config)) {
+ debug ("* fdt: config '%s' from image at 0x%08lx\n",
+ fit_uname_config, fdt_addr);
+ } else if (fit_parse_subimage (argv[3], default_addr,
+ &fdt_addr, &fit_uname_fdt)) {
+ debug ("* fdt: subimage '%s' from image at 0x%08lx\n",
+ fit_uname_fdt, fdt_addr);
+ } else
+#endif
+ {
+ fdt_addr = simple_strtoul(argv[3], NULL, 16);
+ debug ("* fdt: cmdline image address = 0x%08lx\n",
+ fdt_addr);
+ }
+#if defined(CONFIG_FIT)
+ } else {
+ /* use FIT configuration provided in first bootm
+ * command argument
+ */
+ fdt_addr = (ulong)images->fit_hdr_os;
+ fit_uname_config = images->fit_uname_cfg;
+ debug ("* fdt: using config '%s' from image at 0x%08lx\n",
+ fit_uname_config, fdt_addr);
+
+ /*
+ * Check whether configuration has FDT blob defined,
+ * if not quit silently.
+ */
+ fit_hdr = (void *)fdt_addr;
+ cfg_noffset = fit_conf_get_node (fit_hdr,
+ fit_uname_config);
+ if (cfg_noffset < 0) {
+ debug ("* fdt: no such config\n");
+ return 0;
+ }
+
+ fdt_noffset = fit_conf_get_fdt_node (fit_hdr,
+ cfg_noffset);
+ if (fdt_noffset < 0) {
+ debug ("* fdt: no fdt in config\n");
+ return 0;
+ }
+ }
+#endif
+
+ debug ("## Checking for 'FDT'/'FDT Image' at %08lx\n",
+ fdt_addr);
+
+ /* copy from dataflash if needed */
+ fdt_addr = genimg_get_image (fdt_addr);
+
+ /*
+ * Check if there is an FDT image at the
+ * address provided in the second bootm argument
+ * check image type, for FIT images get a FIT node.
+ */
+ switch (genimg_get_format ((void *)fdt_addr)) {
+ case IMAGE_FORMAT_LEGACY:
+ /* verify fdt_addr points to a valid image header */
+ printf ("## Flattened Device Tree from Legacy Image at %08lx\n",
+ fdt_addr);
+ fdt_hdr = image_get_fdt (fdt_addr);
+ if (!fdt_hdr)
+ goto error;
+
+ /*
+ * move image data to the load address,
+ * make sure we don't overwrite initial image
+ */
+ image_start = (ulong)fdt_hdr;
+ image_end = image_get_image_end (fdt_hdr);
+
+ load_start = image_get_load (fdt_hdr);
+ load_end = load_start + image_get_data_size (fdt_hdr);
+
+ if ((load_start < image_end) && (load_end > image_start)) {
+ fdt_error ("fdt overwritten");
+ goto error;
+ }
+
+ debug (" Loading FDT from 0x%08lx to 0x%08lx\n",
+ image_get_data (fdt_hdr), load_start);
+
+ memmove ((void *)load_start,
+ (void *)image_get_data (fdt_hdr),
+ image_get_data_size (fdt_hdr));
+
+ fdt_blob = (char *)load_start;
+ break;
+ case IMAGE_FORMAT_FIT:
+ /*
+ * This case will catch both: new uImage format
+ * (libfdt based) and raw FDT blob (also libfdt
+ * based).
+ */
+#if defined(CONFIG_FIT)
+ /* check FDT blob vs FIT blob */
+ if (fit_check_format ((const void *)fdt_addr)) {
+ /*
+ * FIT image
+ */
+ fit_hdr = (void *)fdt_addr;
+ printf ("## Flattened Device Tree from FIT Image at %08lx\n",
+ fdt_addr);
+
+ if (!fit_uname_fdt) {
+ /*
+ * no FDT blob image node unit name,
+ * try to get config node first. If
+ * config unit node name is NULL
+ * fit_conf_get_node() will try to
+ * find default config node
+ */
+ cfg_noffset = fit_conf_get_node (fit_hdr,
+ fit_uname_config);
+
+ if (cfg_noffset < 0) {
+ fdt_error ("Could not find configuration node\n");
+ goto error;
+ }
+
+ fit_uname_config = fdt_get_name (fit_hdr,
+ cfg_noffset, NULL);
+ printf (" Using '%s' configuration\n",
+ fit_uname_config);
+
+ fdt_noffset = fit_conf_get_fdt_node (fit_hdr,
+ cfg_noffset);
+ fit_uname_fdt = fit_get_name (fit_hdr,
+ fdt_noffset, NULL);
+ } else {
+ /* get FDT component image node offset */
+ fdt_noffset = fit_image_get_node (fit_hdr,
+ fit_uname_fdt);
+ }
+ if (fdt_noffset < 0) {
+ fdt_error ("Could not find subimage node\n");
+ goto error;
+ }
+
+ printf (" Trying '%s' FDT blob subimage\n",
+ fit_uname_fdt);
+
+ if (!fit_check_fdt (fit_hdr, fdt_noffset,
+ images->verify))
+ goto error;
+
+ /* get ramdisk image data address and length */
+ if (fit_image_get_data (fit_hdr, fdt_noffset,
+ &data, &size)) {
+ fdt_error ("Could not find FDT subimage data");
+ goto error;
+ }
+
+ /* verift that image data is a proper FDT blob */
+ if (fdt_check_header ((char *)data) != 0) {
+ fdt_error ("Subimage data is not a FTD");
+ goto error;
+ }
+
+ /*
+ * move image data to the load address,
+ * make sure we don't overwrite initial image
+ */
+ image_start = (ulong)fit_hdr;
+ image_end = fit_get_end (fit_hdr);
+
+ if (fit_image_get_load (fit_hdr, fdt_noffset,
+ &load_start) == 0) {
+ load_end = load_start + size;
+
+ if ((load_start < image_end) &&
+ (load_end > image_start)) {
+ fdt_error ("FDT overwritten");
+ goto error;
+ }
+
+ printf (" Loading FDT from 0x%08lx to 0x%08lx\n",
+ (ulong)data, load_start);
+
+ memmove ((void *)load_start,
+ (void *)data, size);
+
+ fdt_blob = (char *)load_start;
+ } else {
+ fdt_blob = (char *)data;
+ }
+
+ images->fit_hdr_fdt = fit_hdr;
+ images->fit_uname_fdt = fit_uname_fdt;
+ images->fit_noffset_fdt = fdt_noffset;
+ break;
+ } else
+#endif
+ {
+ /*
+ * FDT blob
+ */
+ fdt_blob = (char *)fdt_addr;
+ debug ("* fdt: raw FDT blob\n");
+ printf ("## Flattened Device Tree blob at %08lx\n", (long)fdt_blob);
+ }
+ break;
+ default:
+ puts ("ERROR: Did not find a cmdline Flattened Device Tree\n");
+ goto error;
+ }
+
+ printf (" Booting using the fdt blob at 0x%x\n", (int)fdt_blob);
+
+ } else if (images->legacy_hdr_valid &&
+ image_check_type (&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
+
+ ulong fdt_data, fdt_len;
+
+ /*
+ * Now check if we have a legacy multi-component image,
+ * get second entry data start address and len.
+ */
+ printf ("## Flattened Device Tree from multi "
+ "component Image at %08lX\n",
+ (ulong)images->legacy_hdr_os);
+
+ image_multi_getimg (images->legacy_hdr_os, 2, &fdt_data, &fdt_len);
+ if (fdt_len) {
+
+ fdt_blob = (char *)fdt_data;
+ printf (" Booting using the fdt at 0x%x\n", (int)fdt_blob);
+
+ if (fdt_check_header (fdt_blob) != 0) {
+ fdt_error ("image is not a fdt");
+ goto error;
+ }
+
+ if (fdt_totalsize(fdt_blob) != fdt_len) {
+ fdt_error ("fdt size != image size");
+ goto error;
+ }
+ } else {
+ debug ("## No Flattened Device Tree\n");
+ return 0;
+ }
+ } else {
+ debug ("## No Flattened Device Tree\n");
+ return 0;
+ }
+
+ *of_flat_tree = fdt_blob;
+ *of_size = fdt_totalsize(fdt_blob);
+ debug (" of_flat_tree at 0x%08lx size 0x%08lx\n",
+ (ulong)*of_flat_tree, *of_size);
+
+ return 0;
+
+error:
+ *of_flat_tree = 0;
+ *of_size = 0;
+ return 1;
+}
+#endif /* CONFIG_OF_LIBFDT */
+
+#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
+/**
+ * boot_get_cmdline - allocate and initialize kernel cmdline
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @cmd_start: pointer to a ulong variable, will hold cmdline start
+ * @cmd_end: pointer to a ulong variable, will hold cmdline end
+ * @bootmap_base: ulong variable, holds offset in physical memory to
+ * base of bootmap
+ *
+ * boot_get_cmdline() allocates space for kernel command line below
+ * BOOTMAPSZ + bootmap_base address. If "bootargs" U-boot environemnt
+ * variable is present its contents is copied to allocated kernel
+ * command line.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_get_cmdline (struct lmb *lmb, ulong *cmd_start, ulong *cmd_end,
+ ulong bootmap_base)
+{
+ char *cmdline;
+ char *s;
+
+ cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf,
+ CONFIG_SYS_BOOTMAPSZ + bootmap_base);
+
+ if (cmdline == NULL)
+ return -1;
+
+ if ((s = getenv("bootargs")) == NULL)
+ s = "";
+
+ strcpy(cmdline, s);
+
+ *cmd_start = (ulong) & cmdline[0];
+ *cmd_end = *cmd_start + strlen(cmdline);
+
+ debug ("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
+
+ return 0;
+}
+#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
+
+#ifdef CONFIG_SYS_BOOT_GET_KBD
+/**
+ * boot_get_kbd - allocate and initialize kernel copy of board info
+ * @lmb: pointer to lmb handle, will be used for memory mgmt
+ * @kbd: double pointer to board info data
+ * @bootmap_base: ulong variable, holds offset in physical memory to
+ * base of bootmap
+ *
+ * boot_get_kbd() allocates space for kernel copy of board info data below
+ * BOOTMAPSZ + bootmap_base address and kernel board info is initialized with
+ * the current u-boot board info data.
+ *
+ * returns:
+ * 0 - success
+ * -1 - failure
+ */
+int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base)
+{
+ *kbd = (bd_t *)(ulong)lmb_alloc_base(lmb, sizeof(bd_t), 0xf,
+ CONFIG_SYS_BOOTMAPSZ + bootmap_base);
+ if (*kbd == NULL)
+ return -1;
+
+ **kbd = *(gd->bd);
+
+ debug ("## kernel board info at 0x%08lx\n", (ulong)*kbd);
+
+#if defined(DEBUG) && defined(CONFIG_CMD_BDI)
+ do_bdinfo(NULL, 0, 0, NULL);
+#endif
+
+ return 0;
+}
+#endif /* CONFIG_SYS_BOOT_GET_KBD */
+#endif /* !USE_HOSTCC */
+
+#if defined(CONFIG_FIT)
+/*****************************************************************************/
+/* New uImage format routines */
+/*****************************************************************************/
+#ifndef USE_HOSTCC
+static int fit_parse_spec (const char *spec, char sepc, ulong addr_curr,
+ ulong *addr, const char **name)
+{
+ const char *sep;
+
+ *addr = addr_curr;
+ *name = NULL;
+
+ sep = strchr (spec, sepc);
+ if (sep) {
+ if (sep - spec > 0)
+ *addr = simple_strtoul (spec, NULL, 16);
+
+ *name = sep + 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_parse_conf - parse FIT configuration spec
+ * @spec: input string, containing configuration spec
+ * @add_curr: current image address (to be used as a possible default)
+ * @addr: pointer to a ulong variable, will hold FIT image address of a given
+ * configuration
+ * @conf_name double pointer to a char, will hold pointer to a configuration
+ * unit name
+ *
+ * fit_parse_conf() expects configuration spec in the for of [<addr>]#<conf>,
+ * where <addr> is a FIT image address that contains configuration
+ * with a <conf> unit name.
+ *
+ * Address part is optional, and if omitted default add_curr will
+ * be used instead.
+ *
+ * returns:
+ * 1 if spec is a valid configuration string,
+ * addr and conf_name are set accordingly
+ * 0 otherwise
+ */
+inline int fit_parse_conf (const char *spec, ulong addr_curr,
+ ulong *addr, const char **conf_name)
+{
+ return fit_parse_spec (spec, '#', addr_curr, addr, conf_name);
+}
+
+/**
+ * fit_parse_subimage - parse FIT subimage spec
+ * @spec: input string, containing subimage spec
+ * @add_curr: current image address (to be used as a possible default)
+ * @addr: pointer to a ulong variable, will hold FIT image address of a given
+ * subimage
+ * @image_name: double pointer to a char, will hold pointer to a subimage name
+ *
+ * fit_parse_subimage() expects subimage spec in the for of
+ * [<addr>]:<subimage>, where <addr> is a FIT image address that contains
+ * subimage with a <subimg> unit name.
+ *
+ * Address part is optional, and if omitted default add_curr will
+ * be used instead.
+ *
+ * returns:
+ * 1 if spec is a valid subimage string,
+ * addr and image_name are set accordingly
+ * 0 otherwise
+ */
+inline int fit_parse_subimage (const char *spec, ulong addr_curr,
+ ulong *addr, const char **image_name)
+{
+ return fit_parse_spec (spec, ':', addr_curr, addr, image_name);
+}
+#endif /* !USE_HOSTCC */
+
+static void fit_get_debug (const void *fit, int noffset,
+ char *prop_name, int err)
+{
+ debug ("Can't get '%s' property from FIT 0x%08lx, "
+ "node: offset %d, name %s (%s)\n",
+ prop_name, (ulong)fit, noffset,
+ fit_get_name (fit, noffset, NULL),
+ fdt_strerror (err));
+}
+
+/**
+ * fit_print_contents - prints out the contents of the FIT format image
+ * @fit: pointer to the FIT format image header
+ * @p: pointer to prefix string
+ *
+ * fit_print_contents() formats a multi line FIT image contents description.
+ * The routine prints out FIT image properties (root node level) follwed by
+ * the details of each component image.
+ *
+ * returns:
+ * no returned results
+ */
+void fit_print_contents (const void *fit)
+{
+ char *desc;
+ char *uname;
+ int images_noffset;
+ int confs_noffset;
+ int noffset;
+ int ndepth;
+ int count = 0;
+ int ret;
+ const char *p;
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+ time_t timestamp;
+#endif
+
+#ifdef USE_HOSTCC
+ p = "";
+#else
+ p = " ";
+#endif
+
+ /* Root node properties */
+ ret = fit_get_desc (fit, 0, &desc);
+ printf ("%sFIT description: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("%s\n", desc);
+
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+ ret = fit_get_timestamp (fit, 0, &timestamp);
+ printf ("%sCreated: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ genimg_print_time (timestamp);
+#endif
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf ("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror (images_noffset));
+ return;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (ndepth = 0, count = 0, noffset = fdt_next_node (fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ printf ("%s Image %u (%s)\n", p, count++,
+ fit_get_name(fit, noffset, NULL));
+
+ fit_image_print (fit, noffset, p);
+ }
+ }
+
+ /* Find configurations parent node offset */
+ confs_noffset = fdt_path_offset (fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ debug ("Can't get configurations parent node '%s' (%s)\n",
+ FIT_CONFS_PATH, fdt_strerror (confs_noffset));
+ return;
+ }
+
+ /* get default configuration unit name from default property */
+ uname = (char *)fdt_getprop (fit, noffset, FIT_DEFAULT_PROP, NULL);
+ if (uname)
+ printf ("%s Default Configuration: '%s'\n", p, uname);
+
+ /* Process its subnodes, print out configurations details */
+ for (ndepth = 0, count = 0, noffset = fdt_next_node (fit, confs_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the configurations parent node,
+ * i.e. configuration node.
+ */
+ printf ("%s Configuration %u (%s)\n", p, count++,
+ fit_get_name(fit, noffset, NULL));
+
+ fit_conf_print (fit, noffset, p);
+ }
+ }
+}
+
+/**
+ * fit_image_print - prints out the FIT component image details
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: offset of the component image node
+ * @p: pointer to prefix string
+ *
+ * fit_image_print() lists all mandatory properies for the processed component
+ * image. If present, hash nodes are printed out as well. Load
+ * address for images of type firmware is also printed out. Since the load
+ * address is not mandatory for firmware images, it will be output as
+ * "unavailable" when not present.
+ *
+ * returns:
+ * no returned results
+ */
+void fit_image_print (const void *fit, int image_noffset, const char *p)
+{
+ char *desc;
+ uint8_t type, arch, os, comp;
+ size_t size;
+ ulong load, entry;
+ const void *data;
+ int noffset;
+ int ndepth;
+ int ret;
+
+ /* Mandatory properties */
+ ret = fit_get_desc (fit, image_noffset, &desc);
+ printf ("%s Description: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("%s\n", desc);
+
+ fit_image_get_type (fit, image_noffset, &type);
+ printf ("%s Type: %s\n", p, genimg_get_type_name (type));
+
+ fit_image_get_comp (fit, image_noffset, &comp);
+ printf ("%s Compression: %s\n", p, genimg_get_comp_name (comp));
+
+ ret = fit_image_get_data (fit, image_noffset, &data, &size);
+
+#ifndef USE_HOSTCC
+ printf ("%s Data Start: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("0x%08lx\n", (ulong)data);
+#endif
+
+ printf ("%s Data Size: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ genimg_print_size (size);
+
+ /* Remaining, type dependent properties */
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+ (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
+ (type == IH_TYPE_FLATDT)) {
+ fit_image_get_arch (fit, image_noffset, &arch);
+ printf ("%s Architecture: %s\n", p, genimg_get_arch_name (arch));
+ }
+
+ if (type == IH_TYPE_KERNEL) {
+ fit_image_get_os (fit, image_noffset, &os);
+ printf ("%s OS: %s\n", p, genimg_get_os_name (os));
+ }
+
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+ (type == IH_TYPE_FIRMWARE)) {
+ ret = fit_image_get_load (fit, image_noffset, &load);
+ printf ("%s Load Address: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("0x%08lx\n", load);
+ }
+
+ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE)) {
+ fit_image_get_entry (fit, image_noffset, &entry);
+ printf ("%s Entry Point: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("0x%08lx\n", entry);
+ }
+
+ /* Process all hash subnodes of the component image node */
+ for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /* Direct child node of the component image node */
+ fit_image_print_hash (fit, noffset, p);
+ }
+ }
+}
+
+/**
+ * fit_image_print_hash - prints out the hash node details
+ * @fit: pointer to the FIT format image header
+ * @noffset: offset of the hash node
+ * @p: pointer to prefix string
+ *
+ * fit_image_print_hash() lists properies for the processed hash node
+ *
+ * returns:
+ * no returned results
+ */
+void fit_image_print_hash (const void *fit, int noffset, const char *p)
+{
+ char *algo;
+ uint8_t *value;
+ int value_len;
+ int i, ret;
+
+ /*
+ * Check subnode name, must be equal to "hash".
+ * Multiple hash nodes require unique unit node
+ * names, e.g. hash@1, hash@2, etc.
+ */
+ if (strncmp (fit_get_name(fit, noffset, NULL),
+ FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME)) != 0)
+ return;
+
+ debug ("%s Hash node: '%s'\n", p,
+ fit_get_name (fit, noffset, NULL));
+
+ printf ("%s Hash algo: ", p);
+ if (fit_image_hash_get_algo (fit, noffset, &algo)) {
+ printf ("invalid/unsupported\n");
+ return;
+ }
+ printf ("%s\n", algo);
+
+ ret = fit_image_hash_get_value (fit, noffset, &value,
+ &value_len);
+ printf ("%s Hash value: ", p);
+ if (ret) {
+ printf ("unavailable\n");
+ } else {
+ for (i = 0; i < value_len; i++)
+ printf ("%02x", value[i]);
+ printf ("\n");
+ }
+
+ debug ("%s Hash len: %d\n", p, value_len);
+}
+
+/**
+ * fit_get_desc - get node description property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @desc: double pointer to the char, will hold pointer to the descrption
+ *
+ * fit_get_desc() reads description property from a given node, if
+ * description is found pointer to it is returened in third call argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_get_desc (const void *fit, int noffset, char **desc)
+{
+ int len;
+
+ *desc = (char *)fdt_getprop (fit, noffset, FIT_DESC_PROP, &len);
+ if (*desc == NULL) {
+ fit_get_debug (fit, noffset, FIT_DESC_PROP, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_get_timestamp - get node timestamp property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @timestamp: pointer to the time_t, will hold read timestamp
+ *
+ * fit_get_timestamp() reads timestamp poperty from given node, if timestamp
+ * is found and has a correct size its value is retured in third call
+ * argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, on property read failure
+ * -2, on wrong timestamp size
+ */
+int fit_get_timestamp (const void *fit, int noffset, time_t *timestamp)
+{
+ int len;
+ const void *data;
+
+ data = fdt_getprop (fit, noffset, FIT_TIMESTAMP_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_TIMESTAMP_PROP, len);
+ return -1;
+ }
+ if (len != sizeof (uint32_t)) {
+ debug ("FIT timestamp with incorrect size of (%u)\n", len);
+ return -2;
+ }
+
+ *timestamp = uimage_to_cpu (*((uint32_t *)data));
+ return 0;
+}
+
+/**
+ * fit_image_get_node - get node offset for component image of a given unit name
+ * @fit: pointer to the FIT format image header
+ * @image_uname: component image node unit name
+ *
+ * fit_image_get_node() finds a component image (withing the '/images'
+ * node) of a provided unit name. If image is found its node offset is
+ * returned to the caller.
+ *
+ * returns:
+ * image node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_image_get_node (const void *fit, const char *image_uname)
+{
+ int noffset, images_noffset;
+
+ images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ debug ("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror (images_noffset));
+ return images_noffset;
+ }
+
+ noffset = fdt_subnode_offset (fit, images_noffset, image_uname);
+ if (noffset < 0) {
+ debug ("Can't get node offset for image unit name: '%s' (%s)\n",
+ image_uname, fdt_strerror (noffset));
+ }
+
+ return noffset;
+}
+
+/**
+ * fit_image_get_os - get os id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @os: pointer to the uint8_t, will hold os numeric id
+ *
+ * fit_image_get_os() finds os property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_os (const void *fit, int noffset, uint8_t *os)
+{
+ int len;
+ const void *data;
+
+ /* Get OS name from property data */
+ data = fdt_getprop (fit, noffset, FIT_OS_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_OS_PROP, len);
+ *os = -1;
+ return -1;
+ }
+
+ /* Translate OS name to id */
+ *os = genimg_get_os_id (data);
+ return 0;
+}
+
+/**
+ * fit_image_get_arch - get arch id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @arch: pointer to the uint8_t, will hold arch numeric id
+ *
+ * fit_image_get_arch() finds arch property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_arch (const void *fit, int noffset, uint8_t *arch)
+{
+ int len;
+ const void *data;
+
+ /* Get architecture name from property data */
+ data = fdt_getprop (fit, noffset, FIT_ARCH_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_ARCH_PROP, len);
+ *arch = -1;
+ return -1;
+ }
+
+ /* Translate architecture name to id */
+ *arch = genimg_get_arch_id (data);
+ return 0;
+}
+
+/**
+ * fit_image_get_type - get type id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @type: pointer to the uint8_t, will hold type numeric id
+ *
+ * fit_image_get_type() finds type property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_type (const void *fit, int noffset, uint8_t *type)
+{
+ int len;
+ const void *data;
+
+ /* Get image type name from property data */
+ data = fdt_getprop (fit, noffset, FIT_TYPE_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_TYPE_PROP, len);
+ *type = -1;
+ return -1;
+ }
+
+ /* Translate image type name to id */
+ *type = genimg_get_type_id (data);
+ return 0;
+}
+
+/**
+ * fit_image_get_comp - get comp id for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @comp: pointer to the uint8_t, will hold comp numeric id
+ *
+ * fit_image_get_comp() finds comp property in a given component image node.
+ * If the property is found, its (string) value is translated to the numeric
+ * id which is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp)
+{
+ int len;
+ const void *data;
+
+ /* Get compression name from property data */
+ data = fdt_getprop (fit, noffset, FIT_COMP_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_COMP_PROP, len);
+ *comp = -1;
+ return -1;
+ }
+
+ /* Translate compression name to id */
+ *comp = genimg_get_comp_id (data);
+ return 0;
+}
+
+/**
+ * fit_image_get_load - get load address property for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @load: pointer to the uint32_t, will hold load address
+ *
+ * fit_image_get_load() finds load address property in a given component image node.
+ * If the property is found, its value is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_load (const void *fit, int noffset, ulong *load)
+{
+ int len;
+ const uint32_t *data;
+
+ data = fdt_getprop (fit, noffset, FIT_LOAD_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_LOAD_PROP, len);
+ return -1;
+ }
+
+ *load = uimage_to_cpu (*data);
+ return 0;
+}
+
+/**
+ * fit_image_get_entry - get entry point address property for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @entry: pointer to the uint32_t, will hold entry point address
+ *
+ * fit_image_get_entry() finds entry point address property in a given component image node.
+ * If the property is found, its value is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_entry (const void *fit, int noffset, ulong *entry)
+{
+ int len;
+ const uint32_t *data;
+
+ data = fdt_getprop (fit, noffset, FIT_ENTRY_PROP, &len);
+ if (data == NULL) {
+ fit_get_debug (fit, noffset, FIT_ENTRY_PROP, len);
+ return -1;
+ }
+
+ *entry = uimage_to_cpu (*data);
+ return 0;
+}
+
+/**
+ * fit_image_get_data - get data property and its size for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @data: double pointer to void, will hold data property's data address
+ * @size: pointer to size_t, will hold data property's data size
+ *
+ * fit_image_get_data() finds data property in a given component image node.
+ * If the property is found its data start address and size are returned to
+ * the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_get_data (const void *fit, int noffset,
+ const void **data, size_t *size)
+{
+ int len;
+
+ *data = fdt_getprop (fit, noffset, FIT_DATA_PROP, &len);
+ if (*data == NULL) {
+ fit_get_debug (fit, noffset, FIT_DATA_PROP, len);
+ *size = 0;
+ return -1;
+ }
+
+ *size = len;
+ return 0;
+}
+
+/**
+ * fit_image_hash_get_algo - get hash algorithm name
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @algo: double pointer to char, will hold pointer to the algorithm name
+ *
+ * fit_image_hash_get_algo() finds hash algorithm property in a given hash node.
+ * If the property is found its data start address is returned to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_hash_get_algo (const void *fit, int noffset, char **algo)
+{
+ int len;
+
+ *algo = (char *)fdt_getprop (fit, noffset, FIT_ALGO_PROP, &len);
+ if (*algo == NULL) {
+ fit_get_debug (fit, noffset, FIT_ALGO_PROP, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_hash_get_value - get hash value and length
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: double pointer to uint8_t, will hold address of a hash value data
+ * @value_len: pointer to an int, will hold hash data length
+ *
+ * fit_image_hash_get_value() finds hash value property in a given hash node.
+ * If the property is found its data start address and size are returned to
+ * the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_hash_get_value (const void *fit, int noffset, uint8_t **value,
+ int *value_len)
+{
+ int len;
+
+ *value = (uint8_t *)fdt_getprop (fit, noffset, FIT_VALUE_PROP, &len);
+ if (*value == NULL) {
+ fit_get_debug (fit, noffset, FIT_VALUE_PROP, len);
+ *value_len = 0;
+ return -1;
+ }
+
+ *value_len = len;
+ return 0;
+}
+
+/**
+ * fit_set_timestamp - set node timestamp property
+ * @fit: pointer to the FIT format image header
+ * @noffset: node offset
+ * @timestamp: timestamp value to be set
+ *
+ * fit_set_timestamp() attempts to set timestamp property in the requested
+ * node and returns operation status to the caller.
+ *
+ * returns:
+ * 0, on success
+ * -1, on property read failure
+ */
+int fit_set_timestamp (void *fit, int noffset, time_t timestamp)
+{
+ uint32_t t;
+ int ret;
+
+ t = cpu_to_uimage (timestamp);
+ ret = fdt_setprop (fit, noffset, FIT_TIMESTAMP_PROP, &t,
+ sizeof (uint32_t));
+ if (ret) {
+ printf ("Can't set '%s' property for '%s' node (%s)\n",
+ FIT_TIMESTAMP_PROP, fit_get_name (fit, noffset, NULL),
+ fdt_strerror (ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * calculate_hash - calculate and return hash for provided input data
+ * @data: pointer to the input data
+ * @data_len: data length
+ * @algo: requested hash algorithm
+ * @value: pointer to the char, will hold hash value data (caller must
+ * allocate enough free space)
+ * value_len: length of the calculated hash
+ *
+ * calculate_hash() computes input data hash according to the requested algorithm.
+ * Resulting hash value is placed in caller provided 'value' buffer, length
+ * of the calculated hash is returned via value_len pointer argument.
+ *
+ * returns:
+ * 0, on success
+ * -1, when algo is unsupported
+ */
+static int calculate_hash (const void *data, int data_len, const char *algo,
+ uint8_t *value, int *value_len)
+{
+ if (strcmp (algo, "crc32") == 0 ) {
+ *((uint32_t *)value) = crc32_wd (0, data, data_len,
+ CHUNKSZ_CRC32);
+ *((uint32_t *)value) = cpu_to_uimage (*((uint32_t *)value));
+ *value_len = 4;
+ } else if (strcmp (algo, "sha1") == 0 ) {
+ sha1_csum_wd ((unsigned char *) data, data_len,
+ (unsigned char *) value, CHUNKSZ_SHA1);
+ *value_len = 20;
+ } else if (strcmp (algo, "md5") == 0 ) {
+ md5_wd ((unsigned char *)data, data_len, value, CHUNKSZ_MD5);
+ *value_len = 16;
+ } else {
+ debug ("Unsupported hash alogrithm\n");
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef USE_HOSTCC
+/**
+ * fit_set_hashes - process FIT component image nodes and calculate hashes
+ * @fit: pointer to the FIT format image header
+ *
+ * fit_set_hashes() adds hash values for all component images in the FIT blob.
+ * Hashes are calculated for all component images which have hash subnodes
+ * with algorithm property set to one of the supported hash algorithms.
+ *
+ * returns
+ * 0, on success
+ * libfdt error code, on failure
+ */
+int fit_set_hashes (void *fit)
+{
+ int images_noffset;
+ int noffset;
+ int ndepth;
+ int ret;
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf ("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror (images_noffset));
+ return images_noffset;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (ndepth = 0, noffset = fdt_next_node (fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ ret = fit_image_set_hashes (fit, noffset);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_set_hashes - calculate/set hashes for given component image node
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: requested component image node
+ *
+ * fit_image_set_hashes() adds hash values for an component image node. All
+ * existing hash subnodes are checked, if algorithm property is set to one of
+ * the supported hash algorithms, hash value is computed and corresponding
+ * hash node property is set, for example:
+ *
+ * Input component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ * | - data = [binary data]
+ * o hash@1
+ * |- algo = "sha1"
+ *
+ * Output component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ * | - data = [binary data]
+ * o hash@1
+ * |- algo = "sha1"
+ * |- value = sha1(data)
+ *
+ * returns:
+ * 0 on sucess
+ * <0 on failure
+ */
+int fit_image_set_hashes (void *fit, int image_noffset)
+{
+ const void *data;
+ size_t size;
+ char *algo;
+ uint8_t value[FIT_MAX_HASH_LEN];
+ int value_len;
+ int noffset;
+ int ndepth;
+
+ /* Get image data and data length */
+ if (fit_image_get_data (fit, image_noffset, &data, &size)) {
+ printf ("Can't get image data/size\n");
+ return -1;
+ }
+
+ /* Process all hash subnodes of the component image node */
+ for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /* Direct child node of the component image node */
+
+ /*
+ * Check subnode name, must be equal to "hash".
+ * Multiple hash nodes require unique unit node
+ * names, e.g. hash@1, hash@2, etc.
+ */
+ if (strncmp (fit_get_name(fit, noffset, NULL),
+ FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME)) != 0) {
+ /* Not a hash subnode, skip it */
+ continue;
+ }
+
+ if (fit_image_hash_get_algo (fit, noffset, &algo)) {
+ printf ("Can't get hash algo property for "
+ "'%s' hash node in '%s' image node\n",
+ fit_get_name (fit, noffset, NULL),
+ fit_get_name (fit, image_noffset, NULL));
+ return -1;
+ }
+
+ if (calculate_hash (data, size, algo, value, &value_len)) {
+ printf ("Unsupported hash algorithm (%s) for "
+ "'%s' hash node in '%s' image node\n",
+ algo, fit_get_name (fit, noffset, NULL),
+ fit_get_name (fit, image_noffset, NULL));
+ return -1;
+ }
+
+ if (fit_image_hash_set_value (fit, noffset, value,
+ value_len)) {
+ printf ("Can't set hash value for "
+ "'%s' hash node in '%s' image node\n",
+ fit_get_name (fit, noffset, NULL),
+ fit_get_name (fit, image_noffset, NULL));
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_hash_set_value - set hash value in requested has node
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: hash value to be set
+ * @value_len: hash value length
+ *
+ * fit_image_hash_set_value() attempts to set hash value in a node at offset
+ * given and returns operation status to the caller.
+ *
+ * returns
+ * 0, on success
+ * -1, on failure
+ */
+int fit_image_hash_set_value (void *fit, int noffset, uint8_t *value,
+ int value_len)
+{
+ int ret;
+
+ ret = fdt_setprop (fit, noffset, FIT_VALUE_PROP, value, value_len);
+ if (ret) {
+ printf ("Can't set hash '%s' property for '%s' node (%s)\n",
+ FIT_VALUE_PROP, fit_get_name (fit, noffset, NULL),
+ fdt_strerror (ret));
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* USE_HOSTCC */
+
+/**
+ * fit_image_check_hashes - verify data intergity
+ * @fit: pointer to the FIT format image header
+ * @image_noffset: component image node offset
+ *
+ * fit_image_check_hashes() goes over component image hash nodes,
+ * re-calculates each data hash and compares with the value stored in hash
+ * node.
+ *
+ * returns:
+ * 1, if all hashes are valid
+ * 0, otherwise (or on error)
+ */
+int fit_image_check_hashes (const void *fit, int image_noffset)
+{
+ const void *data;
+ size_t size;
+ char *algo;
+ uint8_t *fit_value;
+ int fit_value_len;
+ uint8_t value[FIT_MAX_HASH_LEN];
+ int value_len;
+ int noffset;
+ int ndepth;
+ char *err_msg = "";
+
+ /* Get image data and data length */
+ if (fit_image_get_data (fit, image_noffset, &data, &size)) {
+ printf ("Can't get image data/size\n");
+ return 0;
+ }
+
+ /* Process all hash subnodes of the component image node */
+ for (ndepth = 0, noffset = fdt_next_node (fit, image_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /* Direct child node of the component image node */
+
+ /*
+ * Check subnode name, must be equal to "hash".
+ * Multiple hash nodes require unique unit node
+ * names, e.g. hash@1, hash@2, etc.
+ */
+ if (strncmp (fit_get_name(fit, noffset, NULL),
+ FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME)) != 0)
+ continue;
+
+ if (fit_image_hash_get_algo (fit, noffset, &algo)) {
+ err_msg = " error!\nCan't get hash algo "
+ "property";
+ goto error;
+ }
+ printf ("%s", algo);
+
+ if (fit_image_hash_get_value (fit, noffset, &fit_value,
+ &fit_value_len)) {
+ err_msg = " error!\nCan't get hash value "
+ "property";
+ goto error;
+ }
+
+ if (calculate_hash (data, size, algo, value, &value_len)) {
+ err_msg = " error!\nUnsupported hash algorithm";
+ goto error;
+ }
+
+ if (value_len != fit_value_len) {
+ err_msg = " error !\nBad hash value len";
+ goto error;
+ } else if (memcmp (value, fit_value, value_len) != 0) {
+ err_msg = " error!\nBad hash value";
+ goto error;
+ }
+ printf ("+ ");
+ }
+ }
+
+ return 1;
+
+error:
+ printf ("%s for '%s' hash node in '%s' image node\n",
+ err_msg, fit_get_name (fit, noffset, NULL),
+ fit_get_name (fit, image_noffset, NULL));
+ return 0;
+}
+
+/**
+ * fit_all_image_check_hashes - verify data intergity for all images
+ * @fit: pointer to the FIT format image header
+ *
+ * fit_all_image_check_hashes() goes over all images in the FIT and
+ * for every images checks if all it's hashes are valid.
+ *
+ * returns:
+ * 1, if all hashes of all images are valid
+ * 0, otherwise (or on error)
+ */
+int fit_all_image_check_hashes (const void *fit)
+{
+ int images_noffset;
+ int noffset;
+ int ndepth;
+ int count;
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset (fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf ("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror (images_noffset));
+ return 0;
+ }
+
+ /* Process all image subnodes, check hashes for each */
+ printf ("## Checking hash(es) for FIT Image at %08lx ...\n",
+ (ulong)fit);
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node (fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node (fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ printf (" Hash(es) for Image %u (%s): ", count++,
+ fit_get_name (fit, noffset, NULL));
+
+ if (!fit_image_check_hashes (fit, noffset))
+ return 0;
+ printf ("\n");
+ }
+ }
+ return 1;
+}
+
+/**
+ * fit_image_check_os - check whether image node is of a given os type
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @os: requested image os
+ *
+ * fit_image_check_os() reads image os property and compares its numeric
+ * id with the requested os. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given os type
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_os (const void *fit, int noffset, uint8_t os)
+{
+ uint8_t image_os;
+
+ if (fit_image_get_os (fit, noffset, &image_os))
+ return 0;
+ return (os == image_os);
+}
+
+/**
+ * fit_image_check_arch - check whether image node is of a given arch
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @arch: requested imagearch
+ *
+ * fit_image_check_arch() reads image arch property and compares its numeric
+ * id with the requested arch. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given arch
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_arch (const void *fit, int noffset, uint8_t arch)
+{
+ uint8_t image_arch;
+
+ if (fit_image_get_arch (fit, noffset, &image_arch))
+ return 0;
+ return (arch == image_arch);
+}
+
+/**
+ * fit_image_check_type - check whether image node is of a given type
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @type: requested image type
+ *
+ * fit_image_check_type() reads image type property and compares its numeric
+ * id with the requested type. Comparison result is returned to the caller.
+ *
+ * returns:
+ * 1 if image is of given type
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_type (const void *fit, int noffset, uint8_t type)
+{
+ uint8_t image_type;
+
+ if (fit_image_get_type (fit, noffset, &image_type))
+ return 0;
+ return (type == image_type);
+}
+
+/**
+ * fit_image_check_comp - check whether image node uses given compression
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @comp: requested image compression type
+ *
+ * fit_image_check_comp() reads image compression property and compares its
+ * numeric id with the requested compression type. Comparison result is
+ * returned to the caller.
+ *
+ * returns:
+ * 1 if image uses requested compression
+ * 0 otherwise (or on error)
+ */
+int fit_image_check_comp (const void *fit, int noffset, uint8_t comp)
+{
+ uint8_t image_comp;
+
+ if (fit_image_get_comp (fit, noffset, &image_comp))
+ return 0;
+ return (comp == image_comp);
+}
+
+/**
+ * fit_check_format - sanity check FIT image format
+ * @fit: pointer to the FIT format image header
+ *
+ * fit_check_format() runs a basic sanity FIT image verification.
+ * Routine checks for mandatory properties, nodes, etc.
+ *
+ * returns:
+ * 1, on success
+ * 0, on failure
+ */
+int fit_check_format (const void *fit)
+{
+ /* mandatory / node 'description' property */
+ if (fdt_getprop (fit, 0, FIT_DESC_PROP, NULL) == NULL) {
+ debug ("Wrong FIT format: no description\n");
+ return 0;
+ }
+
+#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
+ /* mandatory / node 'timestamp' property */
+ if (fdt_getprop (fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) {
+ debug ("Wrong FIT format: no timestamp\n");
+ return 0;
+ }
+#endif
+
+ /* mandatory subimages parent '/images' node */
+ if (fdt_path_offset (fit, FIT_IMAGES_PATH) < 0) {
+ debug ("Wrong FIT format: no images parent node\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * fit_conf_get_node - get node offset for configuration of a given unit name
+ * @fit: pointer to the FIT format image header
+ * @conf_uname: configuration node unit name
+ *
+ * fit_conf_get_node() finds a configuration (withing the '/configurations'
+ * parant node) of a provided unit name. If configuration is found its node offset
+ * is returned to the caller.
+ *
+ * When NULL is provided in second argument fit_conf_get_node() will search
+ * for a default configuration node instead. Default configuration node unit name
+ * is retrived from FIT_DEFAULT_PROP property of the '/configurations' node.
+ *
+ * returns:
+ * configuration node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_conf_get_node (const void *fit, const char *conf_uname)
+{
+ int noffset, confs_noffset;
+ int len;
+
+ confs_noffset = fdt_path_offset (fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ debug ("Can't find configurations parent node '%s' (%s)\n",
+ FIT_CONFS_PATH, fdt_strerror (confs_noffset));
+ return confs_noffset;
+ }
+
+ if (conf_uname == NULL) {
+ /* get configuration unit name from the default property */
+ debug ("No configuration specified, trying default...\n");
+ conf_uname = (char *)fdt_getprop (fit, confs_noffset, FIT_DEFAULT_PROP, &len);
+ if (conf_uname == NULL) {
+ fit_get_debug (fit, confs_noffset, FIT_DEFAULT_PROP, len);
+ return len;
+ }
+ debug ("Found default configuration: '%s'\n", conf_uname);
+ }
+
+ noffset = fdt_subnode_offset (fit, confs_noffset, conf_uname);
+ if (noffset < 0) {
+ debug ("Can't get node offset for configuration unit name: '%s' (%s)\n",
+ conf_uname, fdt_strerror (noffset));
+ }
+
+ return noffset;
+}
+
+static int __fit_conf_get_prop_node (const void *fit, int noffset,
+ const char *prop_name)
+{
+ char *uname;
+ int len;
+
+ /* get kernel image unit name from configuration kernel property */
+ uname = (char *)fdt_getprop (fit, noffset, prop_name, &len);
+ if (uname == NULL)
+ return len;
+
+ return fit_image_get_node (fit, uname);
+}
+
+/**
+ * fit_conf_get_kernel_node - get kernel image node offset that corresponds to
+ * a given configuration
+ * @fit: pointer to the FIT format image header
+ * @noffset: configuration node offset
+ *
+ * fit_conf_get_kernel_node() retrives kernel image node unit name from
+ * configuration FIT_KERNEL_PROP property and translates it to the node
+ * offset.
+ *
+ * returns:
+ * image node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_conf_get_kernel_node (const void *fit, int noffset)
+{
+ return __fit_conf_get_prop_node (fit, noffset, FIT_KERNEL_PROP);
+}
+
+/**
+ * fit_conf_get_ramdisk_node - get ramdisk image node offset that corresponds to
+ * a given configuration
+ * @fit: pointer to the FIT format image header
+ * @noffset: configuration node offset
+ *
+ * fit_conf_get_ramdisk_node() retrives ramdisk image node unit name from
+ * configuration FIT_KERNEL_PROP property and translates it to the node
+ * offset.
+ *
+ * returns:
+ * image node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_conf_get_ramdisk_node (const void *fit, int noffset)
+{
+ return __fit_conf_get_prop_node (fit, noffset, FIT_RAMDISK_PROP);
+}
+
+/**
+ * fit_conf_get_fdt_node - get fdt image node offset that corresponds to
+ * a given configuration
+ * @fit: pointer to the FIT format image header
+ * @noffset: configuration node offset
+ *
+ * fit_conf_get_fdt_node() retrives fdt image node unit name from
+ * configuration FIT_KERNEL_PROP property and translates it to the node
+ * offset.
+ *
+ * returns:
+ * image node offset when found (>=0)
+ * negative number on failure (FDT_ERR_* code)
+ */
+int fit_conf_get_fdt_node (const void *fit, int noffset)
+{
+ return __fit_conf_get_prop_node (fit, noffset, FIT_FDT_PROP);
+}
+
+/**
+ * fit_conf_print - prints out the FIT configuration details
+ * @fit: pointer to the FIT format image header
+ * @noffset: offset of the configuration node
+ * @p: pointer to prefix string
+ *
+ * fit_conf_print() lists all mandatory properies for the processed
+ * configuration node.
+ *
+ * returns:
+ * no returned results
+ */
+void fit_conf_print (const void *fit, int noffset, const char *p)
+{
+ char *desc;
+ char *uname;
+ int ret;
+
+ /* Mandatory properties */
+ ret = fit_get_desc (fit, noffset, &desc);
+ printf ("%s Description: ", p);
+ if (ret)
+ printf ("unavailable\n");
+ else
+ printf ("%s\n", desc);
+
+ uname = (char *)fdt_getprop (fit, noffset, FIT_KERNEL_PROP, NULL);
+ printf ("%s Kernel: ", p);
+ if (uname == NULL)
+ printf ("unavailable\n");
+ else
+ printf ("%s\n", uname);
+
+ /* Optional properties */
+ uname = (char *)fdt_getprop (fit, noffset, FIT_RAMDISK_PROP, NULL);
+ if (uname)
+ printf ("%s Init Ramdisk: %s\n", p, uname);
+
+ uname = (char *)fdt_getprop (fit, noffset, FIT_FDT_PROP, NULL);
+ if (uname)
+ printf ("%s FDT: %s\n", p, uname);
+}
+
+/**
+ * fit_check_ramdisk - verify FIT format ramdisk subimage
+ * @fit_hdr: pointer to the FIT ramdisk header
+ * @rd_noffset: ramdisk subimage node offset within FIT image
+ * @arch: requested ramdisk image architecture type
+ * @verify: data CRC verification flag
+ *
+ * fit_check_ramdisk() verifies integrity of the ramdisk subimage and from
+ * specified FIT image.
+ *
+ * returns:
+ * 1, on success
+ * 0, on failure
+ */
+#ifndef USE_HOSTCC
+static int fit_check_ramdisk (const void *fit, int rd_noffset, uint8_t arch, int verify)
+{
+ fit_image_print (fit, rd_noffset, " ");
+
+ if (verify) {
+ puts (" Verifying Hash Integrity ... ");
+ if (!fit_image_check_hashes (fit, rd_noffset)) {
+ puts ("Bad Data Hash\n");
+ show_boot_progress (-125);
+ return 0;
+ }
+ puts ("OK\n");
+ }
+
+ show_boot_progress (126);
+ if (!fit_image_check_os (fit, rd_noffset, IH_OS_LINUX) ||
+ !fit_image_check_arch (fit, rd_noffset, arch) ||
+ !fit_image_check_type (fit, rd_noffset, IH_TYPE_RAMDISK)) {
+ printf ("No Linux %s Ramdisk Image\n",
+ genimg_get_arch_name(arch));
+ show_boot_progress (-126);
+ return 0;
+ }
+
+ show_boot_progress (127);
+ return 1;
+}
+#endif /* USE_HOSTCC */
+#endif /* CONFIG_FIT */
diff --git a/u-boot/common/iomux.c b/u-boot/common/iomux.c
new file mode 100644
index 0000000..91d98e9
--- /dev/null
+++ b/u-boot/common/iomux.c
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
+ *
+ * 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 <serial.h>
+#include <malloc.h>
+
+#ifdef CONFIG_CONSOLE_MUX
+void iomux_printdevs(const int console)
+{
+ int i;
+ struct stdio_dev *dev;
+
+ for (i = 0; i < cd_count[console]; i++) {
+ dev = console_devices[console][i];
+ printf("%s ", dev->name);
+ }
+ printf("\n");
+}
+
+/* This tries to preserve the old list if an error occurs. */
+int iomux_doenv(const int console, const char *arg)
+{
+ char *console_args, *temp, **start;
+ int i, j, k, io_flag, cs_idx, repeat;
+ struct stdio_dev *dev;
+ struct stdio_dev **cons_set;
+
+ console_args = strdup(arg);
+ if (console_args == NULL)
+ return 1;
+ /*
+ * Check whether a comma separated list of devices was
+ * entered and count how many devices were entered.
+ * The array start[] has pointers to the beginning of
+ * each device name (up to MAX_CONSARGS devices).
+ *
+ * Have to do this twice - once to count the number of
+ * commas and then again to populate start.
+ */
+ i = 0;
+ temp = console_args;
+ for (;;) {
+ temp = strchr(temp, ',');
+ if (temp != NULL) {
+ i++;
+ temp++;
+ continue;
+ }
+ /* There's always one entry more than the number of commas. */
+ i++;
+ break;
+ }
+ start = (char **)malloc(i * sizeof(char *));
+ if (start == NULL) {
+ free(console_args);
+ return 1;
+ }
+ i = 0;
+ start[0] = console_args;
+ for (;;) {
+ temp = strchr(start[i++], ',');
+ if (temp == NULL)
+ break;
+ *temp = '\0';
+ start[i] = temp + 1;
+ }
+ cons_set = (struct stdio_dev **)calloc(i, sizeof(struct stdio_dev *));
+ if (cons_set == NULL) {
+ free(start);
+ free(console_args);
+ return 1;
+ }
+
+ switch (console) {
+ case stdin:
+ io_flag = DEV_FLAGS_INPUT;
+ break;
+ case stdout:
+ case stderr:
+ io_flag = DEV_FLAGS_OUTPUT;
+ break;
+ default:
+ free(start);
+ free(console_args);
+ free(cons_set);
+ return 1;
+ }
+
+ cs_idx = 0;
+ for (j = 0; j < i; j++) {
+ /*
+ * Check whether the device exists and is valid.
+ * console_assign() also calls search_device(),
+ * but I need the pointer to the device.
+ */
+ dev = search_device(io_flag, start[j]);
+ if (dev == NULL)
+ continue;
+ /*
+ * Prevent multiple entries for a device.
+ */
+ repeat = 0;
+ for (k = 0; k < cs_idx; k++) {
+ if (dev == cons_set[k]) {
+ repeat++;
+ break;
+ }
+ }
+ if (repeat)
+ continue;
+ /*
+ * Try assigning the specified device.
+ * This could screw up the console settings for apps.
+ */
+ if (console_assign(console, start[j]) < 0)
+ continue;
+#ifdef CONFIG_SERIAL_MULTI
+ /*
+ * This was taken from common/cmd_nvedit.c.
+ * This will never work because serial_assign() returns
+ * 1 upon error, not -1.
+ * This would almost always return an error anyway because
+ * serial_assign() expects the name of a serial device, like
+ * serial_smc, but the user generally only wants to set serial.
+ */
+ if (serial_assign(start[j]) < 0)
+ continue;
+#endif
+ cons_set[cs_idx++] = dev;
+ }
+ free(console_args);
+ free(start);
+ /* failed to set any console */
+ if (cs_idx == 0) {
+ free(cons_set);
+ return 1;
+ } else {
+ /* Works even if console_devices[console] is NULL. */
+ console_devices[console] =
+ (struct stdio_dev **)realloc(console_devices[console],
+ cs_idx * sizeof(struct stdio_dev *));
+ if (console_devices[console] == NULL) {
+ free(cons_set);
+ return 1;
+ }
+ memcpy(console_devices[console], cons_set, cs_idx *
+ sizeof(struct stdio_dev *));
+
+ cd_count[console] = cs_idx;
+ }
+ free(cons_set);
+ return 0;
+}
+#endif /* CONFIG_CONSOLE_MUX */
diff --git a/u-boot/common/kallsyms.c b/u-boot/common/kallsyms.c
new file mode 100644
index 0000000..ce42a93
--- /dev/null
+++ b/u-boot/common/kallsyms.c
@@ -0,0 +1,44 @@
+/*
+ * Helper functions for working with the builtin symbol table
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+
+/* We need the weak marking as this symbol is provided specially */
+extern const char system_map[] __attribute__((weak));
+
+/* Given an address, return a pointer to the symbol name and store
+ * the base address in caddr. So if the symbol map had an entry:
+ * 03fb9b7c_spi_cs_deactivate
+ * Then the following call:
+ * unsigned long base;
+ * const char *sym = symbol_lookup(0x03fb9b80, &base);
+ * Would end up setting the variables like so:
+ * base = 0x03fb9b7c;
+ * sym = "_spi_cs_deactivate";
+ */
+const char *symbol_lookup(unsigned long addr, unsigned long *caddr)
+{
+ const char *sym, *csym;
+ char *esym;
+ unsigned long sym_addr;
+
+ sym = system_map;
+ csym = NULL;
+ *caddr = 0;
+
+ while (*sym) {
+ sym_addr = simple_strtoul(sym, &esym, 16);
+ sym = esym;
+ if (sym_addr > addr)
+ break;
+ *caddr = sym_addr;
+ csym = sym;
+ sym += strlen(sym) + 1;
+ }
+
+ return csym;
+}
diff --git a/u-boot/common/kgdb.c b/u-boot/common/kgdb.c
new file mode 100644
index 0000000..8a621ad
--- /dev/null
+++ b/u-boot/common/kgdb.c
@@ -0,0 +1,608 @@
+/* taken from arch/powerpc/kernel/ppc-stub.c */
+
+/****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or its performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <common.h>
+
+#include <kgdb.h>
+#include <command.h>
+
+#undef KGDB_DEBUG
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ */
+#define BUFMAX 1024
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char remcomRegBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active = 0, first_entry = 1;
+static struct pt_regs entry_regs;
+static long error_jmp_buf[BUFMAX/2];
+static int longjmp_on_fault = 0;
+#ifdef KGDB_DEBUG
+static int kdebug = 1;
+#endif
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null).
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+ char *tmp;
+ unsigned char ch;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory copy. Hex conversion will work against this one.
+ */
+ tmp = buf + count;
+ longjmp_on_fault = 1;
+
+ memcpy(tmp, mem, count);
+
+ while (count-- > 0) {
+ ch = *tmp++;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+ *buf = 0;
+ longjmp_on_fault = 0;
+ return (unsigned char *)buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte fetched from buf.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+ int hexValue;
+ char *tmp_raw, *tmp_hex;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory that is converted from hex.
+ */
+ tmp_raw = buf + count * 2;
+ tmp_hex = tmp_raw - 1;
+
+ longjmp_on_fault = 1;
+ while (tmp_hex >= buf) {
+ tmp_raw--;
+ hexValue = hex(*tmp_hex--);
+ if (hexValue < 0)
+ kgdb_error(KGDBERR_NOTHEXDIG);
+ *tmp_raw = hexValue;
+ hexValue = hex(*tmp_hex--);
+ if (hexValue < 0)
+ kgdb_error(KGDBERR_NOTHEXDIG);
+ *tmp_raw |= hexValue << 4;
+
+ }
+
+ memcpy(mem, tmp_raw, count);
+
+ kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
+ longjmp_on_fault = 0;
+
+ return buf;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ longjmp_on_fault = 1;
+ while (**ptr) {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+ longjmp_on_fault = 0;
+
+ return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum> */
+static void
+getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /* wait around for the start character, ignore all other
+ * characters */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') {
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ putc(ch);
+#endif
+ ;
+ }
+
+ checksum = 0;
+ xmitcsum = -1;
+
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+ if (checksum != xmitcsum)
+ putDebugChar('-'); /* failed checksum */
+ else {
+ putDebugChar('+'); /* successful transfer */
+ /* if a sequence char is present, reply the ID */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+ /* remove sequence chars from buffer */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ } while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer. */
+static void
+putpacket(unsigned char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch, recv;
+
+ /* $<packet info>#<checksum>. */
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count])) {
+ putDebugChar(ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+ recv = getDebugChar();
+ } while ((recv & 0x7f) != '+');
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static int
+handle_exception (struct pt_regs *regs)
+{
+ int addr;
+ int length;
+ char *ptr;
+ kgdb_data kd;
+ int i;
+
+ if (!initialized) {
+ printf("kgdb: exception before kgdb is initialized! huh?\n");
+ return (0);
+ }
+
+ /* probably should check which exception occured as well */
+ if (longjmp_on_fault) {
+ longjmp_on_fault = 0;
+ kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
+ panic("kgdb longjump failed!\n");
+ }
+
+ if (kgdb_active) {
+ printf("kgdb: unexpected exception from within kgdb\n");
+ return (0);
+ }
+ kgdb_active = 1;
+
+ kgdb_interruptible(0);
+
+ printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
+
+ if (kgdb_setjmp(error_jmp_buf) != 0)
+ panic("kgdb: error or fault in entry init!\n");
+
+ kgdb_enter(regs, &kd);
+
+ if (first_entry) {
+ /*
+ * the first time we enter kgdb, we save the processor
+ * state so that we can return to the monitor if the
+ * remote end quits gdb (or at least, tells us to quit
+ * with the 'k' packet)
+ */
+ entry_regs = *regs;
+ first_entry = 0;
+ }
+
+ ptr = remcomOutBuffer;
+
+ *ptr++ = 'T';
+
+ *ptr++ = hexchars[kd.sigval >> 4];
+ *ptr++ = hexchars[kd.sigval & 0xf];
+
+ for (i = 0; i < kd.nregs; i++) {
+ kgdb_reg *rp = &kd.regs[i];
+
+ *ptr++ = hexchars[rp->num >> 4];
+ *ptr++ = hexchars[rp->num & 0xf];
+ *ptr++ = ':';
+ ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
+ *ptr++ = ';';
+ }
+
+ *ptr = 0;
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+ putpacket((unsigned char *)&remcomOutBuffer);
+
+ while (1) {
+ volatile int errnum;
+
+ remcomOutBuffer[0] = 0;
+
+ getpacket(remcomInBuffer);
+ ptr = &remcomInBuffer[1];
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
+#endif
+
+ errnum = kgdb_setjmp(error_jmp_buf);
+
+ if (errnum == 0) switch (remcomInBuffer[0]) {
+
+ case '?': /* report most recent signal */
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
+ remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
+ remcomOutBuffer[3] = 0;
+ break;
+
+#ifdef KGDB_DEBUG
+ case 'd':
+ /* toggle debug flag */
+ kdebug ^= 1;
+ break;
+#endif
+
+ case 'g': /* return the value of the CPU registers. */
+ length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
+ mem2hex(remcomRegBuffer, remcomOutBuffer, length);
+ break;
+
+ case 'G': /* set the value of the CPU registers */
+ length = strlen(ptr);
+ if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
+ hex2mem(ptr, remcomRegBuffer, length/2);
+ kgdb_putregs(regs, remcomRegBuffer, length/2);
+ strcpy(remcomOutBuffer,"OK");
+ break;
+
+ case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ /* Try to read %x,%x. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ mem2hex((char *)addr, remcomOutBuffer, length);
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+
+ case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ /* Try to read '%x,%x:'. */
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ hex2mem(ptr, (char *)addr, length);
+ strcpy(remcomOutBuffer, "OK");
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+
+
+ case 'k': /* kill the program, actually return to monitor */
+ kd.extype = KGDBEXIT_KILL;
+ *regs = entry_regs;
+ first_entry = 1;
+ goto doexit;
+
+ case 'C': /* CSS continue with signal SS */
+ *ptr = '\0'; /* ignore the signal number for now */
+ /* fall through */
+
+ case 'c': /* cAA..AA Continue; address AA..AA optional */
+ /* try to read optional parameter, pc unchanged if no parm */
+ kd.extype = KGDBEXIT_CONTINUE;
+
+ if (hexToInt(&ptr, &addr)) {
+ kd.exaddr = addr;
+ kd.extype |= KGDBEXIT_WITHADDR;
+ }
+
+ goto doexit;
+
+ case 'S': /* SSS single step with signal SS */
+ *ptr = '\0'; /* ignore the signal number for now */
+ /* fall through */
+
+ case 's':
+ kd.extype = KGDBEXIT_SINGLE;
+
+ if (hexToInt(&ptr, &addr)) {
+ kd.exaddr = addr;
+ kd.extype |= KGDBEXIT_WITHADDR;
+ }
+
+ doexit:
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+ kgdb_flush_cache_all();
+ kgdb_exit(regs, &kd);
+ kgdb_active = 0;
+ kgdb_interruptible(1);
+ return (1);
+
+ case 'r': /* Reset (if user process..exit ???)*/
+ panic("kgdb reset.");
+ break;
+
+ case 'P': /* Pr=v set reg r to value v (r and v are hex) */
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == '='
+ && ((length = strlen(ptr)) & 1) == 0) {
+ hex2mem(ptr, remcomRegBuffer, length/2);
+ kgdb_putreg(regs, addr,
+ remcomRegBuffer, length/2);
+ strcpy(remcomOutBuffer,"OK");
+ } else {
+ kgdb_error(KGDBERR_BADPARAMS);
+ }
+ break;
+ } /* switch */
+
+ if (errnum != 0)
+ sprintf(remcomOutBuffer, "E%02d", errnum);
+
+#ifdef KGDB_DEBUG
+ if (kdebug)
+ printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
+#endif
+
+ /* reply to the request */
+ putpacket((unsigned char *)&remcomOutBuffer);
+
+ } /* while(1) */
+}
+
+/*
+ * kgdb_init must be called *after* the
+ * monitor is relocated into ram
+ */
+void
+kgdb_init(void)
+{
+ kgdb_serial_init();
+ debugger_exception_handler = handle_exception;
+ initialized = 1;
+
+ putDebugStr("kgdb ready\n");
+ puts("ready\n");
+}
+
+void
+kgdb_error(int errnum)
+{
+ longjmp_on_fault = 0;
+ kgdb_longjmp(error_jmp_buf, errnum);
+ panic("kgdb_error: longjmp failed!\n");
+}
+
+/* Output string in GDB O-packet format if GDB has connected. If nothing
+ output, returns 0 (caller must then handle output). */
+int
+kgdb_output_string (const char* s, unsigned int count)
+{
+ char buffer[512];
+
+ count = (count <= (sizeof(buffer) / 2 - 2))
+ ? count : (sizeof(buffer) / 2 - 2);
+
+ buffer[0] = 'O';
+ mem2hex ((char *)s, &buffer[1], count);
+ putpacket((unsigned char *)&buffer);
+
+ return 1;
+}
+
+void
+breakpoint(void)
+{
+ if (!initialized) {
+ printf("breakpoint() called b4 kgdb init\n");
+ return;
+ }
+
+ kgdb_breakpoint(0, 0);
+}
+
+int
+do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("Entering KGDB mode via exception handler...\n\n");
+ kgdb_breakpoint(argc - 1, argv + 1);
+ printf("\nReturned from KGDB mode\n");
+ return 0;
+}
+
+U_BOOT_CMD(
+ kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
+ "enter gdb remote debug mode",
+ "[arg0 arg1 .. argN]\n"
+ " - executes a breakpoint so that kgdb mode is\n"
+ " entered via the exception handler. To return\n"
+ " to the monitor, the remote gdb debugger must\n"
+ " execute a \"continue\" or \"quit\" command.\n"
+ "\n"
+ " if a program is loaded by the remote gdb, any args\n"
+ " passed to the kgdb command are given to the loaded\n"
+ " program if it is executed (see the \"hello_world\"\n"
+ " example program in the U-Boot examples directory)."
+);
diff --git a/u-boot/common/kgdb_stubs.c b/u-boot/common/kgdb_stubs.c
new file mode 100644
index 0000000..19b0c18
--- /dev/null
+++ b/u-boot/common/kgdb_stubs.c
@@ -0,0 +1,64 @@
+/*
+ * U-boot - stub functions for common kgdb code,
+ * can be overridden in board specific files
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <kgdb.h>
+
+int (*debugger_exception_handler)(struct pt_regs *);
+
+__attribute__((weak))
+void kgdb_serial_init(void)
+{
+ puts("[on serial] ");
+}
+
+__attribute__((weak))
+void putDebugChar(int c)
+{
+ serial_putc(c);
+}
+
+__attribute__((weak))
+void putDebugStr(const char *str)
+{
+#ifdef DEBUG
+ serial_puts(str);
+#endif
+}
+
+__attribute__((weak))
+int getDebugChar(void)
+{
+ return serial_getc();
+}
+
+__attribute__((weak))
+void kgdb_interruptible(int yes)
+{
+ return;
+}
+
+__attribute__((weak))
+void kgdb_flush_cache_range(void *from, void *to)
+{
+ flush_cache((unsigned long)from, (unsigned long)(to - from));
+}
+
+__attribute__((weak))
+void kgdb_flush_cache_all(void)
+{
+ if (dcache_status()) {
+ dcache_disable();
+ dcache_enable();
+ }
+ if (icache_status()) {
+ icache_disable();
+ icache_enable();
+ }
+}
diff --git a/u-boot/common/lcd.c b/u-boot/common/lcd.c
new file mode 100644
index 0000000..0555ab4
--- /dev/null
+++ b/u-boot/common/lcd.c
@@ -0,0 +1,855 @@
+/*
+ * Common LCD routines for supported CPUs
+ *
+ * (C) Copyright 2001-2002
+ * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
+ *
+ * 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
+ */
+
+/************************************************************************/
+/* ** HEADER FILES */
+/************************************************************************/
+
+/* #define DEBUG */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+#if defined(CONFIG_POST)
+#include <post.h>
+#endif
+#include <lcd.h>
+#include <watchdog.h>
+
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
+#include <asm/byteorder.h>
+#endif
+
+#if defined(CONFIG_MPC823)
+#include <lcdvideo.h>
+#endif
+
+#if defined(CONFIG_ATMEL_LCD)
+#include <atmel_lcdc.h>
+#endif
+
+/************************************************************************/
+/* ** FONT DATA */
+/************************************************************************/
+#include <video_font.h> /* Get font data, width and height */
+
+/************************************************************************/
+/* ** LOGO DATA */
+/************************************************************************/
+#ifdef CONFIG_LCD_LOGO
+# include <bmp_logo.h> /* Get logo data, width and height */
+# if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
+# error Default Color Map overlaps with Logo Color Map
+# endif
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+ulong lcd_setmem (ulong addr);
+
+static void lcd_drawchars (ushort x, ushort y, uchar *str, int count);
+static inline void lcd_puts_xy (ushort x, ushort y, uchar *s);
+static inline void lcd_putc_xy (ushort x, ushort y, uchar c);
+
+static int lcd_init (void *lcdbase);
+
+static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]);
+static void *lcd_logo (void);
+
+static int lcd_getbgcolor (void);
+static void lcd_setfgcolor (int color);
+static void lcd_setbgcolor (int color);
+
+char lcd_is_enabled = 0;
+
+#ifdef NOT_USED_SO_FAR
+static void lcd_getcolreg (ushort regno,
+ ushort *red, ushort *green, ushort *blue);
+static int lcd_getfgcolor (void);
+#endif /* NOT_USED_SO_FAR */
+
+/************************************************************************/
+
+/*----------------------------------------------------------------------*/
+
+static void console_scrollup (void)
+{
+ /* Copy up rows ignoring the first one */
+ memcpy (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE);
+
+ /* Clear the last one */
+ memset (CONSOLE_ROW_LAST, COLOR_MASK(lcd_color_bg), CONSOLE_ROW_SIZE);
+}
+
+/*----------------------------------------------------------------------*/
+
+static inline void console_back (void)
+{
+ if (--console_col < 0) {
+ console_col = CONSOLE_COLS-1 ;
+ if (--console_row < 0) {
+ console_row = 0;
+ }
+ }
+
+ lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT,
+ ' ');
+}
+
+/*----------------------------------------------------------------------*/
+
+static inline void console_newline (void)
+{
+ ++console_row;
+ console_col = 0;
+
+ /* Check if we need to scroll the terminal */
+ if (console_row >= CONSOLE_ROWS) {
+ /* Scroll everything up */
+ console_scrollup () ;
+ --console_row;
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+void lcd_putc (const char c)
+{
+ if (!lcd_is_enabled) {
+ serial_putc(c);
+ return;
+ }
+
+ switch (c) {
+ case '\r': console_col = 0;
+ return;
+
+ case '\n': console_newline();
+ return;
+
+ case '\t': /* Tab (8 chars alignment) */
+ console_col += 8;
+ console_col &= ~7;
+
+ if (console_col >= CONSOLE_COLS) {
+ console_newline();
+ }
+ return;
+
+ case '\b': console_back();
+ return;
+
+ default: lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT,
+ c);
+ if (++console_col >= CONSOLE_COLS) {
+ console_newline();
+ }
+ return;
+ }
+ /* NOTREACHED */
+}
+
+/*----------------------------------------------------------------------*/
+
+void lcd_puts (const char *s)
+{
+ if (!lcd_is_enabled) {
+ serial_puts (s);
+ return;
+ }
+
+ while (*s) {
+ lcd_putc (*s++);
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+void lcd_printf(const char *fmt, ...)
+{
+ va_list args;
+ char buf[CONFIG_SYS_PBSIZE];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ lcd_puts(buf);
+}
+
+/************************************************************************/
+/* ** Low-Level Graphics Routines */
+/************************************************************************/
+
+static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
+{
+ uchar *dest;
+ ushort off, row;
+
+ dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_BPP) / 8);
+ off = x * (1 << LCD_BPP) % 8;
+
+ for (row=0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
+ uchar *s = str;
+ int i;
+#if LCD_BPP == LCD_COLOR16
+ ushort *d = (ushort *)dest;
+#else
+ uchar *d = dest;
+#endif
+
+#if LCD_BPP == LCD_MONOCHROME
+ uchar rest = *d & -(1 << (8-off));
+ uchar sym;
+#endif
+ for (i=0; i<count; ++i) {
+ uchar c, bits;
+
+ c = *s++;
+ bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+
+#if LCD_BPP == LCD_MONOCHROME
+ sym = (COLOR_MASK(lcd_color_fg) & bits) |
+ (COLOR_MASK(lcd_color_bg) & ~bits);
+
+ *d++ = rest | (sym >> off);
+ rest = sym << (8-off);
+#elif LCD_BPP == LCD_COLOR8
+ for (c=0; c<8; ++c) {
+ *d++ = (bits & 0x80) ?
+ lcd_color_fg : lcd_color_bg;
+ bits <<= 1;
+ }
+#elif LCD_BPP == LCD_COLOR16
+ for (c=0; c<8; ++c) {
+ *d++ = (bits & 0x80) ?
+ lcd_color_fg : lcd_color_bg;
+ bits <<= 1;
+ }
+#endif
+ }
+#if LCD_BPP == LCD_MONOCHROME
+ *d = rest | (*d & ((1 << (8-off)) - 1));
+#endif
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+static inline void lcd_puts_xy (ushort x, ushort y, uchar *s)
+{
+#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
+ lcd_drawchars (x, y+BMP_LOGO_HEIGHT, s, strlen ((char *)s));
+#else
+ lcd_drawchars (x, y, s, strlen ((char *)s));
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+static inline void lcd_putc_xy (ushort x, ushort y, uchar c)
+{
+#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
+ lcd_drawchars (x, y+BMP_LOGO_HEIGHT, &c, 1);
+#else
+ lcd_drawchars (x, y, &c, 1);
+#endif
+}
+
+/************************************************************************/
+/** Small utility to check that you got the colours right */
+/************************************************************************/
+#ifdef LCD_TEST_PATTERN
+
+#define N_BLK_VERT 2
+#define N_BLK_HOR 3
+
+static int test_colors[N_BLK_HOR*N_BLK_VERT] = {
+ CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW,
+ CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN,
+};
+
+static void test_pattern (void)
+{
+ ushort v_max = panel_info.vl_row;
+ ushort h_max = panel_info.vl_col;
+ ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
+ ushort h_step = (h_max + N_BLK_HOR - 1) / N_BLK_HOR;
+ ushort v, h;
+ uchar *pix = (uchar *)lcd_base;
+
+ printf ("[LCD] Test Pattern: %d x %d [%d x %d]\n",
+ h_max, v_max, h_step, v_step);
+
+ /* WARNING: Code silently assumes 8bit/pixel */
+ for (v=0; v<v_max; ++v) {
+ uchar iy = v / v_step;
+ for (h=0; h<h_max; ++h) {
+ uchar ix = N_BLK_HOR * iy + (h/h_step);
+ *pix++ = test_colors[ix];
+ }
+ }
+}
+#endif /* LCD_TEST_PATTERN */
+
+
+/************************************************************************/
+/* ** GENERIC Initialization Routines */
+/************************************************************************/
+
+int drv_lcd_init (void)
+{
+ struct stdio_dev lcddev;
+ int rc;
+
+ lcd_base = (void *)(gd->fb_base);
+
+ lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+ lcd_init (lcd_base); /* LCD initialization */
+
+ /* Device initialization */
+ memset (&lcddev, 0, sizeof (lcddev));
+
+ strcpy (lcddev.name, "lcd");
+ lcddev.ext = 0; /* No extensions */
+ lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ lcddev.putc = lcd_putc; /* 'putc' function */
+ lcddev.puts = lcd_puts; /* 'puts' function */
+
+ rc = stdio_register (&lcddev);
+
+ return (rc == 0) ? 1 : rc;
+}
+
+/*----------------------------------------------------------------------*/
+static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+#if LCD_BPP == LCD_MONOCHROME
+ /* Setting the palette */
+ lcd_initcolregs();
+
+#elif LCD_BPP == LCD_COLOR8
+ /* Setting the palette */
+ lcd_setcolreg (CONSOLE_COLOR_BLACK, 0, 0, 0);
+ lcd_setcolreg (CONSOLE_COLOR_RED, 0xFF, 0, 0);
+ lcd_setcolreg (CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
+ lcd_setcolreg (CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
+ lcd_setcolreg (CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
+ lcd_setcolreg (CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
+ lcd_setcolreg (CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
+ lcd_setcolreg (CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
+ lcd_setcolreg (CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
+#endif
+
+#ifndef CONFIG_SYS_WHITE_ON_BLACK
+ lcd_setfgcolor (CONSOLE_COLOR_BLACK);
+ lcd_setbgcolor (CONSOLE_COLOR_WHITE);
+#else
+ lcd_setfgcolor (CONSOLE_COLOR_WHITE);
+ lcd_setbgcolor (CONSOLE_COLOR_BLACK);
+#endif /* CONFIG_SYS_WHITE_ON_BLACK */
+
+#ifdef LCD_TEST_PATTERN
+ test_pattern();
+#else
+ /* set framebuffer to background color */
+ memset ((char *)lcd_base,
+ COLOR_MASK(lcd_getbgcolor()),
+ lcd_line_length*panel_info.vl_row);
+#endif
+ /* Paint the logo and retrieve LCD base address */
+ debug ("[LCD] Drawing the logo...\n");
+ lcd_console_address = lcd_logo ();
+
+ console_col = 0;
+ console_row = 0;
+
+ return (0);
+}
+
+U_BOOT_CMD(
+ cls, 1, 1, lcd_clear,
+ "clear screen",
+ ""
+);
+
+/*----------------------------------------------------------------------*/
+
+static int lcd_init (void *lcdbase)
+{
+ /* Initialize the lcd controller */
+ debug ("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
+
+ lcd_ctrl_init (lcdbase);
+ lcd_is_enabled = 1;
+ lcd_clear (NULL, 1, 1, NULL); /* dummy args */
+ lcd_enable ();
+
+ /* Initialize the console */
+ console_col = 0;
+#ifdef CONFIG_LCD_INFO_BELOW_LOGO
+ console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;
+#else
+ console_row = 1; /* leave 1 blank line below logo */
+#endif
+
+ return 0;
+}
+
+
+/************************************************************************/
+/* ** ROM capable initialization part - needed to reserve FB memory */
+/************************************************************************/
+/*
+ * This is called early in the system initialization to grab memory
+ * for the LCD controller.
+ * Returns new address for monitor, after reserving LCD buffer memory
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong lcd_setmem (ulong addr)
+{
+ ulong size;
+ int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+ debug ("LCD panel info: %d x %d, %d bit/pix\n",
+ panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );
+
+ size = line_length * panel_info.vl_row;
+
+ /* Round up to nearest full page */
+ size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+
+ /* Allocate pages for the frame buffer. */
+ addr -= size;
+
+ debug ("Reserving %ldk for LCD Framebuffer at: %08lx\n", size>>10, addr);
+
+ return (addr);
+}
+
+/*----------------------------------------------------------------------*/
+
+static void lcd_setfgcolor (int color)
+{
+ lcd_color_fg = color;
+}
+
+/*----------------------------------------------------------------------*/
+
+static void lcd_setbgcolor (int color)
+{
+ lcd_color_bg = color;
+}
+
+/*----------------------------------------------------------------------*/
+
+#ifdef NOT_USED_SO_FAR
+static int lcd_getfgcolor (void)
+{
+ return lcd_color_fg;
+}
+#endif /* NOT_USED_SO_FAR */
+
+/*----------------------------------------------------------------------*/
+
+static int lcd_getbgcolor (void)
+{
+ return lcd_color_bg;
+}
+
+/*----------------------------------------------------------------------*/
+
+/************************************************************************/
+/* ** Chipset depending Bitmap / Logo stuff... */
+/************************************************************************/
+#ifdef CONFIG_LCD_LOGO
+void bitmap_plot (int x, int y)
+{
+#ifdef CONFIG_ATMEL_LCD
+ uint *cmap;
+#else
+ ushort *cmap;
+#endif
+ ushort i, j;
+ uchar *bmap;
+ uchar *fb;
+ ushort *fb16;
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
+ struct pxafb_info *fbi = &panel_info.pxa;
+#elif defined(CONFIG_MPC823)
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(immr->im_cpm);
+#endif
+
+ debug ("Logo: width %d height %d colors %d cmap %d\n",
+ BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS,
+ (int)(sizeof(bmp_logo_palette)/(sizeof(ushort))));
+
+ bmap = &bmp_logo_bitmap[0];
+ fb = (uchar *)(lcd_base + y * lcd_line_length + x);
+
+ if (NBITS(panel_info.vl_bpix) < 12) {
+ /* Leave room for default color map */
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
+ cmap = (ushort *)fbi->palette;
+#elif defined(CONFIG_MPC823)
+ cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET*sizeof(ushort)]);
+#elif defined(CONFIG_ATMEL_LCD)
+ cmap = (uint *) (panel_info.mmio + ATMEL_LCDC_LUT(0));
+#else
+ /*
+ * default case: generic system with no cmap (most likely 16bpp)
+ * We set cmap to the source palette, so no change is done.
+ * This avoids even more ifdef in the next stanza
+ */
+ cmap = bmp_logo_palette;
+#endif
+
+ WATCHDOG_RESET();
+
+ /* Set color map */
+ for (i=0; i<(sizeof(bmp_logo_palette)/(sizeof(ushort))); ++i) {
+ ushort colreg = bmp_logo_palette[i];
+#ifdef CONFIG_ATMEL_LCD
+ uint lut_entry;
+#ifdef CONFIG_ATMEL_LCD_BGR555
+ lut_entry = ((colreg & 0x000F) << 11) |
+ ((colreg & 0x00F0) << 2) |
+ ((colreg & 0x0F00) >> 7);
+#else /* CONFIG_ATMEL_LCD_RGB565 */
+ lut_entry = ((colreg & 0x000F) << 1) |
+ ((colreg & 0x00F0) << 3) |
+ ((colreg & 0x0F00) << 4);
+#endif
+ *(cmap + BMP_LOGO_OFFSET) = lut_entry;
+ cmap++;
+#else /* !CONFIG_ATMEL_LCD */
+#ifdef CONFIG_SYS_INVERT_COLORS
+ *cmap++ = 0xffff - colreg;
+#else
+ *cmap++ = colreg;
+#endif
+#endif /* CONFIG_ATMEL_LCD */
+ }
+
+ WATCHDOG_RESET();
+
+ for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
+ memcpy (fb, bmap, BMP_LOGO_WIDTH);
+ bmap += BMP_LOGO_WIDTH;
+ fb += panel_info.vl_col;
+ }
+ }
+ else { /* true color mode */
+ u16 col16;
+ fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
+ for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
+ for (j=0; j<BMP_LOGO_WIDTH; j++) {
+ col16 = bmp_logo_palette[(bmap[j]-16)];
+ fb16[j] =
+ ((col16 & 0x000F) << 1) |
+ ((col16 & 0x00F0) << 3) |
+ ((col16 & 0x0F00) << 4);
+ }
+ bmap += BMP_LOGO_WIDTH;
+ fb16 += panel_info.vl_col;
+ }
+ }
+
+ WATCHDOG_RESET();
+}
+#endif /* CONFIG_LCD_LOGO */
+
+/*----------------------------------------------------------------------*/
+#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
+/*
+ * Display the BMP file located at address bmp_image.
+ * Only uncompressed.
+ */
+
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+#define BMP_ALIGN_CENTER 0x7FFF
+#endif
+
+int lcd_display_bitmap(ulong bmp_image, int x, int y)
+{
+#if !defined(CONFIG_MCC200)
+ ushort *cmap = NULL;
+#endif
+ ushort *cmap_base = NULL;
+ ushort i, j;
+ uchar *fb;
+ bmp_image_t *bmp=(bmp_image_t *)bmp_image;
+ uchar *bmap;
+ ushort padded_line;
+ unsigned long width, height, byte_width;
+ unsigned long pwidth = panel_info.vl_col;
+ unsigned colors, bpix, bmp_bpix;
+ unsigned long compression;
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
+ struct pxafb_info *fbi = &panel_info.pxa;
+#elif defined(CONFIG_MPC823)
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(immr->im_cpm);
+#endif
+
+ if (!((bmp->header.signature[0]=='B') &&
+ (bmp->header.signature[1]=='M'))) {
+ printf ("Error: no valid bmp image at %lx\n", bmp_image);
+ return 1;
+ }
+
+ width = le32_to_cpu (bmp->header.width);
+ height = le32_to_cpu (bmp->header.height);
+ bmp_bpix = le16_to_cpu(bmp->header.bit_count);
+ colors = 1 << bmp_bpix;
+ compression = le32_to_cpu (bmp->header.compression);
+
+ bpix = NBITS(panel_info.vl_bpix);
+
+ if ((bpix != 1) && (bpix != 8) && (bpix != 16)) {
+ printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix, bmp_bpix);
+ return 1;
+ }
+
+ /* We support displaying 8bpp BMPs on 16bpp LCDs */
+ if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16)) {
+ printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+ bpix,
+ le16_to_cpu(bmp->header.bit_count));
+ return 1;
+ }
+
+ debug ("Display-bmp: %d x %d with %d colors\n",
+ (int)width, (int)height, (int)colors);
+
+#if !defined(CONFIG_MCC200)
+ /* MCC200 LCD doesn't need CMAP, supports 1bpp b&w only */
+ if (bmp_bpix == 8) {
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
+ cmap = (ushort *)fbi->palette;
+#elif defined(CONFIG_MPC823)
+ cmap = (ushort *)&(cp->lcd_cmap[255*sizeof(ushort)]);
+#elif !defined(CONFIG_ATMEL_LCD)
+ cmap = panel_info.cmap;
+#endif
+
+ cmap_base = cmap;
+
+ /* Set color map */
+ for (i=0; i<colors; ++i) {
+ bmp_color_table_entry_t cte = bmp->color_table[i];
+#if !defined(CONFIG_ATMEL_LCD)
+ ushort colreg =
+ ( ((cte.red) << 8) & 0xf800) |
+ ( ((cte.green) << 3) & 0x07e0) |
+ ( ((cte.blue) >> 3) & 0x001f) ;
+#ifdef CONFIG_SYS_INVERT_COLORS
+ *cmap = 0xffff - colreg;
+#else
+ *cmap = colreg;
+#endif
+#if defined(CONFIG_MPC823)
+ cmap--;
+#else
+ cmap++;
+#endif
+#else /* CONFIG_ATMEL_LCD */
+ lcd_setcolreg(i, cte.red, cte.green, cte.blue);
+#endif
+ }
+ }
+#endif
+
+ /*
+ * BMP format for Monochrome assumes that the state of a
+ * pixel is described on a per Bit basis, not per Byte.
+ * So, in case of Monochrome BMP we should align widths
+ * on a byte boundary and convert them from Bit to Byte
+ * units.
+ * Probably, PXA250 and MPC823 process 1bpp BMP images in
+ * their own ways, so make the converting to be MCC200
+ * specific.
+ */
+#if defined(CONFIG_MCC200)
+ if (bpix==1)
+ {
+ width = ((width + 7) & ~7) >> 3;
+ x = ((x + 7) & ~7) >> 3;
+ pwidth= ((pwidth + 7) & ~7) >> 3;
+ }
+#endif
+
+ padded_line = (width&0x3) ? ((width&~0x3)+4) : (width);
+
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+ if (x == BMP_ALIGN_CENTER)
+ x = max(0, (pwidth - width) / 2);
+ else if (x < 0)
+ x = max(0, pwidth - width + x + 1);
+
+ if (y == BMP_ALIGN_CENTER)
+ y = max(0, (panel_info.vl_row - height) / 2);
+ else if (y < 0)
+ y = max(0, panel_info.vl_row - height + y + 1);
+#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
+
+ if ((x + width)>pwidth)
+ width = pwidth - x;
+ if ((y + height)>panel_info.vl_row)
+ height = panel_info.vl_row - y;
+
+ bmap = (uchar *)bmp + le32_to_cpu (bmp->header.data_offset);
+ fb = (uchar *) (lcd_base +
+ (y + height - 1) * lcd_line_length + x * bpix / 8);
+
+ switch (bmp_bpix) {
+ case 1: /* pass through */
+ case 8:
+ if (bpix != 16)
+ byte_width = width;
+ else
+ byte_width = width * 2;
+
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ if (bpix != 16) {
+#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS || defined(CONFIG_ATMEL_LCD)
+ *(fb++) = *(bmap++);
+#elif defined(CONFIG_MPC823) || defined(CONFIG_MCC200)
+ *(fb++) = 255 - *(bmap++);
+#endif
+ } else {
+ *(uint16_t *)fb = cmap_base[*(bmap++)];
+ fb += sizeof(uint16_t) / sizeof(*fb);
+ }
+ }
+ bmap += (width - padded_line);
+ fb -= (byte_width + lcd_line_length);
+ }
+ break;
+
+#if defined(CONFIG_BMP_16BPP)
+ case 16:
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+#if defined(CONFIG_ATMEL_LCD_BGR555)
+ *(fb++) = ((bmap[0] & 0x1f) << 2) |
+ (bmap[1] & 0x03);
+ *(fb++) = (bmap[0] & 0xe0) |
+ ((bmap[1] & 0x7c) >> 2);
+ bmap += 2;
+#else
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+#endif
+ }
+ bmap += (padded_line - width) * 2;
+ fb -= (width * 2 + lcd_line_length);
+ }
+ break;
+#endif /* CONFIG_BMP_16BPP */
+
+ default:
+ break;
+ };
+
+ return (0);
+}
+#endif
+
+static void *lcd_logo (void)
+{
+#ifdef CONFIG_SPLASH_SCREEN
+ char *s;
+ ulong addr;
+ static int do_splash = 1;
+
+ if (do_splash && (s = getenv("splashimage")) != NULL) {
+ int x = 0, y = 0;
+ do_splash = 0;
+
+ addr = simple_strtoul (s, NULL, 16);
+#ifdef CONFIG_SPLASH_SCREEN_ALIGN
+ if ((s = getenv ("splashpos")) != NULL) {
+ if (s[0] == 'm')
+ x = BMP_ALIGN_CENTER;
+ else
+ x = simple_strtol (s, NULL, 0);
+
+ if ((s = strchr (s + 1, ',')) != NULL) {
+ if (s[1] == 'm')
+ y = BMP_ALIGN_CENTER;
+ else
+ y = simple_strtol (s + 1, NULL, 0);
+ }
+ }
+#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
+
+#ifdef CONFIG_VIDEO_BMP_GZIP
+ bmp_image_t *bmp = (bmp_image_t *)addr;
+ unsigned long len;
+
+ if (!((bmp->header.signature[0]=='B') &&
+ (bmp->header.signature[1]=='M'))) {
+ addr = (ulong)gunzip_bmp(addr, &len);
+ }
+#endif
+
+ if (lcd_display_bitmap (addr, x, y) == 0) {
+ return ((void *)lcd_base);
+ }
+ }
+#endif /* CONFIG_SPLASH_SCREEN */
+
+#ifdef CONFIG_LCD_LOGO
+ bitmap_plot (0, 0);
+#endif /* CONFIG_LCD_LOGO */
+
+#ifdef CONFIG_LCD_INFO
+ console_col = LCD_INFO_X / VIDEO_FONT_WIDTH;
+ console_row = LCD_INFO_Y / VIDEO_FONT_HEIGHT;
+ lcd_show_board_info();
+#endif /* CONFIG_LCD_INFO */
+
+#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
+ return ((void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length));
+#else
+ return ((void *)lcd_base);
+#endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */
+}
+
+/************************************************************************/
+/************************************************************************/
diff --git a/u-boot/common/lynxkdi.c b/u-boot/common/lynxkdi.c
new file mode 100644
index 0000000..b23135b
--- /dev/null
+++ b/u-boot/common/lynxkdi.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) Orbacom Systems, Inc <www.orbacom.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <image.h>
+#include <net.h>
+
+#include <lynxkdi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_MPC8260) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+void lynxkdi_boot (image_header_t *hdr)
+{
+ void (*lynxkdi)(void) = (void(*)(void))image_get_ep (hdr);
+ lynxos_bootparms_t *parms = (lynxos_bootparms_t *)0x0020;
+ bd_t *kbd;
+ u32 *psz = (u32 *)(image_get_load (hdr) + 0x0204);
+
+ memset (parms, 0, sizeof(*parms));
+ kbd = gd->bd;
+ parms->clock_ref = kbd->bi_busfreq;
+ parms->dramsz = kbd->bi_memsize;
+ eth_getenv_enetaddr("ethaddr", parms->ethaddr);
+ mtspr (SPRN_SPRG2, 0x0020);
+
+ /* Do a simple check for Bluecat so we can pass the
+ * kernel command line parameters.
+ */
+ if (le32_to_cpu (*psz) == image_get_data_size (hdr)) { /* FIXME: NOT SURE HERE ! */
+ char *args;
+ char *cmdline = (char *)(image_get_load (hdr) + 0x020c);
+ int len;
+
+ printf ("Booting Bluecat KDI ...\n");
+ udelay (200*1000); /* Allow serial port to flush */
+ if ((args = getenv ("bootargs")) == NULL)
+ args = "";
+ /* Prepend the cmdline */
+ len = strlen (args);
+ if (len && (len + strlen (cmdline) + 2 < (0x0400 - 0x020c))) {
+ memmove (cmdline + strlen (args) + 1, cmdline, strlen (cmdline));
+ strcpy (cmdline, args);
+ cmdline[len] = ' ';
+ }
+ }
+ else {
+ printf ("Booting LynxOS KDI ...\n");
+ }
+
+ lynxkdi ();
+}
+#else
+#error "Lynx KDI support not implemented for configured CPU"
+#endif
diff --git a/u-boot/common/main.c b/u-boot/common/main.c
new file mode 100644
index 0000000..dcbacc9
--- /dev/null
+++ b/u-boot/common/main.c
@@ -0,0 +1,1427 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#ifdef CONFIG_MODEM_SUPPORT
+#include <malloc.h> /* for free() prototype */
+#endif
+
+#ifdef CONFIG_SYS_HUSH_PARSER
+#include <hush.h>
+#endif
+
+#include <post.h>
+
+#if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Board-specific Platform code can reimplement show_boot_progress () if needed
+ */
+void inline __show_boot_progress (int val) {}
+void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
+
+#if defined(CONFIG_UPDATE_TFTP)
+void update_tftp (void);
+#endif /* CONFIG_UPDATE_TFTP */
+
+#define MAX_DELAY_STOP_STR 32
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+static int abortboot(int);
+#endif
+
+#undef DEBUG_PARSER
+
+char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
+static const char erase_seq[] = "\b \b"; /* erase sequence */
+static const char tab_seq[] = " "; /* used to expand TABs */
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+static uint64_t endtime = 0; /* must be set, default is instant timeout */
+static int retry_time = -1; /* -1 so can call readline before main_loop */
+#endif
+
+#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
+
+#ifndef CONFIG_BOOT_RETRY_MIN
+#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
+#endif
+
+#ifdef CONFIG_MODEM_SUPPORT
+int do_mdm_init = 0;
+extern void mdm_init(void); /* defined in board.c */
+#endif
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
+ * returns: 0 - no key string, allow autoboot
+ * 1 - got key string, abort
+ */
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+# if defined(CONFIG_AUTOBOOT_KEYED)
+static __inline__ int abortboot(int bootdelay)
+{
+ int abort = 0;
+ uint64_t etime = endtick(bootdelay);
+ struct {
+ char* str;
+ u_int len;
+ int retry;
+ }
+ delaykey [] = {
+ { str: getenv ("bootdelaykey"), retry: 1 },
+ { str: getenv ("bootdelaykey2"), retry: 1 },
+ { str: getenv ("bootstopkey"), retry: 0 },
+ { str: getenv ("bootstopkey2"), retry: 0 },
+ };
+
+ char presskey [MAX_DELAY_STOP_STR];
+ u_int presskey_len = 0;
+ u_int presskey_max = 0;
+ u_int i;
+
+# ifdef CONFIG_AUTOBOOT_PROMPT
+ printf(CONFIG_AUTOBOOT_PROMPT);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_DELAY_STR
+ if (delaykey[0].str == NULL)
+ delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
+# endif
+# ifdef CONFIG_AUTOBOOT_DELAY_STR2
+ if (delaykey[1].str == NULL)
+ delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
+# endif
+# ifdef CONFIG_AUTOBOOT_STOP_STR
+ if (delaykey[2].str == NULL)
+ delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
+# endif
+# ifdef CONFIG_AUTOBOOT_STOP_STR2
+ if (delaykey[3].str == NULL)
+ delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
+# endif
+
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+ delaykey[i].len = delaykey[i].str == NULL ?
+ 0 : strlen (delaykey[i].str);
+ delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
+ MAX_DELAY_STOP_STR : delaykey[i].len;
+
+ presskey_max = presskey_max > delaykey[i].len ?
+ presskey_max : delaykey[i].len;
+
+# if DEBUG_BOOTKEYS
+ printf("%s key:<%s>\n",
+ delaykey[i].retry ? "delay" : "stop",
+ delaykey[i].str ? delaykey[i].str : "NULL");
+# endif
+ }
+
+ /* In order to keep up with incoming data, check timeout only
+ * when catch up.
+ */
+ do {
+ if (tstc()) {
+ if (presskey_len < presskey_max) {
+ presskey [presskey_len ++] = getc();
+ }
+ else {
+ for (i = 0; i < presskey_max - 1; i ++)
+ presskey [i] = presskey [i + 1];
+
+ presskey [i] = getc();
+ }
+ }
+
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+ if (delaykey[i].len > 0 &&
+ presskey_len >= delaykey[i].len &&
+ memcmp (presskey + presskey_len - delaykey[i].len,
+ delaykey[i].str,
+ delaykey[i].len) == 0) {
+# if DEBUG_BOOTKEYS
+ printf("got %skey\n",
+ delaykey[i].retry ? "delay" : "stop");
+# endif
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+ /* don't retry auto boot */
+ if (! delaykey[i].retry)
+ retry_time = -1;
+# endif
+ abort = 1;
+ }
+ }
+ } while (!abort && get_ticks() <= etime);
+
+# if DEBUG_BOOTKEYS
+ if (!abort)
+ puts("key timeout\n");
+# endif
+
+#ifdef CONFIG_SILENT_CONSOLE
+ if (abort)
+ gd->flags &= ~GD_FLG_SILENT;
+#endif
+
+ return abort;
+}
+
+# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
+
+#ifdef CONFIG_MENUKEY
+static int menukey = 0;
+#endif
+
+static __inline__ int abortboot(int bootdelay)
+{
+ int abort = 0;
+
+#ifdef CONFIG_MENUPROMPT
+ printf(CONFIG_MENUPROMPT);
+#else
+ printf("Hit any key to stop autoboot: %2d ", bootdelay);
+#endif
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+ /*
+ * Check if key already pressed
+ * Don't check if bootdelay < 0
+ */
+ if (bootdelay >= 0) {
+ if (tstc()) { /* we got a key press */
+ (void) getc(); /* consume input */
+ puts ("\b\b\b 0");
+ abort = 1; /* don't auto boot */
+ }
+ }
+#endif
+
+ while ((bootdelay > 0) && (!abort)) {
+ int i;
+
+ --bootdelay;
+ /* delay 100 * 10ms */
+ for (i=0; !abort && i<100; ++i) {
+ if (tstc()) { /* we got a key press */
+ abort = 1; /* don't auto boot */
+ bootdelay = 0; /* no more delay */
+# ifdef CONFIG_MENUKEY
+ menukey = getc();
+# else
+ (void) getc(); /* consume input */
+# endif
+ break;
+ }
+ udelay(10000);
+ }
+
+ printf("\b\b\b%2d ", bootdelay);
+ }
+
+ putc('\n');
+
+#ifdef CONFIG_SILENT_CONSOLE
+ if (abort)
+ gd->flags &= ~GD_FLG_SILENT;
+#endif
+
+ return abort;
+}
+# endif /* CONFIG_AUTOBOOT_KEYED */
+#endif /* CONFIG_BOOTDELAY >= 0 */
+
+/****************************************************************************/
+
+void main_loop (void)
+{
+#ifndef CONFIG_SYS_HUSH_PARSER
+ static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
+ int len;
+ int rc = 1;
+ int flag;
+#endif
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ char *s;
+ int bootdelay;
+#endif
+#ifdef CONFIG_PREBOOT
+ char *p;
+#endif
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+ unsigned long bootcount = 0;
+ unsigned long bootlimit = 0;
+ char *bcs;
+ char bcs_set[16];
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
+
+#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
+ ulong bmp = 0; /* default bitmap */
+ extern int trab_vfd (ulong bitmap);
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (do_mdm_init)
+ bmp = 1; /* alternate bitmap */
+#endif
+ trab_vfd (bmp);
+#endif /* CONFIG_VFD && VFD_TEST_LOGO */
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+ bootcount = bootcount_load();
+ bootcount++;
+ bootcount_store (bootcount);
+ sprintf (bcs_set, "%lu", bootcount);
+ setenv ("bootcount", bcs_set);
+ bcs = getenv ("bootlimit");
+ bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
+
+#ifdef CONFIG_MODEM_SUPPORT
+ debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
+ if (do_mdm_init) {
+ char *str = strdup(getenv("mdm_cmd"));
+ setenv ("preboot", str); /* set or delete definition */
+ if (str != NULL)
+ free (str);
+ mdm_init(); /* wait for modem connection */
+ }
+#endif /* CONFIG_MODEM_SUPPORT */
+
+#ifdef CONFIG_VERSION_VARIABLE
+ {
+ extern char version_string[];
+
+ setenv ("ver", version_string); /* set version variable */
+ }
+#endif /* CONFIG_VERSION_VARIABLE */
+
+#ifdef CONFIG_SYS_HUSH_PARSER
+ u_boot_hush_start ();
+#endif
+
+#if defined(CONFIG_HUSH_INIT_VAR)
+ hush_init_var ();
+#endif
+
+#ifdef CONFIG_PREBOOT
+ if ((p = getenv ("preboot")) != NULL) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+ int prev = disable_ctrlc(1); /* disable Control C checking */
+# endif
+
+# ifndef CONFIG_SYS_HUSH_PARSER
+ run_command (p, 0);
+# else
+ parse_string_outer(p, FLAG_PARSE_SEMICOLON |
+ FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+ disable_ctrlc(prev); /* restore Control C checking */
+# endif
+ }
+#endif /* CONFIG_PREBOOT */
+
+#if defined(CONFIG_UPDATE_TFTP)
+ update_tftp ();
+#endif /* CONFIG_UPDATE_TFTP */
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ s = getenv ("bootdelay");
+ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+
+ debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+ init_cmd_timeout ();
+# endif /* CONFIG_BOOT_RETRY_TIME */
+
+#ifdef CONFIG_POST
+ if (gd->flags & GD_FLG_POSTFAIL) {
+ s = getenv("failbootcmd");
+ }
+ else
+#endif /* CONFIG_POST */
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+ if (bootlimit && (bootcount > bootlimit)) {
+ printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
+ (unsigned)bootlimit);
+ s = getenv ("altbootcmd");
+ }
+ else
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
+ s = getenv ("bootcmd");
+
+ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
+
+ if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+ int prev = disable_ctrlc(1); /* disable Control C checking */
+# endif
+
+# ifndef CONFIG_SYS_HUSH_PARSER
+ run_command (s, 0);
+# else
+ parse_string_outer(s, FLAG_PARSE_SEMICOLON |
+ FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+ disable_ctrlc(prev); /* restore Control C checking */
+# endif
+ }
+
+# ifdef CONFIG_MENUKEY
+ if (menukey == CONFIG_MENUKEY) {
+ s = getenv("menucmd");
+ if (s) {
+# ifndef CONFIG_SYS_HUSH_PARSER
+ run_command (s, 0);
+# else
+ parse_string_outer(s, FLAG_PARSE_SEMICOLON |
+ FLAG_EXIT_FROM_LOOP);
+# endif
+ }
+ }
+#endif /* CONFIG_MENUKEY */
+#endif /* CONFIG_BOOTDELAY */
+
+ /*
+ * Main Loop for Monitor Command Processing
+ */
+#ifdef CONFIG_SYS_HUSH_PARSER
+ parse_file_outer();
+ /* This point is never reached */
+ for (;;);
+#else
+ for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ if (rc >= 0) {
+ /* Saw enough of a valid command to
+ * restart the timeout.
+ */
+ reset_cmd_timeout();
+ }
+#endif
+ len = readline (CONFIG_SYS_PROMPT);
+
+ flag = 0; /* assume no special flags for now */
+ if (len > 0)
+ strcpy (lastcommand, console_buffer);
+ else if (len == 0)
+ flag |= CMD_FLAG_REPEAT;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (len == -2) {
+ /* -2 means timed out, retry autoboot
+ */
+ puts ("\nTimed out waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ /* Reinit board to run initialization code again */
+ do_reset (NULL, 0, 0, NULL);
+# else
+ return; /* retry autoboot */
+# endif
+ }
+#endif
+
+ if (len == -1)
+ puts ("<INTERRUPT>\n");
+ else
+ rc = run_command (lastcommand, flag);
+
+ if (rc <= 0) {
+ /* invalid command or not repeatable, forget it */
+ lastcommand[0] = 0;
+ }
+ }
+#endif /*CONFIG_SYS_HUSH_PARSER*/
+}
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+/***************************************************************************
+ * initialize command line timeout
+ */
+void init_cmd_timeout(void)
+{
+ char *s = getenv ("bootretry");
+
+ if (s != NULL)
+ retry_time = (int)simple_strtol(s, NULL, 10);
+ else
+ retry_time = CONFIG_BOOT_RETRY_TIME;
+
+ if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
+ retry_time = CONFIG_BOOT_RETRY_MIN;
+}
+
+/***************************************************************************
+ * reset command line timeout to retry_time seconds
+ */
+void reset_cmd_timeout(void)
+{
+ endtime = endtick(retry_time);
+}
+#endif
+
+#ifdef CONFIG_CMDLINE_EDITING
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+#define putnstr(str,n) do { \
+ printf ("%.*s", (int)n, str); \
+ } while (0)
+
+#define CTL_CH(c) ((c) - 'a' + 1)
+#define CTL_BACKSPACE ('\b')
+#define DEL ((char)255)
+#define DEL7 ((char)127)
+#define CREAD_HIST_CHAR ('!')
+
+#define getcmd_putch(ch) putc(ch)
+#define getcmd_getch() getc()
+#define getcmd_cbeep() getcmd_putch('\a')
+
+#define HIST_MAX 20
+#define HIST_SIZE CONFIG_SYS_CBSIZE
+
+static int hist_max = 0;
+static int hist_add_idx = 0;
+static int hist_cur = -1;
+unsigned hist_num = 0;
+
+char* hist_list[HIST_MAX];
+char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
+
+#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
+
+static void hist_init(void)
+{
+ int i;
+
+ hist_max = 0;
+ hist_add_idx = 0;
+ hist_cur = -1;
+ hist_num = 0;
+
+ for (i = 0; i < HIST_MAX; i++) {
+ hist_list[i] = hist_lines[i];
+ hist_list[i][0] = '\0';
+ }
+}
+
+static void cread_add_to_hist(char *line)
+{
+ strcpy(hist_list[hist_add_idx], line);
+
+ if (++hist_add_idx >= HIST_MAX)
+ hist_add_idx = 0;
+
+ if (hist_add_idx > hist_max)
+ hist_max = hist_add_idx;
+
+ hist_num++;
+}
+
+static char* hist_prev(void)
+{
+ char *ret;
+ int old_cur;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ old_cur = hist_cur;
+ if (--hist_cur < 0)
+ hist_cur = hist_max;
+
+ if (hist_cur == hist_add_idx) {
+ hist_cur = old_cur;
+ ret = NULL;
+ } else
+ ret = hist_list[hist_cur];
+
+ return (ret);
+}
+
+static char* hist_next(void)
+{
+ char *ret;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ if (hist_cur == hist_add_idx)
+ return NULL;
+
+ if (++hist_cur > hist_max)
+ hist_cur = 0;
+
+ if (hist_cur == hist_add_idx) {
+ ret = "";
+ } else
+ ret = hist_list[hist_cur];
+
+ return (ret);
+}
+
+#ifndef CONFIG_CMDLINE_EDITING
+static void cread_print_hist_list(void)
+{
+ int i;
+ unsigned long n;
+
+ n = hist_num - hist_max;
+
+ i = hist_add_idx + 1;
+ while (1) {
+ if (i > hist_max)
+ i = 0;
+ if (i == hist_add_idx)
+ break;
+ printf("%s\n", hist_list[i]);
+ n++;
+ i++;
+ }
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+#define BEGINNING_OF_LINE() { \
+ while (num) { \
+ getcmd_putch(CTL_BACKSPACE); \
+ num--; \
+ } \
+}
+
+#define ERASE_TO_EOL() { \
+ if (num < eol_num) { \
+ printf("%*s", (int)(eol_num - num), ""); \
+ do { \
+ getcmd_putch(CTL_BACKSPACE); \
+ } while (--eol_num > num); \
+ } \
+}
+
+#define REFRESH_TO_EOL() { \
+ if (num < eol_num) { \
+ wlen = eol_num - num; \
+ putnstr(buf + num, wlen); \
+ num = eol_num; \
+ } \
+}
+
+static void cread_add_char(char ichar, int insert, unsigned long *num,
+ unsigned long *eol_num, char *buf, unsigned long len)
+{
+ unsigned long wlen;
+
+ /* room ??? */
+ if (insert || *num == *eol_num) {
+ if (*eol_num > len - 1) {
+ getcmd_cbeep();
+ return;
+ }
+ (*eol_num)++;
+ }
+
+ if (insert) {
+ wlen = *eol_num - *num;
+ if (wlen > 1) {
+ memmove(&buf[*num+1], &buf[*num], wlen-1);
+ }
+
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ while (--wlen) {
+ getcmd_putch(CTL_BACKSPACE);
+ }
+ } else {
+ /* echo the character */
+ wlen = 1;
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ }
+}
+
+static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
+ unsigned long *eol_num, char *buf, unsigned long len)
+{
+ while (strsize--) {
+ cread_add_char(*str, insert, num, eol_num, buf, len);
+ str++;
+ }
+}
+
+static int cread_line(const char *const prompt, char *buf, unsigned int *len)
+{
+ unsigned long num = 0;
+ unsigned long eol_num = 0;
+ unsigned long wlen;
+ char ichar;
+ int insert = 1;
+ int esc_len = 0;
+ char esc_save[8];
+ int init_len = strlen(buf);
+
+ if (init_len)
+ cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
+
+ while (1) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ while (!tstc()) { /* while no incoming data */
+ if (retry_time >= 0 && get_ticks() > endtime)
+ return (-2); /* timed out */
+ WATCHDOG_RESET();
+ }
+#endif
+
+ ichar = getcmd_getch();
+
+ if ((ichar == '\n') || (ichar == '\r')) {
+ putc('\n');
+ break;
+ }
+
+ /*
+ * handle standard linux xterm esc sequences for arrow key, etc.
+ */
+ if (esc_len != 0) {
+ if (esc_len == 1) {
+ if (ichar == '[') {
+ esc_save[esc_len] = ichar;
+ esc_len = 2;
+ } else {
+ cread_add_str(esc_save, esc_len, insert,
+ &num, &eol_num, buf, *len);
+ esc_len = 0;
+ }
+ continue;
+ }
+
+ switch (ichar) {
+
+ case 'D': /* <- key */
+ ichar = CTL_CH('b');
+ esc_len = 0;
+ break;
+ case 'C': /* -> key */
+ ichar = CTL_CH('f');
+ esc_len = 0;
+ break; /* pass off to ^F handler */
+ case 'H': /* Home key */
+ ichar = CTL_CH('a');
+ esc_len = 0;
+ break; /* pass off to ^A handler */
+ case 'A': /* up arrow */
+ ichar = CTL_CH('p');
+ esc_len = 0;
+ break; /* pass off to ^P handler */
+ case 'B': /* down arrow */
+ ichar = CTL_CH('n');
+ esc_len = 0;
+ break; /* pass off to ^N handler */
+ default:
+ esc_save[esc_len++] = ichar;
+ cread_add_str(esc_save, esc_len, insert,
+ &num, &eol_num, buf, *len);
+ esc_len = 0;
+ continue;
+ }
+ }
+
+ switch (ichar) {
+ case 0x1b:
+ if (esc_len == 0) {
+ esc_save[esc_len] = ichar;
+ esc_len = 1;
+ } else {
+ puts("impossible condition #876\n");
+ esc_len = 0;
+ }
+ break;
+
+ case CTL_CH('a'):
+ BEGINNING_OF_LINE();
+ break;
+ case CTL_CH('c'): /* ^C - break */
+ *buf = '\0'; /* discard input */
+ return (-1);
+ case CTL_CH('f'):
+ if (num < eol_num) {
+ getcmd_putch(buf[num]);
+ num++;
+ }
+ break;
+ case CTL_CH('b'):
+ if (num) {
+ getcmd_putch(CTL_BACKSPACE);
+ num--;
+ }
+ break;
+ case CTL_CH('d'):
+ if (num < eol_num) {
+ wlen = eol_num - num - 1;
+ if (wlen) {
+ memmove(&buf[num], &buf[num+1], wlen);
+ putnstr(buf + num, wlen);
+ }
+
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('k'):
+ ERASE_TO_EOL();
+ break;
+ case CTL_CH('e'):
+ REFRESH_TO_EOL();
+ break;
+ case CTL_CH('o'):
+ insert = !insert;
+ break;
+ case CTL_CH('x'):
+ case CTL_CH('u'):
+ BEGINNING_OF_LINE();
+ ERASE_TO_EOL();
+ break;
+ case DEL:
+ case DEL7:
+ case 8:
+ if (num) {
+ wlen = eol_num - num;
+ num--;
+ memmove(&buf[num], &buf[num+1], wlen);
+ getcmd_putch(CTL_BACKSPACE);
+ putnstr(buf + num, wlen);
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('p'):
+ case CTL_CH('n'):
+ {
+ char * hline;
+
+ esc_len = 0;
+
+ if (ichar == CTL_CH('p'))
+ hline = hist_prev();
+ else
+ hline = hist_next();
+
+ if (!hline) {
+ getcmd_cbeep();
+ continue;
+ }
+
+ /* nuke the current line */
+ /* first, go home */
+ BEGINNING_OF_LINE();
+
+ /* erase to end of line */
+ ERASE_TO_EOL();
+
+ /* copy new line into place and display */
+ strcpy(buf, hline);
+ eol_num = strlen(buf);
+ REFRESH_TO_EOL();
+ continue;
+ }
+#ifdef CONFIG_AUTO_COMPLETE
+ case '\t': {
+ int num2, col;
+
+ /* do not autocomplete when in the middle */
+ if (num < eol_num) {
+ getcmd_cbeep();
+ break;
+ }
+
+ buf[num] = '\0';
+ col = strlen(prompt) + eol_num;
+ num2 = num;
+ if (cmd_auto_complete(prompt, buf, &num2, &col)) {
+ col = num2 - num;
+ num += col;
+ eol_num += col;
+ }
+ break;
+ }
+#endif
+ default:
+ cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
+ break;
+ }
+ }
+ *len = eol_num;
+ buf[eol_num] = '\0'; /* lose the newline */
+
+ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
+ cread_add_to_hist(buf);
+ hist_cur = hist_add_idx;
+
+ return 0;
+}
+
+#endif /* CONFIG_CMDLINE_EDITING */
+
+/****************************************************************************/
+
+/*
+ * Prompt for input and read a line.
+ * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
+ * time out when time goes past endtime (timebase time in ticks).
+ * Return: number of read characters
+ * -1 if break
+ * -2 if timed out
+ */
+int readline (const char *const prompt)
+{
+ /*
+ * If console_buffer isn't 0-length the user will be prompted to modify
+ * it instead of entering it from scratch as desired.
+ */
+ console_buffer[0] = '\0';
+
+ return readline_into_buffer(prompt, console_buffer);
+}
+
+
+int readline_into_buffer (const char *const prompt, char * buffer)
+{
+ char *p = buffer;
+#ifdef CONFIG_CMDLINE_EDITING
+ unsigned int len = CONFIG_SYS_CBSIZE;
+ int rc;
+ static int initted = 0;
+
+ /*
+ * History uses a global array which is not
+ * writable until after relocation to RAM.
+ * Revert to non-history version if still
+ * running from flash.
+ */
+ if (gd->flags & GD_FLG_RELOC) {
+ if (!initted) {
+ hist_init();
+ initted = 1;
+ }
+
+ if (prompt)
+ puts (prompt);
+
+ rc = cread_line(prompt, p, &len);
+ return rc < 0 ? rc : len;
+
+ } else {
+#endif /* CONFIG_CMDLINE_EDITING */
+ char * p_buf = p;
+ int n = 0; /* buffer index */
+ int plen = 0; /* prompt length */
+ int col; /* output column cnt */
+ char c;
+
+ /* print prompt */
+ if (prompt) {
+ plen = strlen (prompt);
+ puts (prompt);
+ }
+ col = plen;
+
+ for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ while (!tstc()) { /* while no incoming data */
+ if (retry_time >= 0 && get_ticks() > endtime)
+ return (-2); /* timed out */
+ WATCHDOG_RESET();
+ }
+#endif
+ WATCHDOG_RESET(); /* Trigger watchdog, if needed */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+ while (!tstc()) {
+ extern void show_activity(int arg);
+ show_activity(0);
+ WATCHDOG_RESET();
+ }
+#endif
+ c = getc();
+
+ /*
+ * Special character handling
+ */
+ switch (c) {
+ case '\r': /* Enter */
+ case '\n':
+ *p = '\0';
+ puts ("\r\n");
+ return (p - p_buf);
+
+ case '\0': /* nul */
+ continue;
+
+ case 0x03: /* ^C - break */
+ p_buf[0] = '\0'; /* discard input */
+ return (-1);
+
+ case 0x15: /* ^U - erase line */
+ while (col > plen) {
+ puts (erase_seq);
+ --col;
+ }
+ p = p_buf;
+ n = 0;
+ continue;
+
+ case 0x17: /* ^W - erase word */
+ p=delete_char(p_buf, p, &col, &n, plen);
+ while ((n > 0) && (*p != ' ')) {
+ p=delete_char(p_buf, p, &col, &n, plen);
+ }
+ continue;
+
+ case 0x08: /* ^H - backspace */
+ case 0x7F: /* DEL - backspace */
+ p=delete_char(p_buf, p, &col, &n, plen);
+ continue;
+
+ default:
+ /*
+ * Must be a normal character then
+ */
+ if (n < CONFIG_SYS_CBSIZE-2) {
+ if (c == '\t') { /* expand TABs */
+#ifdef CONFIG_AUTO_COMPLETE
+ /* if auto completion triggered just continue */
+ *p = '\0';
+ if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
+ p = p_buf + n; /* reset */
+ continue;
+ }
+#endif
+ puts (tab_seq+(col&07));
+ col += 8 - (col&07);
+ } else {
+ ++col; /* echo input */
+ putc (c);
+ }
+ *p++ = c;
+ ++n;
+ } else { /* Buffer full */
+ putc ('\a');
+ }
+ }
+ }
+#ifdef CONFIG_CMDLINE_EDITING
+ }
+#endif
+}
+
+/****************************************************************************/
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+ char *s;
+
+ if (*np == 0) {
+ return (p);
+ }
+
+ if (*(--p) == '\t') { /* will retype the whole line */
+ while (*colp > plen) {
+ puts (erase_seq);
+ (*colp)--;
+ }
+ for (s=buffer; s<p; ++s) {
+ if (*s == '\t') {
+ puts (tab_seq+((*colp) & 07));
+ *colp += 8 - ((*colp) & 07);
+ } else {
+ ++(*colp);
+ putc (*s);
+ }
+ }
+ } else {
+ puts (erase_seq);
+ (*colp)--;
+ }
+ (*np)--;
+ return (p);
+}
+
+/****************************************************************************/
+
+int parse_line (char *line, char *argv[])
+{
+ int nargs = 0;
+
+#ifdef DEBUG_PARSER
+ printf ("parse_line: \"%s\"\n", line);
+#endif
+ while (nargs < CONFIG_SYS_MAXARGS) {
+
+ /* skip any white space */
+ while ((*line == ' ') || (*line == '\t')) {
+ ++line;
+ }
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+ }
+
+ argv[nargs++] = line; /* begin of argument string */
+
+ /* find end of string */
+ while (*line && (*line != ' ') && (*line != '\t')) {
+ ++line;
+ }
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+ }
+
+ *line++ = '\0'; /* terminate current arg */
+ }
+
+ printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
+
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+}
+
+/****************************************************************************/
+
+static void process_macros (const char *input, char *output)
+{
+ char c, prev;
+ const char *varname_start = NULL;
+ int inputcnt = strlen (input);
+ int outputcnt = CONFIG_SYS_CBSIZE;
+ int state = 0; /* 0 = waiting for '$' */
+
+ /* 1 = waiting for '(' or '{' */
+ /* 2 = waiting for ')' or '}' */
+ /* 3 = waiting for ''' */
+#ifdef DEBUG_PARSER
+ char *output_start = output;
+
+ printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
+ input);
+#endif
+
+ prev = '\0'; /* previous character */
+
+ while (inputcnt && outputcnt) {
+ c = *input++;
+ inputcnt--;
+
+ if (state != 3) {
+ /* remove one level of escape characters */
+ if ((c == '\\') && (prev != '\\')) {
+ if (inputcnt-- == 0)
+ break;
+ prev = c;
+ c = *input++;
+ }
+ }
+
+ switch (state) {
+ case 0: /* Waiting for (unescaped) $ */
+ if ((c == '\'') && (prev != '\\')) {
+ state = 3;
+ break;
+ }
+ if ((c == '$') && (prev != '\\')) {
+ state++;
+ } else {
+ *(output++) = c;
+ outputcnt--;
+ }
+ break;
+ case 1: /* Waiting for ( */
+ if (c == '(' || c == '{') {
+ state++;
+ varname_start = input;
+ } else {
+ state = 0;
+ *(output++) = '$';
+ outputcnt--;
+
+ if (outputcnt) {
+ *(output++) = c;
+ outputcnt--;
+ }
+ }
+ break;
+ case 2: /* Waiting for ) */
+ if (c == ')' || c == '}') {
+ int i;
+ char envname[CONFIG_SYS_CBSIZE], *envval;
+ int envcnt = input - varname_start - 1; /* Varname # of chars */
+
+ /* Get the varname */
+ for (i = 0; i < envcnt; i++) {
+ envname[i] = varname_start[i];
+ }
+ envname[i] = 0;
+
+ /* Get its value */
+ envval = getenv (envname);
+
+ /* Copy into the line if it exists */
+ if (envval != NULL)
+ while ((*envval) && outputcnt) {
+ *(output++) = *(envval++);
+ outputcnt--;
+ }
+ /* Look for another '$' */
+ state = 0;
+ }
+ break;
+ case 3: /* Waiting for ' */
+ if ((c == '\'') && (prev != '\\')) {
+ state = 0;
+ } else {
+ *(output++) = c;
+ outputcnt--;
+ }
+ break;
+ }
+ prev = c;
+ }
+
+ if (outputcnt)
+ *output = 0;
+ else
+ *(output - 1) = 0;
+
+#ifdef DEBUG_PARSER
+ printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+ strlen (output_start), output_start);
+#endif
+}
+
+/****************************************************************************
+ * returns:
+ * 1 - command executed, repeatable
+ * 0 - command executed but not repeatable, interrupted commands are
+ * always considered not repeatable
+ * -1 - not executed (unrecognized, bootd recursion or too many args)
+ * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
+ * considered unrecognized)
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+
+int run_command (const char *cmd, int flag)
+{
+ cmd_tbl_t *cmdtp;
+ char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
+ char *token; /* start of token in cmdbuf */
+ char *sep; /* end of token (separator) in cmdbuf */
+ char finaltoken[CONFIG_SYS_CBSIZE];
+ char *str = cmdbuf;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ int argc, inquotes;
+ int repeatable = 1;
+ int rc = 0;
+
+#ifdef DEBUG_PARSER
+ printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
+ puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
+ puts ("\"\n");
+#endif
+
+ clear_ctrlc(); /* forget any previous Control C */
+
+ if (!cmd || !*cmd) {
+ return -1; /* empty command */
+ }
+
+ if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
+ puts ("## Command too long!\n");
+ return -1;
+ }
+
+ strcpy (cmdbuf, cmd);
+
+ /* Process separators and check for invalid
+ * repeatable commands
+ */
+
+#ifdef DEBUG_PARSER
+ printf ("[PROCESS_SEPARATORS] %s\n", cmd);
+#endif
+ while (*str) {
+
+ /*
+ * Find separator, or string end
+ * Allow simple escape of ';' by writing "\;"
+ */
+ for (inquotes = 0, sep = str; *sep; sep++) {
+ if ((*sep=='\'') &&
+ (*(sep-1) != '\\'))
+ inquotes=!inquotes;
+
+ if (!inquotes &&
+ (*sep == ';') && /* separator */
+ ( sep != str) && /* past string start */
+ (*(sep-1) != '\\')) /* and NOT escaped */
+ break;
+ }
+
+ /*
+ * Limit the token to data between separators
+ */
+ token = str;
+ if (*sep) {
+ str = sep + 1; /* start of command for next pass */
+ *sep = '\0';
+ }
+ else
+ str = sep; /* no more commands for next pass */
+#ifdef DEBUG_PARSER
+ printf ("token: \"%s\"\n", token);
+#endif
+
+ /* find macros in this token and replace them */
+ process_macros (token, finaltoken);
+
+ /* Extract arguments */
+ if ((argc = parse_line (finaltoken, argv)) == 0) {
+ rc = -1; /* no command at all */
+ continue;
+ }
+
+ /* Look up command in command table */
+ if ((cmdtp = find_cmd(argv[0])) == NULL) {
+ printf ("Unknown command '%s' - try 'help'\n", argv[0]);
+ rc = -1; /* give up after bad command */
+ continue;
+ }
+
+ /* found - check max args */
+ if (argc > cmdtp->maxargs) {
+ cmd_usage(cmdtp);
+ rc = -1;
+ continue;
+ }
+
+#if defined(CONFIG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ if (cmdtp->cmd == do_bootd) {
+#ifdef DEBUG_PARSER
+ printf ("[%s]\n", finaltoken);
+#endif
+ if (flag & CMD_FLAG_BOOTD) {
+ puts ("'bootd' recursion detected\n");
+ rc = -1;
+ continue;
+ } else {
+ flag |= CMD_FLAG_BOOTD;
+ }
+ }
+#endif
+
+ /* OK - call function to do the command */
+ if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
+ rc = -1;
+ }
+
+ repeatable &= cmdtp->repeatable;
+
+ /* Did the user stop this? */
+ if (had_ctrlc ())
+ return -1; /* if stopped then not repeatable */
+ }
+
+ return rc ? rc : repeatable;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_RUN)
+int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ for (i=1; i<argc; ++i) {
+ char *arg;
+
+ if ((arg = getenv (argv[i])) == NULL) {
+ printf ("## Error: \"%s\" not defined\n", argv[i]);
+ return 1;
+ }
+#ifndef CONFIG_SYS_HUSH_PARSER
+ if (run_command (arg, flag) == -1)
+ return 1;
+#else
+ if (parse_string_outer(arg,
+ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+ return 1;
+#endif
+ }
+ return 0;
+}
+#endif
diff --git a/u-boot/common/memsize.c b/u-boot/common/memsize.c
new file mode 100644
index 0000000..6c275c9
--- /dev/null
+++ b/u-boot/common/memsize.c
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <config.h>
+#ifdef __PPC__
+/*
+ * At least on G2 PowerPC cores, sequential accesses to non-existent
+ * memory must be synchronized.
+ */
+# include <asm/io.h> /* for sync() */
+#else
+# define sync() /* nothing */
+#endif
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'.
+ */
+long get_ram_size(volatile long *base, long maxsize)
+{
+ volatile long *addr;
+ long save[32];
+ long cnt;
+ long val;
+ long size;
+ int i = 0;
+
+ for (cnt = (maxsize / sizeof (long)) >> 1; cnt > 0; cnt >>= 1) {
+ addr = base + cnt; /* pointer arith! */
+ sync ();
+ save[i++] = *addr;
+ sync ();
+ *addr = ~cnt;
+ }
+
+ addr = base;
+ sync ();
+ save[i] = *addr;
+ sync ();
+ *addr = 0;
+
+ sync ();
+ if ((val = *addr) != 0) {
+ /* Restore the original data before leaving the function.
+ */
+ sync ();
+ *addr = save[i];
+ for (cnt = 1; cnt < maxsize / sizeof(long); cnt <<= 1) {
+ addr = base + cnt;
+ sync ();
+ *addr = save[--i];
+ }
+ return (0);
+ }
+
+ for (cnt = 1; cnt < maxsize / sizeof (long); cnt <<= 1) {
+ addr = base + cnt; /* pointer arith! */
+ val = *addr;
+ *addr = save[--i];
+ if (val != ~cnt) {
+ size = cnt * sizeof (long);
+ /* Restore the original data before leaving the function.
+ */
+ for (cnt <<= 1; cnt < maxsize / sizeof (long); cnt <<= 1) {
+ addr = base + cnt;
+ *addr = save[--i];
+ }
+ return (size);
+ }
+ }
+
+ return (maxsize);
+}
diff --git a/u-boot/common/miiphyutil.c b/u-boot/common/miiphyutil.c
new file mode 100644
index 0000000..e282096
--- /dev/null
+++ b/u-boot/common/miiphyutil.c
@@ -0,0 +1,483 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <miiphy.h>
+
+#include <asm/types.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <net.h>
+
+/* local debug macro */
+#undef MII_DEBUG
+
+#undef debug
+#ifdef MII_DEBUG
+#define debug(fmt,args...) printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif /* MII_DEBUG */
+
+struct mii_dev {
+ struct list_head link;
+ const char *name;
+ int (*read) (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+ int (*write) (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+};
+
+static struct list_head mii_devs;
+static struct mii_dev *current_mii;
+
+/*
+ * Lookup the mii_dev struct by the registered device name.
+ */
+static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ if (!devname) {
+ printf("NULL device name!\n");
+ return NULL;
+ }
+
+ list_for_each(entry, &mii_devs) {
+ dev = list_entry(entry, struct mii_dev, link);
+ if (strcmp(dev->name, devname) == 0)
+ return dev;
+ }
+
+ if (!quiet)
+ printf("No such device: %s\n", devname);
+ return NULL;
+}
+
+/*****************************************************************************
+ *
+ * Initialize global data. Need to be called before any other miiphy routine.
+ */
+void miiphy_init(void)
+{
+ INIT_LIST_HEAD (&mii_devs);
+ current_mii = NULL;
+}
+
+/*****************************************************************************
+ *
+ * Register read and write MII access routines for the device <name>.
+ */
+void miiphy_register(const char *name,
+ int (*read) (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value),
+ int (*write) (const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value))
+{
+ struct mii_dev *new_dev;
+ unsigned int name_len;
+ char *new_name;
+
+ /* check if we have unique name */
+ new_dev = miiphy_get_dev_by_name(name, 1);
+ if (new_dev) {
+ printf("miiphy_register: non unique device name '%s'\n", name);
+ return;
+ }
+
+ /* allocate memory */
+ name_len = strlen (name);
+ new_dev =
+ (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);
+
+ if (new_dev == NULL) {
+ printf ("miiphy_register: cannot allocate memory for '%s'\n",
+ name);
+ return;
+ }
+ memset (new_dev, 0, sizeof (struct mii_dev) + name_len);
+
+ /* initalize mii_dev struct fields */
+ INIT_LIST_HEAD (&new_dev->link);
+ new_dev->read = read;
+ new_dev->write = write;
+ new_dev->name = new_name = (char *)(new_dev + 1);
+ strncpy (new_name, name, name_len);
+ new_name[name_len] = '\0';
+
+ debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
+ new_dev->name, new_dev->read, new_dev->write);
+
+ /* add it to the list */
+ list_add_tail (&new_dev->link, &mii_devs);
+
+ if (!current_mii)
+ current_mii = new_dev;
+}
+
+int miiphy_set_current_dev(const char *devname)
+{
+ struct mii_dev *dev;
+
+ dev = miiphy_get_dev_by_name(devname, 0);
+ if (dev) {
+ current_mii = dev;
+ return 0;
+ }
+
+ return 1;
+}
+
+const char *miiphy_get_current_dev(void)
+{
+ if (current_mii)
+ return current_mii->name;
+
+ return NULL;
+}
+
+static struct mii_dev *miiphy_get_active_dev(const char *devname)
+{
+ /* If the current mii is the one we want, return it */
+ if (current_mii)
+ if (strcmp(current_mii->name, devname) == 0)
+ return current_mii;
+
+ /* Otherwise, set the active one to the one we want */
+ if (miiphy_set_current_dev(devname))
+ return NULL;
+ else
+ return current_mii;
+}
+
+/*****************************************************************************
+ *
+ * Read to variable <value> from the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ struct mii_dev *dev;
+
+ dev = miiphy_get_active_dev(devname);
+ if (dev)
+ return dev->read(devname, addr, reg, value);
+
+ return 1;
+}
+
+/*****************************************************************************
+ *
+ * Write <value> to the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ struct mii_dev *dev;
+
+ dev = miiphy_get_active_dev(devname);
+ if (dev)
+ return dev->write(devname, addr, reg, value);
+
+ return 1;
+}
+
+/*****************************************************************************
+ *
+ * Print out list of registered MII capable devices.
+ */
+void miiphy_listdev (void)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ puts ("MII devices: ");
+ list_for_each (entry, &mii_devs) {
+ dev = list_entry (entry, struct mii_dev, link);
+ printf ("'%s' ", dev->name);
+ }
+ puts ("\n");
+
+ if (current_mii)
+ printf ("Current device: '%s'\n", current_mii->name);
+}
+
+/*****************************************************************************
+ *
+ * Read the OUI, manufacture's model number, and revision number.
+ *
+ * OUI: 22 bits (unsigned int)
+ * Model: 6 bits (unsigned char)
+ * Revision: 4 bits (unsigned char)
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
+ unsigned char *model, unsigned char *rev)
+{
+ unsigned int reg = 0;
+ unsigned short tmp;
+
+ if (miiphy_read (devname, addr, MII_PHYSID2, &tmp) != 0) {
+ debug ("PHY ID register 2 read failed\n");
+ return (-1);
+ }
+ reg = tmp;
+
+ debug ("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
+
+ if (reg == 0xFFFF) {
+ /* No physical device present at this address */
+ return (-1);
+ }
+
+ if (miiphy_read (devname, addr, MII_PHYSID1, &tmp) != 0) {
+ debug ("PHY ID register 1 read failed\n");
+ return (-1);
+ }
+ reg |= tmp << 16;
+ debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+
+ *oui = (reg >> 10);
+ *model = (unsigned char)((reg >> 4) & 0x0000003F);
+ *rev = (unsigned char)(reg & 0x0000000F);
+ return (0);
+}
+
+/*****************************************************************************
+ *
+ * Reset the PHY.
+ * Returns:
+ * 0 on success
+ */
+int miiphy_reset(const char *devname, unsigned char addr)
+{
+ unsigned short reg;
+ int timeout = 500;
+
+ if (miiphy_read (devname, addr, MII_BMCR, &reg) != 0) {
+ debug ("PHY status read failed\n");
+ return (-1);
+ }
+ if (miiphy_write (devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
+ debug ("PHY reset failed\n");
+ return (-1);
+ }
+#ifdef CONFIG_PHY_RESET_DELAY
+ udelay (CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
+#endif
+ /*
+ * Poll the control register for the reset bit to go to 0 (it is
+ * auto-clearing). This should happen within 0.5 seconds per the
+ * IEEE spec.
+ */
+ reg = 0x8000;
+ while (((reg & 0x8000) != 0) && timeout--) {
+ if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
+ debug("PHY status read failed\n");
+ return -1;
+ }
+ udelay(1000);
+ }
+ if ((reg & 0x8000) == 0) {
+ return (0);
+ } else {
+ puts ("PHY reset timed out\n");
+ return (-1);
+ }
+ return (0);
+}
+
+/*****************************************************************************
+ *
+ * Determine the ethernet speed (10/100/1000). Return 10 on error.
+ */
+int miiphy_speed(const char *devname, unsigned char addr)
+{
+ u16 bmcr, anlpar;
+
+#if defined(CONFIG_PHY_GIGE)
+ u16 btsr;
+
+ /*
+ * Check for 1000BASE-X. If it is supported, then assume that the speed
+ * is 1000.
+ */
+ if (miiphy_is_1000base_x (devname, addr)) {
+ return _1000BASET;
+ }
+ /*
+ * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
+ */
+ /* Check for 1000BASE-T. */
+ if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) {
+ printf ("PHY 1000BT status");
+ goto miiphy_read_failed;
+ }
+ if (btsr != 0xFFFF &&
+ (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
+ return _1000BASET;
+ }
+#endif /* CONFIG_PHY_GIGE */
+
+ /* Check Basic Management Control Register first. */
+ if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) {
+ printf ("PHY speed");
+ goto miiphy_read_failed;
+ }
+ /* Check if auto-negotiation is on. */
+ if (bmcr & BMCR_ANENABLE) {
+ /* Get auto-negotiation results. */
+ if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
+ printf ("PHY AN speed");
+ goto miiphy_read_failed;
+ }
+ return (anlpar & LPA_100) ? _100BASET : _10BASET;
+ }
+ /* Get speed from basic control settings. */
+ return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;
+
+miiphy_read_failed:
+ printf (" read failed, assuming 10BASE-T\n");
+ return _10BASET;
+}
+
+/*****************************************************************************
+ *
+ * Determine full/half duplex. Return half on error.
+ */
+int miiphy_duplex(const char *devname, unsigned char addr)
+{
+ u16 bmcr, anlpar;
+
+#if defined(CONFIG_PHY_GIGE)
+ u16 btsr;
+
+ /* Check for 1000BASE-X. */
+ if (miiphy_is_1000base_x (devname, addr)) {
+ /* 1000BASE-X */
+ if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
+ printf ("1000BASE-X PHY AN duplex");
+ goto miiphy_read_failed;
+ }
+ }
+ /*
+ * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
+ */
+ /* Check for 1000BASE-T. */
+ if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) {
+ printf ("PHY 1000BT status");
+ goto miiphy_read_failed;
+ }
+ if (btsr != 0xFFFF) {
+ if (btsr & PHY_1000BTSR_1000FD) {
+ return FULL;
+ } else if (btsr & PHY_1000BTSR_1000HD) {
+ return HALF;
+ }
+ }
+#endif /* CONFIG_PHY_GIGE */
+
+ /* Check Basic Management Control Register first. */
+ if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) {
+ puts ("PHY duplex");
+ goto miiphy_read_failed;
+ }
+ /* Check if auto-negotiation is on. */
+ if (bmcr & BMCR_ANENABLE) {
+ /* Get auto-negotiation results. */
+ if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
+ puts ("PHY AN duplex");
+ goto miiphy_read_failed;
+ }
+ return (anlpar & (LPA_10FULL | LPA_100FULL)) ?
+ FULL : HALF;
+ }
+ /* Get speed from basic control settings. */
+ return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;
+
+miiphy_read_failed:
+ printf (" read failed, assuming half duplex\n");
+ return HALF;
+}
+
+/*****************************************************************************
+ *
+ * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
+ * 1000BASE-T, or on error.
+ */
+int miiphy_is_1000base_x(const char *devname, unsigned char addr)
+{
+#if defined(CONFIG_PHY_GIGE)
+ u16 exsr;
+
+ if (miiphy_read (devname, addr, MII_ESTATUS, &exsr)) {
+ printf ("PHY extended status read failed, assuming no "
+ "1000BASE-X\n");
+ return 0;
+ }
+ return 0 != (exsr & (ESTATUS_1000XF | ESTATUS_1000XH));
+#else
+ return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN
+/*****************************************************************************
+ *
+ * Determine link status
+ */
+int miiphy_link(const char *devname, unsigned char addr)
+{
+ unsigned short reg;
+
+ /* dummy read; needed to latch some phys */
+ (void)miiphy_read (devname, addr, MII_BMSR, &reg);
+ if (miiphy_read (devname, addr, MII_BMSR, &reg)) {
+ puts ("MII_BMSR read failed, assuming no link\n");
+ return (0);
+ }
+
+ /* Determine if a link is active */
+ if ((reg & BMSR_LSTATUS) != 0) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+#endif
diff --git a/u-boot/common/modem.c b/u-boot/common/modem.c
new file mode 100644
index 0000000..a017b29
--- /dev/null
+++ b/u-boot/common/modem.c
@@ -0,0 +1,118 @@
+/*
+ * (C) Copyright 2002-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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>
+
+/* 'inline' - We have to do it fast */
+static inline void mdm_readline(char *buf, int bufsiz)
+{
+ char c;
+ char *p;
+ int n;
+
+ n = 0;
+ p = buf;
+ for(;;) {
+ c = serial_getc();
+
+ /* dbg("(%c)", c); */
+
+ switch(c) {
+ case '\r':
+ break;
+ case '\n':
+ *p = '\0';
+ return;
+
+ default:
+ if(n++ > bufsiz) {
+ *p = '\0';
+ return; /* sanity check */
+ }
+ *p = c;
+ p++;
+ break;
+ }
+ }
+}
+
+extern void dbg(const char *fmt, ...);
+int mdm_init (void)
+{
+ char env_str[16];
+ char *init_str;
+ int i;
+ extern char console_buffer[];
+ extern void enable_putc(void);
+ extern int hwflow_onoff(int);
+
+ enable_putc(); /* enable serial_putc() */
+
+#ifdef CONFIG_HWFLOW
+ init_str = getenv("mdm_flow_control");
+ if (init_str && (strcmp(init_str, "rts/cts") == 0))
+ hwflow_onoff (1);
+ else
+ hwflow_onoff(-1);
+#endif
+
+ for (i = 1;;i++) {
+ sprintf(env_str, "mdm_init%d", i);
+ if ((init_str = getenv(env_str)) != NULL) {
+ serial_puts(init_str);
+ serial_puts("\n");
+ for(;;) {
+ mdm_readline(console_buffer, CONFIG_SYS_CBSIZE);
+ dbg("ini%d: [%s]", i, console_buffer);
+
+ if ((strcmp(console_buffer, "OK") == 0) ||
+ (strcmp(console_buffer, "ERROR") == 0)) {
+ dbg("ini%d: cmd done", i);
+ break;
+ } else /* in case we are originating call ... */
+ if (strncmp(console_buffer, "CONNECT", 7) == 0) {
+ dbg("ini%d: connect", i);
+ return 0;
+ }
+ }
+ } else
+ break; /* no init string - stop modem init */
+
+ udelay(100000);
+ }
+
+ udelay(100000);
+
+ /* final stage - wait for connect */
+ for(;i > 1;) { /* if 'i' > 1 - wait for connection
+ message from modem */
+ mdm_readline(console_buffer, CONFIG_SYS_CBSIZE);
+ dbg("ini_f: [%s]", console_buffer);
+ if (strncmp(console_buffer, "CONNECT", 7) == 0) {
+ dbg("ini_f: connected");
+ return 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/u-boot/common/s_record.c b/u-boot/common/s_record.c
new file mode 100644
index 0000000..c52bf1b
--- /dev/null
+++ b/u-boot/common/s_record.c
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <s_record.h>
+
+static int hex1_bin (char c);
+static int hex2_bin (char *s);
+
+int srec_decode (char *input, int *count, ulong *addr, char *data)
+{
+ int i;
+ int v; /* conversion buffer */
+ int srec_type; /* S-Record type */
+ unsigned char chksum; /* buffer for checksum */
+
+ chksum = 0;
+
+ /* skip anything before 'S', and the 'S' itself.
+ * Return error if not found
+ */
+
+ for (; *input; ++input) {
+ if (*input == 'S') { /* skip 'S' */
+ ++input;
+ break;
+ }
+ }
+ if (*input == '\0') { /* no more data? */
+ return (SREC_EMPTY);
+ }
+
+ v = *input++; /* record type */
+
+ if ((*count = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ chksum += *count;
+ input += 2;
+
+ switch (v) { /* record type */
+
+ case '0': /* start record */
+ srec_type = SREC_START; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '1':
+ srec_type = SREC_DATA2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '2':
+ srec_type = SREC_DATA3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '3': /* data record with a */
+ srec_type = SREC_DATA4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+/*** case '4' ***/
+ case '5': /* count record, addr field contains */
+ srec_type = SREC_COUNT; /* a 2 byte record counter */
+ *count = 0; /* no data */
+ break;
+/*** case '6' -- not used ***/
+ case '7': /* end record with a */
+ srec_type = SREC_END4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+ case '8': /* end record with a */
+ srec_type = SREC_END3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '9': /* end record with a */
+ srec_type = SREC_END2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* read address field */
+ *addr = 0;
+
+ switch (v) {
+ case '3': /* 4 byte addr field */
+ case '7':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '2': /* 3 byte addr field */
+ case '8':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '0': /* 2 byte addr field */
+ case '1':
+ case '5':
+ case '9':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* convert data and calculate checksum */
+ for (i=0; i < *count; ++i) {
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ data[i] = v;
+ chksum += v;
+ input += 2;
+ }
+
+ /* read anc check checksum */
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ if ((unsigned char)v != (unsigned char)~chksum) {
+ return (SREC_E_BADCHKS);
+ }
+
+ return (srec_type);
+}
+
+static int hex1_bin (char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c + 10 - 'a');
+ if (c >= 'A' && c <= 'F')
+ return (c + 10 - 'A');
+ return (-1);
+}
+
+static int hex2_bin (char *s)
+{
+ int i, j;
+
+ if ((i = hex1_bin(*s++)) < 0) {
+ return (-1);
+ }
+ if ((j = hex1_bin(*s)) < 0) {
+ return (-1);
+ }
+
+ return ((i<<4) + j);
+}
diff --git a/u-boot/common/serial.c b/u-boot/common/serial.c
new file mode 100644
index 0000000..8ebf9a5
--- /dev/null
+++ b/u-boot/common/serial.c
@@ -0,0 +1,293 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <serial.h>
+#include <stdio_dev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct serial_device *serial_devices = NULL;
+static struct serial_device *serial_current = NULL;
+
+#if !defined(CONFIG_LWMON) && !defined(CONFIG_PXA250) && !defined(CONFIG_PXA27X)
+struct serial_device *__default_serial_console (void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+ return &serial_smc_device;
+#elif defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) \
+ || defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+ return &serial_scc_device;
+#elif defined(CONFIG_4xx) \
+ || defined(CONFIG_MB86R0x) || defined(CONFIG_MPC5xxx) \
+ || defined(CONFIG_MPC83xx) || defined(CONFIG_MPC85xx) \
+ || defined(CONFIG_MPC86xx) || defined(CONFIG_SYS_SC520) \
+ || defined(CONFIG_TEGRA2)
+#if defined(CONFIG_CONS_INDEX) && defined(CONFIG_SYS_NS16550_SERIAL)
+#if (CONFIG_CONS_INDEX==1)
+ return &eserial1_device;
+#elif (CONFIG_CONS_INDEX==2)
+ return &eserial2_device;
+#elif (CONFIG_CONS_INDEX==3)
+ return &eserial3_device;
+#elif (CONFIG_CONS_INDEX==4)
+ return &eserial4_device;
+#else
+#error "Bad CONFIG_CONS_INDEX."
+#endif
+#else
+ return &serial0_device;
+#endif
+#elif defined(CONFIG_MPC512X)
+#if (CONFIG_PSC_CONSOLE == 3)
+ return &serial3_device;
+#elif (CONFIG_PSC_CONSOLE == 6)
+ return &serial6_device;
+#else
+#error "Bad CONFIG_PSC_CONSOLE."
+#endif
+#elif defined(CONFIG_S3C2410)
+#if defined(CONFIG_SERIAL1)
+ return &s3c24xx_serial0_device;
+#elif defined(CONFIG_SERIAL2)
+ return &s3c24xx_serial1_device;
+#elif defined(CONFIG_SERIAL3)
+ return &s3c24xx_serial2_device;
+#else
+#error "CONFIG_SERIAL? missing."
+#endif
+#elif defined(CONFIG_S5P)
+#if defined(CONFIG_SERIAL0)
+ return &s5p_serial0_device;
+#elif defined(CONFIG_SERIAL1)
+ return &s5p_serial1_device;
+#elif defined(CONFIG_SERIAL2)
+ return &s5p_serial2_device;
+#elif defined(CONFIG_SERIAL3)
+ return &s5p_serial3_device;
+#else
+#error "CONFIG_SERIAL? missing."
+#endif
+#elif defined(CONFIG_OMAP3_ZOOM2)
+ return ZOOM2_DEFAULT_SERIAL_DEVICE;
+#else
+#error No default console
+#endif
+}
+
+struct serial_device *default_serial_console(void) __attribute__((weak, alias("__default_serial_console")));
+#endif
+
+int serial_register (struct serial_device *dev)
+{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ dev->init += gd->reloc_off;
+ dev->setbrg += gd->reloc_off;
+ dev->getc += gd->reloc_off;
+ dev->tstc += gd->reloc_off;
+ dev->putc += gd->reloc_off;
+ dev->puts += gd->reloc_off;
+#endif
+
+ dev->next = serial_devices;
+ serial_devices = dev;
+
+ return 0;
+}
+
+void serial_initialize (void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+ serial_register (&serial_smc_device);
+#endif
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) \
+ || defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+ serial_register (&serial_scc_device);
+#endif
+
+#if defined(CONFIG_SYS_NS16550_SERIAL)
+#if defined(CONFIG_SYS_NS16550_COM1)
+ serial_register(&eserial1_device);
+#endif
+#if defined(CONFIG_SYS_NS16550_COM2)
+ serial_register(&eserial2_device);
+#endif
+#if defined(CONFIG_SYS_NS16550_COM3)
+ serial_register(&eserial3_device);
+#endif
+#if defined(CONFIG_SYS_NS16550_COM4)
+ serial_register(&eserial4_device);
+#endif
+#endif /* CONFIG_SYS_NS16550_SERIAL */
+#if defined (CONFIG_FFUART)
+ serial_register(&serial_ffuart_device);
+#endif
+#if defined (CONFIG_BTUART)
+ serial_register(&serial_btuart_device);
+#endif
+#if defined (CONFIG_STUART)
+ serial_register(&serial_stuart_device);
+#endif
+#if defined(CONFIG_S3C2410)
+ serial_register(&s3c24xx_serial0_device);
+ serial_register(&s3c24xx_serial1_device);
+ serial_register(&s3c24xx_serial2_device);
+#endif
+#if defined(CONFIG_S5P)
+ serial_register(&s5p_serial0_device);
+ serial_register(&s5p_serial1_device);
+ serial_register(&s5p_serial2_device);
+ serial_register(&s5p_serial3_device);
+#endif
+#if defined(CONFIG_MPC512X)
+#if defined(CONFIG_SYS_PSC1)
+ serial_register(&serial1_device);
+#endif
+#if defined(CONFIG_SYS_PSC3)
+ serial_register(&serial3_device);
+#endif
+#if defined(CONFIG_SYS_PSC4)
+ serial_register(&serial4_device);
+#endif
+#if defined(CONFIG_SYS_PSC6)
+ serial_register(&serial6_device);
+#endif
+#endif
+ serial_assign (default_serial_console ()->name);
+}
+
+void serial_stdio_init (void)
+{
+ struct stdio_dev dev;
+ struct serial_device *s = serial_devices;
+
+ while (s) {
+ memset (&dev, 0, sizeof (dev));
+
+ strcpy (dev.name, s->name);
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
+
+ dev.start = s->init;
+ dev.stop = s->uninit;
+ dev.putc = s->putc;
+ dev.puts = s->puts;
+ dev.getc = s->getc;
+ dev.tstc = s->tstc;
+
+ stdio_register (&dev);
+
+ s = s->next;
+ }
+}
+
+int serial_assign (char *name)
+{
+ struct serial_device *s;
+
+ for (s = serial_devices; s; s = s->next) {
+ if (strcmp (s->name, name) == 0) {
+ serial_current = s;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void serial_reinit_all (void)
+{
+ struct serial_device *s;
+
+ for (s = serial_devices; s; s = s->next) {
+ s->init ();
+ }
+}
+
+int serial_init (void)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ return dev->init ();
+ }
+
+ return serial_current->init ();
+}
+
+void serial_setbrg (void)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ dev->setbrg ();
+ return;
+ }
+
+ serial_current->setbrg ();
+}
+
+int serial_getc (void)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ return dev->getc ();
+ }
+
+ return serial_current->getc ();
+}
+
+int serial_tstc (void)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ return dev->tstc ();
+ }
+
+ return serial_current->tstc ();
+}
+
+void serial_putc (const char c)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ dev->putc (c);
+ return;
+ }
+
+ serial_current->putc (c);
+}
+
+void serial_puts (const char *s)
+{
+ if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
+ struct serial_device *dev = default_serial_console ();
+
+ dev->puts (s);
+ return;
+ }
+
+ serial_current->puts (s);
+}
diff --git a/u-boot/common/stdio.c b/u-boot/common/stdio.c
new file mode 100644
index 0000000..b20772c
--- /dev/null
+++ b/u-boot/common/stdio.c
@@ -0,0 +1,244 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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 <config.h>
+#include <common.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <stdio_dev.h>
+#include <serial.h>
+#ifdef CONFIG_LOGBUFFER
+#include <logbuff.h>
+#endif
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+#include <i2c.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct stdio_dev devs;
+struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
+char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };
+
+#if defined(CONFIG_SPLASH_SCREEN) && !defined(CONFIG_SYS_DEVICE_NULLDEV)
+#define CONFIG_SYS_DEVICE_NULLDEV 1
+#endif
+
+
+#ifdef CONFIG_SYS_DEVICE_NULLDEV
+void nulldev_putc(const char c)
+{
+ /* nulldev is empty! */
+}
+
+void nulldev_puts(const char *s)
+{
+ /* nulldev is empty! */
+}
+
+int nulldev_input(void)
+{
+ /* nulldev is empty! */
+ return 0;
+}
+#endif
+
+/**************************************************************************
+ * SYSTEM DRIVERS
+ **************************************************************************
+ */
+
+static void drv_system_init (void)
+{
+ struct stdio_dev dev;
+
+ memset (&dev, 0, sizeof (dev));
+
+ strcpy (dev.name, "serial");
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ dev.putc = serial_putc;
+ dev.puts = serial_puts;
+ dev.getc = serial_getc;
+ dev.tstc = serial_tstc;
+ stdio_register (&dev);
+
+#ifdef CONFIG_SYS_DEVICE_NULLDEV
+ memset (&dev, 0, sizeof (dev));
+
+ strcpy (dev.name, "nulldev");
+ dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ dev.putc = nulldev_putc;
+ dev.puts = nulldev_puts;
+ dev.getc = nulldev_input;
+ dev.tstc = nulldev_input;
+
+ stdio_register (&dev);
+#endif
+}
+
+/**************************************************************************
+ * DEVICES
+ **************************************************************************
+ */
+struct list_head* stdio_get_list(void)
+{
+ return &(devs.list);
+}
+
+struct stdio_dev* stdio_get_by_name(const char *name)
+{
+ struct list_head *pos;
+ struct stdio_dev *dev;
+
+ if(!name)
+ return NULL;
+
+ list_for_each(pos, &(devs.list)) {
+ dev = list_entry(pos, struct stdio_dev, list);
+ if(strcmp(dev->name, name) == 0)
+ return dev;
+ }
+
+ return NULL;
+}
+
+struct stdio_dev* stdio_clone(struct stdio_dev *dev)
+{
+ struct stdio_dev *_dev;
+
+ if(!dev)
+ return NULL;
+
+ _dev = calloc(1, sizeof(struct stdio_dev));
+
+ if(!_dev)
+ return NULL;
+
+ memcpy(_dev, dev, sizeof(struct stdio_dev));
+ strncpy(_dev->name, dev->name, 16);
+
+ return _dev;
+}
+
+int stdio_register (struct stdio_dev * dev)
+{
+ struct stdio_dev *_dev;
+
+ _dev = stdio_clone(dev);
+ if(!_dev)
+ return -1;
+ list_add_tail(&(_dev->list), &(devs.list));
+ return 0;
+}
+
+/* deregister the device "devname".
+ * returns 0 if success, -1 if device is assigned and 1 if devname not found
+ */
+#ifdef CONFIG_SYS_STDIO_DEREGISTER
+int stdio_deregister(const char *devname)
+{
+ int l;
+ struct list_head *pos;
+ struct stdio_dev *dev;
+ char temp_names[3][8];
+
+ dev = stdio_get_by_name(devname);
+
+ if(!dev) /* device not found */
+ return -1;
+ /* get stdio devices (ListRemoveItem changes the dev list) */
+ for (l=0 ; l< MAX_FILES; l++) {
+ if (stdio_devices[l] == dev) {
+ /* Device is assigned -> report error */
+ return -1;
+ }
+ memcpy (&temp_names[l][0],
+ stdio_devices[l]->name,
+ sizeof(stdio_devices[l]->name));
+ }
+
+ list_del(&(dev->list));
+
+ /* reassign Device list */
+ list_for_each(pos, &(devs.list)) {
+ dev = list_entry(pos, struct stdio_dev, list);
+ for (l=0 ; l< MAX_FILES; l++) {
+ if(strcmp(dev->name, temp_names[l]) == 0)
+ stdio_devices[l] = dev;
+ }
+ }
+ return 0;
+}
+#endif /* CONFIG_SYS_STDIO_DEREGISTER */
+
+int stdio_init (void)
+{
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ /* already relocated for current ARM implementation */
+ ulong relocation_offset = gd->reloc_off;
+ int i;
+
+ /* relocate device name pointers */
+ for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
+ stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
+ relocation_offset);
+ }
+#endif /* CONFIG_NEEDS_MANUAL_RELOC */
+
+ /* Initialize the list */
+ INIT_LIST_HEAD(&(devs.list));
+
+#ifdef CONFIG_ARM_DCC_MULTI
+ drv_arm_dcc_init ();
+#endif
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+#ifdef CONFIG_LCD
+ drv_lcd_init ();
+#endif
+#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+ drv_video_init ();
+#endif
+#ifdef CONFIG_KEYBOARD
+ drv_keyboard_init ();
+#endif
+#ifdef CONFIG_LOGBUFFER
+ drv_logbuff_init ();
+#endif
+ drv_system_init ();
+#ifdef CONFIG_SERIAL_MULTI
+ serial_stdio_init ();
+#endif
+#ifdef CONFIG_USB_TTY
+ drv_usbtty_init ();
+#endif
+#ifdef CONFIG_NETCONSOLE
+ drv_nc_init ();
+#endif
+#ifdef CONFIG_JTAG_CONSOLE
+ drv_jtag_console_init ();
+#endif
+
+ return (0);
+}
diff --git a/u-boot/common/system_map.c b/u-boot/common/system_map.c
new file mode 100644
index 0000000..8307293
--- /dev/null
+++ b/u-boot/common/system_map.c
@@ -0,0 +1,8 @@
+/*
+ * The builtin symbol table for use with kallsyms
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+const char const system_map[] = SYSTEM_MAP;
diff --git a/u-boot/common/update.c b/u-boot/common/update.c
new file mode 100644
index 0000000..7528474
--- /dev/null
+++ b/u-boot/common/update.c
@@ -0,0 +1,315 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * Written by: Rafal Czubak <rcz@semihalf.com>
+ * Bartlomiej Sieka <tur@semihalf.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+
+#if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
+#error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
+#endif
+
+#if defined(CONFIG_SYS_NO_FLASH)
+#error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature"
+#endif
+
+#include <command.h>
+#include <flash.h>
+#include <net.h>
+#include <malloc.h>
+
+/* env variable holding the location of the update file */
+#define UPDATE_FILE_ENV "updatefile"
+
+/* set configuration defaults if needed */
+#ifndef CONFIG_UPDATE_LOAD_ADDR
+#define CONFIG_UPDATE_LOAD_ADDR 0x100000
+#endif
+
+#ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
+#define CONFIG_UPDATE_TFTP_MSEC_MAX 100
+#endif
+
+#ifndef CONFIG_UPDATE_TFTP_CNT_MAX
+#define CONFIG_UPDATE_TFTP_CNT_MAX 0
+#endif
+
+extern ulong TftpRRQTimeoutMSecs;
+extern int TftpRRQTimeoutCountMax;
+extern flash_info_t flash_info[];
+extern ulong load_addr;
+
+static uchar *saved_prot_info;
+
+static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
+{
+ int size, rv;
+ ulong saved_timeout_msecs;
+ int saved_timeout_count;
+ char *saved_netretry, *saved_bootfile;
+
+ rv = 0;
+ /* save used globals and env variable */
+ saved_timeout_msecs = TftpRRQTimeoutMSecs;
+ saved_timeout_count = TftpRRQTimeoutCountMax;
+ saved_netretry = strdup(getenv("netretry"));
+ saved_bootfile = strdup(BootFile);
+
+ /* set timeouts for auto-update */
+ TftpRRQTimeoutMSecs = msec_max;
+ TftpRRQTimeoutCountMax = cnt_max;
+
+ /* we don't want to retry the connection if errors occur */
+ setenv("netretry", "no");
+
+ /* download the update file */
+ load_addr = addr;
+ copy_filename(BootFile, filename, sizeof(BootFile));
+ size = NetLoop(TFTP);
+
+ if (size < 0)
+ rv = 1;
+ else if (size > 0)
+ flush_cache(addr, size);
+
+ /* restore changed globals and env variable */
+ TftpRRQTimeoutMSecs = saved_timeout_msecs;
+ TftpRRQTimeoutCountMax = saved_timeout_count;
+
+ setenv("netretry", saved_netretry);
+ if (saved_netretry != NULL)
+ free(saved_netretry);
+
+ if (saved_bootfile != NULL) {
+ copy_filename(BootFile, saved_bootfile, sizeof(BootFile));
+ free(saved_bootfile);
+ }
+
+ return rv;
+}
+
+static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
+{
+ uchar *sp_info_ptr;
+ ulong s;
+ int i, bank, cnt;
+ flash_info_t *info;
+
+ sp_info_ptr = NULL;
+
+ if (prot == 0) {
+ saved_prot_info =
+ calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
+ if (!saved_prot_info)
+ return 1;
+ }
+
+ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ cnt = 0;
+ info = &flash_info[bank];
+
+ /* Nothing to do if the bank doesn't exist */
+ if (info->sector_count == 0)
+ return 0;
+
+ /* Point to current bank protection information */
+ sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
+
+ /*
+ * Adjust addr_first or addr_last if we are on bank boundary.
+ * Address space between banks must be continuous for other
+ * flash functions (like flash_sect_erase or flash_write) to
+ * succeed. Banks must also be numbered in correct order,
+ * according to increasing addresses.
+ */
+ if (addr_last > info->start[0] + info->size - 1)
+ addr_last = info->start[0] + info->size - 1;
+ if (addr_first < info->start[0])
+ addr_first = info->start[0];
+
+ for (i = 0; i < info->sector_count; i++) {
+ /* Save current information about protected sectors */
+ if (prot == 0) {
+ s = info->start[i];
+ if ((s >= addr_first) && (s <= addr_last))
+ sp_info_ptr[i] = info->protect[i];
+
+ }
+
+ /* Protect/unprotect sectors */
+ if (sp_info_ptr[i] == 1) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, prot))
+ return 1;
+#else
+ info->protect[i] = prot;
+#endif
+ cnt++;
+ }
+ }
+
+ if (cnt) {
+ printf("%sProtected %d sectors\n",
+ prot ? "": "Un-", cnt);
+ }
+ }
+
+ if((prot == 1) && saved_prot_info)
+ free(saved_prot_info);
+
+ return 0;
+}
+
+static int update_flash(ulong addr_source, ulong addr_first, ulong size)
+{
+ ulong addr_last = addr_first + size - 1;
+
+ /* round last address to the sector boundary */
+ if (flash_sect_roundb(&addr_last) > 0)
+ return 1;
+
+ if (addr_first >= addr_last) {
+ printf("Error: end address exceeds addressing space\n");
+ return 1;
+ }
+
+ /* remove protection on processed sectors */
+ if (update_flash_protect(0, addr_first, addr_last) > 0) {
+ printf("Error: could not unprotect flash sectors\n");
+ return 1;
+ }
+
+ printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
+ if (flash_sect_erase(addr_first, addr_last) > 0) {
+ printf("Error: could not erase flash\n");
+ return 1;
+ }
+
+ printf("Copying to flash...");
+ if (flash_write((char *)addr_source, addr_first, size) > 0) {
+ printf("Error: could not copy to flash\n");
+ return 1;
+ }
+ printf("done\n");
+
+ /* enable protection on processed sectors */
+ if (update_flash_protect(1, addr_first, addr_last) > 0) {
+ printf("Error: could not protect flash sectors\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
+ ulong *fladdr, ulong *size)
+{
+ const void *data;
+
+ if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
+ return 1;
+
+ if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
+ return 1;
+
+ *addr = (ulong)data;
+
+ return 0;
+}
+
+void update_tftp(void)
+{
+ char *filename, *env_addr;
+ int images_noffset, ndepth, noffset;
+ ulong update_addr, update_fladdr, update_size;
+ ulong addr;
+ void *fit;
+
+ printf("Auto-update from TFTP: ");
+
+ /* get the file name of the update file */
+ filename = getenv(UPDATE_FILE_ENV);
+ if (filename == NULL) {
+ printf("failed, env. variable '%s' not found\n",
+ UPDATE_FILE_ENV);
+ return;
+ }
+
+ printf("trying update file '%s'\n", filename);
+
+ /* get load address of downloaded update file */
+ if ((env_addr = getenv("loadaddr")) != NULL)
+ addr = simple_strtoul(env_addr, NULL, 16);
+ else
+ addr = CONFIG_UPDATE_LOAD_ADDR;
+
+
+ if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
+ CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
+ printf("Can't load update file, aborting auto-update\n");
+ return;
+ }
+
+ fit = (void *)addr;
+
+ if (!fit_check_format((void *)fit)) {
+ printf("Bad FIT format of the update file, aborting "
+ "auto-update\n");
+ return;
+ }
+
+ /* process updates */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+
+ ndepth = 0;
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ while (noffset >= 0 && ndepth > 0) {
+ if (ndepth != 1)
+ goto next_node;
+
+ printf("Processing update '%s' :",
+ fit_get_name(fit, noffset, NULL));
+
+ if (!fit_image_check_hashes(fit, noffset)) {
+ printf("Error: invalid update hash, aborting\n");
+ goto next_node;
+ }
+
+ printf("\n");
+ if (update_fit_getparams(fit, noffset, &update_addr,
+ &update_fladdr, &update_size)) {
+ printf("Error: can't get update parameteres, "
+ "aborting\n");
+ goto next_node;
+ }
+ if (update_flash(update_addr, update_fladdr, update_size)) {
+ printf("Error: can't flash update, aborting\n");
+ goto next_node;
+ }
+next_node:
+ noffset = fdt_next_node(fit, noffset, &ndepth);
+ }
+
+ return;
+}
diff --git a/u-boot/common/usb.c b/u-boot/common/usb.c
new file mode 100644
index 0000000..4f7c520
--- /dev/null
+++ b/u-boot/common/usb.c
@@ -0,0 +1,1388 @@
+/*
+ *
+ * Most of this source has been derived from the Linux USB
+ * project:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ *
+ * Adapted for U-Boot:
+ * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ *
+ * 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
+ *
+ */
+
+/*
+ * How it works:
+ *
+ * Since this is a bootloader, the devices will not be automatic
+ * (re)configured on hotplug, but after a restart of the USB the
+ * device should work.
+ *
+ * For each transfer (except "Interrupt") we wait for completion.
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+
+#include <usb.h>
+#ifdef CONFIG_4xx
+#include <asm/4xx_pci.h>
+#endif
+
+#ifdef DEBUG
+#define USB_DEBUG
+#define USB_HUB_DEBUG
+#endif
+
+#ifdef USB_DEBUG
+#define USB_PRINTF(fmt, args...) printf(fmt , ##args)
+#else
+#define USB_PRINTF(fmt, args...)
+#endif
+
+#define USB_BUFSIZ 512
+
+static struct usb_device usb_dev[USB_MAX_DEVICE];
+static int dev_index;
+static int running;
+static int asynch_allowed;
+static struct devrequest setup_packet;
+
+char usb_started; /* flag for the started/stopped USB status */
+
+/**********************************************************************
+ * some forward declerations...
+ */
+void usb_scan_devices(void);
+
+int usb_hub_probe(struct usb_device *dev, int ifnum);
+void usb_hub_reset(void);
+static int hub_port_reset(struct usb_device *dev, int port,
+ unsigned short *portstat);
+
+/***********************************************************************
+ * wait_ms
+ */
+
+inline void wait_ms(unsigned long ms)
+{
+ while (ms-- > 0)
+ udelay(1000);
+}
+
+/***************************************************************************
+ * Init USB Device
+ */
+
+int usb_init(void)
+{
+ int result;
+
+ running = 0;
+ dev_index = 0;
+ asynch_allowed = 1;
+ usb_hub_reset();
+ /* init low_level USB */
+ printf("USB: ");
+ result = usb_lowlevel_init();
+ /* if lowlevel init is OK, scan the bus for devices
+ * i.e. search HUBs and configure them */
+ if (result == 0) {
+ printf("scanning bus for devices... ");
+ running = 1;
+ usb_scan_devices();
+ usb_started = 1;
+ return 0;
+ } else {
+ printf("Error, couldn't init Lowlevel part\n");
+ usb_started = 0;
+ return -1;
+ }
+}
+
+/******************************************************************************
+ * Stop USB this stops the LowLevel Part and deregisters USB devices.
+ */
+int usb_stop(void)
+{
+ int res = 0;
+
+ if (usb_started) {
+ asynch_allowed = 1;
+ usb_started = 0;
+ usb_hub_reset();
+ res = usb_lowlevel_stop();
+ }
+ return res;
+}
+
+/*
+ * disables the asynch behaviour of the control message. This is used for data
+ * transfers that uses the exclusiv access to the control and bulk messages.
+ * Returns the old value so it can be restored later.
+ */
+int usb_disable_asynch(int disable)
+{
+ int old_value = asynch_allowed;
+
+ asynch_allowed = !disable;
+ return old_value;
+}
+
+
+/*-------------------------------------------------------------------
+ * Message wrappers.
+ *
+ */
+
+/*
+ * submits an Interrupt Message
+ */
+int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, int interval)
+{
+ return submit_int_msg(dev, pipe, buffer, transfer_len, interval);
+}
+
+/*
+ * submits a control message and waits for comletion (at least timeout * 1ms)
+ * If timeout is 0, we don't wait for completion (used as example to set and
+ * clear keyboards LEDs). For data transfers, (storage transfers) we don't
+ * allow control messages with 0 timeout, by previousely resetting the flag
+ * asynch_allowed (usb_disable_asynch(1)).
+ * returns the transfered length if OK or -1 if error. The transfered length
+ * and the current status are stored in the dev->act_len and dev->status.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+ unsigned char request, unsigned char requesttype,
+ unsigned short value, unsigned short index,
+ void *data, unsigned short size, int timeout)
+{
+ if ((timeout == 0) && (!asynch_allowed)) {
+ /* request for a asynch control pipe is not allowed */
+ return -1;
+ }
+
+ /* set setup command */
+ setup_packet.requesttype = requesttype;
+ setup_packet.request = request;
+ setup_packet.value = cpu_to_le16(value);
+ setup_packet.index = cpu_to_le16(index);
+ setup_packet.length = cpu_to_le16(size);
+ USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
+ "value 0x%X index 0x%X length 0x%X\n",
+ request, requesttype, value, index, size);
+ dev->status = USB_ST_NOT_PROC; /*not yet processed */
+
+ submit_control_msg(dev, pipe, data, size, &setup_packet);
+ if (timeout == 0)
+ return (int)size;
+
+ /*
+ * Wait for status to update until timeout expires, USB driver
+ * interrupt handler may set the status when the USB operation has
+ * been completed.
+ */
+ while (timeout--) {
+ if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ wait_ms(1);
+ }
+ if (dev->status)
+ return -1;
+
+ return dev->act_len;
+
+}
+
+/*-------------------------------------------------------------------
+ * submits bulk message, and waits for completion. returns 0 if Ok or
+ * -1 if Error.
+ * synchronous behavior
+ */
+int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ if (len < 0)
+ return -1;
+ dev->status = USB_ST_NOT_PROC; /*not yet processed */
+ submit_bulk_msg(dev, pipe, data, len);
+ while (timeout--) {
+ if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ wait_ms(1);
+ }
+ *actual_length = dev->act_len;
+ if (dev->status == 0)
+ return 0;
+ else
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------
+ * Max Packet stuff
+ */
+
+/*
+ * returns the max packet size, depending on the pipe direction and
+ * the configurations values
+ */
+int usb_maxpacket(struct usb_device *dev, unsigned long pipe)
+{
+ /* direction is out -> use emaxpacket out */
+ if ((pipe & USB_DIR_IN) == 0)
+ return dev->epmaxpacketout[((pipe>>15) & 0xf)];
+ else
+ return dev->epmaxpacketin[((pipe>>15) & 0xf)];
+}
+
+/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine
+ * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine
+ * when it is inlined in 1 single routine. What happens is that the register r3
+ * is used as loop-count 'i', but gets overwritten later on.
+ * This is clearly a compiler bug, but it is easier to workaround it here than
+ * to update the compiler (Occurs with at least several GCC 4.{1,2},x
+ * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM)
+ */
+static void __attribute__((noinline))
+usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep)
+{
+ int b;
+
+ b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) {
+ /* Control => bidirectional */
+ dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+ dev->epmaxpacketin[b] = ep->wMaxPacketSize;
+ USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",
+ b, dev->epmaxpacketin[b]);
+ } else {
+ if ((ep->bEndpointAddress & 0x80) == 0) {
+ /* OUT Endpoint */
+ if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
+ dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+ USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",
+ b, dev->epmaxpacketout[b]);
+ }
+ } else {
+ /* IN Endpoint */
+ if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
+ dev->epmaxpacketin[b] = ep->wMaxPacketSize;
+ USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",
+ b, dev->epmaxpacketin[b]);
+ }
+ } /* if out */
+ } /* if control */
+}
+
+/*
+ * set the max packed value of all endpoints in the given configuration
+ */
+int usb_set_maxpacket(struct usb_device *dev)
+{
+ int i, ii;
+
+ for (i = 0; i < dev->config.desc.bNumInterfaces; i++)
+ for (ii = 0; ii < dev->config.if_desc[i].desc.bNumEndpoints; ii++)
+ usb_set_maxpacket_ep(dev,
+ &dev->config.if_desc[i].ep_desc[ii]);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Parse the config, located in buffer, and fills the dev->config structure.
+ * Note that all little/big endian swapping are done automatically.
+ */
+int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno)
+{
+ struct usb_descriptor_header *head;
+ int index, ifno, epno, curr_if_num;
+ int i;
+ unsigned char *ch;
+
+ ifno = -1;
+ epno = -1;
+ curr_if_num = -1;
+
+ dev->configno = cfgno;
+ head = (struct usb_descriptor_header *) &buffer[0];
+ if (head->bDescriptorType != USB_DT_CONFIG) {
+ printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
+ head->bDescriptorType);
+ return -1;
+ }
+ memcpy(&dev->config, buffer, buffer[0]);
+ le16_to_cpus(&(dev->config.desc.wTotalLength));
+ dev->config.no_of_if = 0;
+
+ index = dev->config.desc.bLength;
+ /* Ok the first entry must be a configuration entry,
+ * now process the others */
+ head = (struct usb_descriptor_header *) &buffer[index];
+ while (index + 1 < dev->config.desc.wTotalLength) {
+ switch (head->bDescriptorType) {
+ case USB_DT_INTERFACE:
+ if (((struct usb_interface_descriptor *) \
+ &buffer[index])->bInterfaceNumber != curr_if_num) {
+ /* this is a new interface, copy new desc */
+ ifno = dev->config.no_of_if;
+ dev->config.no_of_if++;
+ memcpy(&dev->config.if_desc[ifno],
+ &buffer[index], buffer[index]);
+ dev->config.if_desc[ifno].no_of_ep = 0;
+ dev->config.if_desc[ifno].num_altsetting = 1;
+ curr_if_num =
+ dev->config.if_desc[ifno].desc.bInterfaceNumber;
+ } else {
+ /* found alternate setting for the interface */
+ dev->config.if_desc[ifno].num_altsetting++;
+ }
+ break;
+ case USB_DT_ENDPOINT:
+ epno = dev->config.if_desc[ifno].no_of_ep;
+ /* found an endpoint */
+ dev->config.if_desc[ifno].no_of_ep++;
+ memcpy(&dev->config.if_desc[ifno].ep_desc[epno],
+ &buffer[index], buffer[index]);
+ le16_to_cpus(&(dev->config.if_desc[ifno].ep_desc[epno].\
+ wMaxPacketSize));
+ USB_PRINTF("if %d, ep %d\n", ifno, epno);
+ break;
+ default:
+ if (head->bLength == 0)
+ return 1;
+
+ USB_PRINTF("unknown Description Type : %x\n",
+ head->bDescriptorType);
+
+ {
+ ch = (unsigned char *)head;
+ for (i = 0; i < head->bLength; i++)
+ USB_PRINTF("%02X ", *ch++);
+ USB_PRINTF("\n\n\n");
+ }
+ break;
+ }
+ index += head->bLength;
+ head = (struct usb_descriptor_header *)&buffer[index];
+ }
+ return 1;
+}
+
+/***********************************************************************
+ * Clears an endpoint
+ * endp: endpoint number in bits 0-3;
+ * direction flag in bit 7 (1 = IN, 0 = OUT)
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
+
+ /* don't clear if failed */
+ if (result < 0)
+ return result;
+
+ /*
+ * NOTE: we do not get status and verify reset was successful
+ * as some devices are reported to lock up upon this check..
+ */
+
+ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+ /* toggle is reset on clear */
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+ return 0;
+}
+
+
+/**********************************************************************
+ * get_descriptor type
+ */
+int usb_get_descriptor(struct usb_device *dev, unsigned char type,
+ unsigned char index, void *buf, int size)
+{
+ int res;
+ res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (type << 8) + index, 0,
+ buf, size, USB_CNTL_TIMEOUT);
+ return res;
+}
+
+/**********************************************************************
+ * gets configuration cfgno and store it in the buffer
+ */
+int usb_get_configuration_no(struct usb_device *dev,
+ unsigned char *buffer, int cfgno)
+{
+ int result;
+ unsigned int tmp;
+ struct usb_configuration_descriptor *config;
+
+ config = (struct usb_configuration_descriptor *)&buffer[0];
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);
+ if (result < 9) {
+ if (result < 0)
+ printf("unable to get descriptor, error %lX\n",
+ dev->status);
+ else
+ printf("config descriptor too short " \
+ "(expected %i, got %i)\n", 9, result);
+ return -1;
+ }
+ tmp = le16_to_cpu(config->wTotalLength);
+
+ if (tmp > USB_BUFSIZ) {
+ USB_PRINTF("usb_get_configuration_no: failed to get " \
+ "descriptor - too long: %d\n", tmp);
+ return -1;
+ }
+
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp);
+ USB_PRINTF("get_conf_no %d Result %d, wLength %d\n",
+ cfgno, result, tmp);
+ return result;
+}
+
+/********************************************************************
+ * set address of a device to the value in dev->devnum.
+ * This can only be done by addressing the device via the default address (0)
+ */
+int usb_set_address(struct usb_device *dev)
+{
+ int res;
+
+ USB_PRINTF("set address %d\n", dev->devnum);
+ res = usb_control_msg(dev, usb_snddefctrl(dev),
+ USB_REQ_SET_ADDRESS, 0,
+ (dev->devnum), 0,
+ NULL, 0, USB_CNTL_TIMEOUT);
+ return res;
+}
+
+/********************************************************************
+ * set interface number to interface
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+ struct usb_interface *if_face = NULL;
+ int ret, i;
+
+ for (i = 0; i < dev->config.desc.bNumInterfaces; i++) {
+ if (dev->config.if_desc[i].desc.bInterfaceNumber == interface) {
+ if_face = &dev->config.if_desc[i];
+ break;
+ }
+ }
+ if (!if_face) {
+ printf("selecting invalid interface %d", interface);
+ return -1;
+ }
+ /*
+ * We should return now for devices with only one alternate setting.
+ * According to 9.4.10 of the Universal Serial Bus Specification
+ * Revision 2.0 such devices can return with a STALL. This results in
+ * some USB sticks timeouting during initialization and then being
+ * unusable in U-Boot.
+ */
+ if (if_face->num_altsetting == 1)
+ return 0;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
+ alternate, interface, NULL, 0,
+ USB_CNTL_TIMEOUT * 5);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/********************************************************************
+ * set configuration number to configuration
+ */
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+ int res;
+ USB_PRINTF("set configuration %d\n", configuration);
+ /* set setup command */
+ res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ configuration, 0,
+ NULL, 0, USB_CNTL_TIMEOUT);
+ if (res == 0) {
+ dev->toggle[0] = 0;
+ dev->toggle[1] = 0;
+ return 0;
+ } else
+ return -1;
+}
+
+/********************************************************************
+ * set protocol to protocol
+ */
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * set idle
+ */
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get report
+ */
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get class descriptor
+ */
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+ unsigned char type, unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get string index in buffer
+ */
+int usb_get_string(struct usb_device *dev, unsigned short langid,
+ unsigned char index, void *buf, int size)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < 3; ++i) {
+ /* some devices are flaky */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid, buf, size,
+ USB_CNTL_TIMEOUT);
+
+ if (result > 0)
+ break;
+ }
+
+ return result;
+}
+
+
+static void usb_try_string_workarounds(unsigned char *buf, int *length)
+{
+ int newlength, oldlength = *length;
+
+ for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
+ if (!isprint(buf[newlength]) || buf[newlength + 1])
+ break;
+
+ if (newlength > 2) {
+ buf[0] = newlength;
+ *length = newlength;
+ }
+}
+
+
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+ unsigned int index, unsigned char *buf)
+{
+ int rc;
+
+ /* Try to read the string descriptor by asking for the maximum
+ * possible number of bytes */
+ rc = usb_get_string(dev, langid, index, buf, 255);
+
+ /* If that failed try to read the descriptor length, then
+ * ask for just that many bytes */
+ if (rc < 2) {
+ rc = usb_get_string(dev, langid, index, buf, 2);
+ if (rc == 2)
+ rc = usb_get_string(dev, langid, index, buf, buf[0]);
+ }
+
+ if (rc >= 2) {
+ if (!buf[0] && !buf[1])
+ usb_try_string_workarounds(buf, &rc);
+
+ /* There might be extra junk at the end of the descriptor */
+ if (buf[0] < rc)
+ rc = buf[0];
+
+ rc = rc - (rc & 1); /* force a multiple of two */
+ }
+
+ if (rc < 2)
+ rc = -1;
+
+ return rc;
+}
+
+
+/********************************************************************
+ * usb_string:
+ * Get string index and translate it to ascii.
+ * returns string length (> 0) or error (< 0)
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+ unsigned char mybuf[USB_BUFSIZ];
+ unsigned char *tbuf;
+ int err;
+ unsigned int u, idx;
+
+ if (size <= 0 || !buf || !index)
+ return -1;
+ buf[0] = 0;
+ tbuf = &mybuf[0];
+
+ /* get langid for strings if it's not yet known */
+ if (!dev->have_langid) {
+ err = usb_string_sub(dev, 0, 0, tbuf);
+ if (err < 0) {
+ USB_PRINTF("error getting string descriptor 0 " \
+ "(error=%lx)\n", dev->status);
+ return -1;
+ } else if (tbuf[0] < 4) {
+ USB_PRINTF("string descriptor 0 too short\n");
+ return -1;
+ } else {
+ dev->have_langid = -1;
+ dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+ /* always use the first langid listed */
+ USB_PRINTF("USB device number %d default " \
+ "language ID 0x%x\n",
+ dev->devnum, dev->string_langid);
+ }
+ }
+
+ err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+ if (err < 0)
+ return err;
+
+ size--; /* leave room for trailing NULL char in output buffer */
+ for (idx = 0, u = 2; u < err; u += 2) {
+ if (idx >= size)
+ break;
+ if (tbuf[u+1]) /* high byte */
+ buf[idx++] = '?'; /* non-ASCII character */
+ else
+ buf[idx++] = tbuf[u];
+ }
+ buf[idx] = 0;
+ err = idx;
+ return err;
+}
+
+
+/********************************************************************
+ * USB device handling:
+ * the USB device are static allocated [USB_MAX_DEVICE].
+ */
+
+
+/* returns a pointer to the device with the index [index].
+ * if the device is not assigned (dev->devnum==-1) returns NULL
+ */
+struct usb_device *usb_get_dev_index(int index)
+{
+ if (usb_dev[index].devnum == -1)
+ return NULL;
+ else
+ return &usb_dev[index];
+}
+
+
+/* returns a pointer of a new device structure or NULL, if
+ * no device struct is available
+ */
+struct usb_device *usb_alloc_new_device(void)
+{
+ int i;
+ USB_PRINTF("New Device %d\n", dev_index);
+ if (dev_index == USB_MAX_DEVICE) {
+ printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
+ return NULL;
+ }
+ /* default Address is 0, real addresses start with 1 */
+ usb_dev[dev_index].devnum = dev_index + 1;
+ usb_dev[dev_index].maxchild = 0;
+ for (i = 0; i < USB_MAXCHILDREN; i++)
+ usb_dev[dev_index].children[i] = NULL;
+ usb_dev[dev_index].parent = NULL;
+ dev_index++;
+ return &usb_dev[dev_index - 1];
+}
+
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+ int addr, err;
+ int tmp;
+ unsigned char tmpbuf[USB_BUFSIZ];
+
+ /* We still haven't set the Address yet */
+ addr = dev->devnum;
+ dev->devnum = 0;
+
+#ifdef CONFIG_LEGACY_USB_INIT_SEQ
+ /* this is the old and known way of initializing devices, it is
+ * different than what Windows and Linux are doing. Windows and Linux
+ * both retrieve 64 bytes while reading the device descriptor
+ * Several USB stick devices report ERR: CTL_TIMEOUT, caused by an
+ * invalid header while reading 8 bytes as device descriptor. */
+ dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */
+ dev->maxpacketsize = PACKET_SIZE_8;
+ dev->epmaxpacketin[0] = 8;
+ dev->epmaxpacketout[0] = 8;
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+ if (err < 8) {
+ printf("\n USB device not responding, " \
+ "giving up (status=%lX)\n", dev->status);
+ return 1;
+ }
+#else
+ /* This is a Windows scheme of initialization sequence, with double
+ * reset of the device (Linux uses the same sequence)
+ * Some equipment is said to work only with such init sequence; this
+ * patch is based on the work by Alan Stern:
+ * http://sourceforge.net/mailarchive/forum.php?
+ * thread_id=5729457&forum_id=5398
+ */
+ struct usb_device_descriptor *desc;
+ int port = -1;
+ struct usb_device *parent = dev->parent;
+ unsigned short portstatus;
+
+ /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
+ * only 18 bytes long, this will terminate with a short packet. But if
+ * the maxpacket size is 8 or 16 the device may be waiting to transmit
+ * some more, or keeps on retransmitting the 8 byte header. */
+
+ desc = (struct usb_device_descriptor *)tmpbuf;
+ dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */
+ /* Default to 64 byte max packet size */
+ dev->maxpacketsize = PACKET_SIZE_64;
+ dev->epmaxpacketin[0] = 64;
+ dev->epmaxpacketout[0] = 64;
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
+ if (err < 0) {
+ USB_PRINTF("usb_new_device: usb_get_descriptor() failed\n");
+ return 1;
+ }
+
+ dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0;
+
+ /* find the port number we're at */
+ if (parent) {
+ int j;
+
+ for (j = 0; j < parent->maxchild; j++) {
+ if (parent->children[j] == dev) {
+ port = j;
+ break;
+ }
+ }
+ if (port < 0) {
+ printf("usb_new_device:cannot locate device's port.\n");
+ return 1;
+ }
+
+ /* reset the port for the second time */
+ err = hub_port_reset(dev->parent, port, &portstatus);
+ if (err < 0) {
+ printf("\n Couldn't reset port %i\n", port);
+ return 1;
+ }
+ }
+#endif
+
+ dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+ switch (dev->descriptor.bMaxPacketSize0) {
+ case 8:
+ dev->maxpacketsize = PACKET_SIZE_8;
+ break;
+ case 16:
+ dev->maxpacketsize = PACKET_SIZE_16;
+ break;
+ case 32:
+ dev->maxpacketsize = PACKET_SIZE_32;
+ break;
+ case 64:
+ dev->maxpacketsize = PACKET_SIZE_64;
+ break;
+ }
+ dev->devnum = addr;
+
+ err = usb_set_address(dev); /* set address */
+
+ if (err < 0) {
+ printf("\n USB device not accepting new address " \
+ "(error=%lX)\n", dev->status);
+ return 1;
+ }
+
+ wait_ms(10); /* Let the SET_ADDRESS settle */
+
+ tmp = sizeof(dev->descriptor);
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
+ &dev->descriptor, sizeof(dev->descriptor));
+ if (err < tmp) {
+ if (err < 0)
+ printf("unable to get device descriptor (error=%d)\n",
+ err);
+ else
+ printf("USB device descriptor short read " \
+ "(expected %i, got %i)\n", tmp, err);
+ return 1;
+ }
+ /* correct le values */
+ le16_to_cpus(&dev->descriptor.bcdUSB);
+ le16_to_cpus(&dev->descriptor.idVendor);
+ le16_to_cpus(&dev->descriptor.idProduct);
+ le16_to_cpus(&dev->descriptor.bcdDevice);
+ /* only support for one config for now */
+ usb_get_configuration_no(dev, &tmpbuf[0], 0);
+ usb_parse_config(dev, &tmpbuf[0], 0);
+ usb_set_maxpacket(dev);
+ /* we set the default configuration here */
+ if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) {
+ printf("failed to set default configuration " \
+ "len %d, status %lX\n", dev->act_len, dev->status);
+ return -1;
+ }
+ USB_PRINTF("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ dev->descriptor.iManufacturer, dev->descriptor.iProduct,
+ dev->descriptor.iSerialNumber);
+ memset(dev->mf, 0, sizeof(dev->mf));
+ memset(dev->prod, 0, sizeof(dev->prod));
+ memset(dev->serial, 0, sizeof(dev->serial));
+ if (dev->descriptor.iManufacturer)
+ usb_string(dev, dev->descriptor.iManufacturer,
+ dev->mf, sizeof(dev->mf));
+ if (dev->descriptor.iProduct)
+ usb_string(dev, dev->descriptor.iProduct,
+ dev->prod, sizeof(dev->prod));
+ if (dev->descriptor.iSerialNumber)
+ usb_string(dev, dev->descriptor.iSerialNumber,
+ dev->serial, sizeof(dev->serial));
+ USB_PRINTF("Manufacturer %s\n", dev->mf);
+ USB_PRINTF("Product %s\n", dev->prod);
+ USB_PRINTF("SerialNumber %s\n", dev->serial);
+ /* now prode if the device is a hub */
+ usb_hub_probe(dev, 0);
+ return 0;
+}
+
+/* build device Tree */
+void usb_scan_devices(void)
+{
+ int i;
+ struct usb_device *dev;
+
+ /* first make all devices unknown */
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ memset(&usb_dev[i], 0, sizeof(struct usb_device));
+ usb_dev[i].devnum = -1;
+ }
+ dev_index = 0;
+ /* device 0 is always present (root hub, so let it analyze) */
+ dev = usb_alloc_new_device();
+ if (usb_new_device(dev))
+ printf("No USB Device found\n");
+ else
+ printf("%d USB Device(s) found\n", dev_index);
+ /* insert "driver" if possible */
+#ifdef CONFIG_USB_KEYBOARD
+ drv_usb_kbd_init();
+ USB_PRINTF("scan end\n");
+#endif
+}
+
+
+/****************************************************************************
+ * HUB "Driver"
+ * Probes device for being a hub and configurate it
+ */
+
+#ifdef USB_HUB_DEBUG
+#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args)
+#else
+#define USB_HUB_PRINTF(fmt, args...)
+#endif
+
+
+static struct usb_hub_device hub_dev[USB_MAX_HUB];
+static int usb_hub_index;
+
+
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+ USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_hub_feature(struct usb_device *dev, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature,
+ 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+
+static void usb_hub_power_on(struct usb_hub_device *hub)
+{
+ int i;
+ struct usb_device *dev;
+
+ dev = hub->pusb_dev;
+ /* Enable power to the ports */
+ USB_HUB_PRINTF("enabling power on all ports\n");
+ for (i = 0; i < dev->maxchild; i++) {
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status);
+ wait_ms(hub->desc.bPwrOn2PwrGood * 2);
+ }
+}
+
+void usb_hub_reset(void)
+{
+ usb_hub_index = 0;
+}
+
+struct usb_hub_device *usb_hub_allocate(void)
+{
+ if (usb_hub_index < USB_MAX_HUB)
+ return &hub_dev[usb_hub_index++];
+
+ printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB);
+ return NULL;
+}
+
+#define MAX_TRIES 5
+
+static inline char *portspeed(int portstatus)
+{
+ if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+ return "480 Mb/s";
+ else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
+static int hub_port_reset(struct usb_device *dev, int port,
+ unsigned short *portstat)
+{
+ int tries;
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+
+ usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
+ wait_ms(200);
+
+ if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed status %lX\n",
+ dev->status);
+ return -1;
+ }
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ portstatus, portchange,
+ portspeed(portstatus));
+
+ USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
+ " USB_PORT_STAT_ENABLE %d\n",
+ (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
+
+ if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+ !(portstatus & USB_PORT_STAT_CONNECTION))
+ return -1;
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ break;
+
+ wait_ms(200);
+ }
+
+ if (tries == MAX_TRIES) {
+ USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \
+ "disabling port.\n", port + 1, MAX_TRIES);
+ USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
+ return -1;
+ }
+
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
+ *portstat = portstatus;
+ return 0;
+}
+
+
+void usb_hub_port_connect_change(struct usb_device *dev, int port)
+{
+ struct usb_device *usb;
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ /* Check status */
+ if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ return;
+ }
+
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ portstatus, portchange, portspeed(portstatus));
+
+ /* Clear the connection change status */
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+ /* Disconnect any existing devices under this port */
+ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+ (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
+ USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
+ /* Return now if nothing is connected */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return;
+ }
+ wait_ms(200);
+
+ /* Reset the port */
+ if (hub_port_reset(dev, port, &portstatus) < 0) {
+ printf("cannot reset port %i!?\n", port + 1);
+ return;
+ }
+
+ wait_ms(200);
+
+ /* Allocate a new device struct for it */
+ usb = usb_alloc_new_device();
+
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ usb->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ usb->speed = USB_SPEED_LOW;
+ else
+ usb->speed = USB_SPEED_FULL;
+
+ dev->children[port] = usb;
+ usb->parent = dev;
+ /* Run it through the hoops (find a driver, etc) */
+ if (usb_new_device(usb)) {
+ /* Woops, disable the port */
+ USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+ }
+}
+
+
+int usb_hub_configure(struct usb_device *dev)
+{
+ unsigned char buffer[USB_BUFSIZ], *bitmap;
+ struct usb_hub_descriptor *descriptor;
+ struct usb_hub_status *hubsts;
+ int i;
+ struct usb_hub_device *hub;
+
+ /* "allocate" Hub device */
+ hub = usb_hub_allocate();
+ if (hub == NULL)
+ return -1;
+ hub->pusb_dev = dev;
+ /* Get the the hub descriptor */
+ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \
+ "descriptor, giving up %lX\n", dev->status);
+ return -1;
+ }
+ descriptor = (struct usb_hub_descriptor *)buffer;
+
+ /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */
+ i = descriptor->bLength;
+ if (i > USB_BUFSIZ) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \
+ "descriptor - too long: %d\n",
+ descriptor->bLength);
+ return -1;
+ }
+
+ if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \
+ "descriptor 2nd giving up %lX\n", dev->status);
+ return -1;
+ }
+ memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength);
+ /* adjust 16bit values */
+ hub->desc.wHubCharacteristics =
+ le16_to_cpu(descriptor->wHubCharacteristics);
+ /* set the bitmap */
+ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0];
+ /* devices not removable by default */
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8);
+ bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0];
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i];
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i];
+
+ dev->maxchild = descriptor->bNbrPorts;
+ USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
+ case 0x00:
+ USB_HUB_PRINTF("ganged power switching\n");
+ break;
+ case 0x01:
+ USB_HUB_PRINTF("individual port power switching\n");
+ break;
+ case 0x02:
+ case 0x03:
+ USB_HUB_PRINTF("unknown reserved power switching mode\n");
+ break;
+ }
+
+ if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
+ USB_HUB_PRINTF("part of a compound device\n");
+ else
+ USB_HUB_PRINTF("standalone hub\n");
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
+ case 0x00:
+ USB_HUB_PRINTF("global over-current protection\n");
+ break;
+ case 0x08:
+ USB_HUB_PRINTF("individual port over-current protection\n");
+ break;
+ case 0x10:
+ case 0x18:
+ USB_HUB_PRINTF("no over-current protection\n");
+ break;
+ }
+
+ USB_HUB_PRINTF("power on to power good time: %dms\n",
+ descriptor->bPwrOn2PwrGood * 2);
+ USB_HUB_PRINTF("hub controller current requirement: %dmA\n",
+ descriptor->bHubContrCurrent);
+
+ for (i = 0; i < dev->maxchild; i++)
+ USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
+ hub->desc.DeviceRemovable[(i + 1) / 8] & \
+ (1 << ((i + 1) % 8)) ? " not" : "");
+
+ if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get Status - " \
+ "too long: %d\n", descriptor->bLength);
+ return -1;
+ }
+
+ if (usb_get_hub_status(dev, buffer) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
+ dev->status);
+ return -1;
+ }
+
+ hubsts = (struct usb_hub_status *)buffer;
+ USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
+ le16_to_cpu(hubsts->wHubStatus),
+ le16_to_cpu(hubsts->wHubChange));
+ USB_HUB_PRINTF("local power source is %s\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \
+ "lost (inactive)" : "good");
+ USB_HUB_PRINTF("%sover-current condition exists\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
+ "" : "no ");
+ usb_hub_power_on(hub);
+
+ for (i = 0; i < dev->maxchild; i++) {
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ continue;
+ }
+
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+ USB_HUB_PRINTF("Port %d Status %X Change %X\n",
+ i + 1, portstatus, portchange);
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ USB_HUB_PRINTF("port %d connection change\n", i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ USB_HUB_PRINTF("port %d enable change, status %x\n",
+ i + 1, portstatus);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_ENABLE);
+
+ /* EM interference sometimes causes bad shielded USB
+ * devices to be shutdown by the hub, this hack enables
+ * them again. Works at least with mouse driver */
+ if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) &&
+ ((dev->children[i]))) {
+ USB_HUB_PRINTF("already running port %i " \
+ "disabled by hub (EMI?), " \
+ "re-enabling...\n", i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ }
+ if (portstatus & USB_PORT_STAT_SUSPEND) {
+ USB_HUB_PRINTF("port %d suspend change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_SUSPEND);
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ USB_HUB_PRINTF("port %d over-current change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ usb_hub_power_on(hub);
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ USB_HUB_PRINTF("port %d reset change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_RESET);
+ }
+ } /* end for i all ports */
+
+ return 0;
+}
+
+int usb_hub_probe(struct usb_device *dev, int ifnum)
+{
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ int ret;
+
+ iface = &dev->config.if_desc[ifnum];
+ /* Is it a hub? */
+ if (iface->desc.bInterfaceClass != USB_CLASS_HUB)
+ return 0;
+ /* Some hubs have a subclass of 1, which AFAICT according to the */
+ /* specs is not defined, but it works */
+ if ((iface->desc.bInterfaceSubClass != 0) &&
+ (iface->desc.bInterfaceSubClass != 1))
+ return 0;
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (iface->desc.bNumEndpoints != 1)
+ return 0;
+ ep = &iface->ep_desc[0];
+ /* Output endpoint? Curiousier and curiousier.. */
+ if (!(ep->bEndpointAddress & USB_DIR_IN))
+ return 0;
+ /* If it's not an interrupt endpoint, we'd better punt! */
+ if ((ep->bmAttributes & 3) != 3)
+ return 0;
+ /* We found a hub */
+ USB_HUB_PRINTF("USB hub found\n");
+ ret = usb_hub_configure(dev);
+ return ret;
+}
+
+/* EOF */
diff --git a/u-boot/common/usb_kbd.c b/u-boot/common/usb_kbd.c
new file mode 100644
index 0000000..9957dcc
--- /dev/null
+++ b/u-boot/common/usb_kbd.c
@@ -0,0 +1,756 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Part of this source has been derived from the Linux USB
+ * project.
+ *
+ * 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 <stdio_dev.h>
+#include <asm/byteorder.h>
+
+#include <usb.h>
+
+#undef USB_KBD_DEBUG
+/*
+ * if overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+ return (0);
+}
+#endif
+
+#ifdef USB_KBD_DEBUG
+#define USB_KBD_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_KBD_PRINTF(fmt,args...)
+#endif
+
+
+#define REPEAT_RATE 40/4 /* 40msec -> 25cps */
+#define REPEAT_DELAY 10 /* 10 x REAPEAT_RATE = 400msec */
+
+#define NUM_LOCK 0x53
+#define CAPS_LOCK 0x39
+#define SCROLL_LOCK 0x47
+
+
+/* Modifier bits */
+#define LEFT_CNTR 0
+#define LEFT_SHIFT 1
+#define LEFT_ALT 2
+#define LEFT_GUI 3
+#define RIGHT_CNTR 4
+#define RIGHT_SHIFT 5
+#define RIGHT_ALT 6
+#define RIGHT_GUI 7
+
+#define USB_KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
+
+static volatile char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
+static volatile int usb_in_pointer = 0;
+static volatile int usb_out_pointer = 0;
+
+unsigned char new[8];
+unsigned char old[8];
+int repeat_delay;
+#define DEVNAME "usbkbd"
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+static unsigned char ctrl = 0;
+
+static unsigned char leds __attribute__ ((aligned (0x4)));
+
+static unsigned char usb_kbd_numkey[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0','\r',0x1b,'\b','\t',' ', '-',
+ '=', '[', ']','\\', '#', ';', '\'', '`', ',', '.', '/'
+};
+static unsigned char usb_kbd_numkey_shifted[] = {
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')','\r',0x1b,'\b','\t',' ', '_',
+ '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'
+};
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+static void usb_kbd_put_queue(char data)
+{
+ if((usb_in_pointer+1)==USB_KBD_BUFFER_LEN) {
+ if(usb_out_pointer==0) {
+ return; /* buffer full */
+ } else{
+ usb_in_pointer=0;
+ }
+ } else {
+ if((usb_in_pointer+1)==usb_out_pointer)
+ return; /* buffer full */
+ usb_in_pointer++;
+ }
+ usb_kbd_buffer[usb_in_pointer]=data;
+ return;
+}
+
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+ usb_event_poll();
+#endif
+ if(usb_in_pointer==usb_out_pointer)
+ return(0); /* no data */
+ else
+ return(1);
+}
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+ char c;
+ while(usb_in_pointer==usb_out_pointer) {
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+ usb_event_poll();
+#endif
+ }
+ if((usb_out_pointer+1)==USB_KBD_BUFFER_LEN)
+ usb_out_pointer=0;
+ else
+ usb_out_pointer++;
+ c=usb_kbd_buffer[usb_out_pointer];
+ return (int)c;
+
+}
+
+/* forward decleration */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+
+/* search for keyboard and register it if found */
+int drv_usb_kbd_init(void)
+{
+ int error,i;
+ struct stdio_dev usb_kbd_dev,*old_dev;
+ struct usb_device *dev;
+ char *stdinname = getenv ("stdin");
+
+ usb_in_pointer=0;
+ usb_out_pointer=0;
+ /* scan all USB Devices */
+ for(i=0;i<USB_MAX_DEVICE;i++) {
+ dev=usb_get_dev_index(i); /* get device */
+ if(dev == NULL)
+ return -1;
+ if(dev->devnum!=-1) {
+ if(usb_kbd_probe(dev,0)==1) { /* Ok, we found a keyboard */
+ /* check, if it is already registered */
+ USB_KBD_PRINTF("USB KBD found set up device.\n");
+ old_dev = stdio_get_by_name(DEVNAME);
+ if(old_dev) {
+ /* ok, already registered, just return ok */
+ USB_KBD_PRINTF("USB KBD is already registered.\n");
+ return 1;
+ }
+ /* register the keyboard */
+ USB_KBD_PRINTF("USB KBD register.\n");
+ memset (&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+ strcpy(usb_kbd_dev.name, DEVNAME);
+ usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ usb_kbd_dev.putc = NULL;
+ usb_kbd_dev.puts = NULL;
+ usb_kbd_dev.getc = usb_kbd_getc;
+ usb_kbd_dev.tstc = usb_kbd_testc;
+ usb_kbd_dev.priv = (void *)dev;
+ error = stdio_register (&usb_kbd_dev);
+ if(error==0) {
+ /* check if this is the standard input device */
+ if(strcmp(stdinname,DEVNAME)==0) {
+ /* reassign the console */
+ if(overwrite_console()) {
+ return 1;
+ }
+ error=console_assign(stdin,DEVNAME);
+ if(error==0)
+ return 1;
+ else
+ return error;
+ }
+ return 1;
+ }
+ return error;
+ }
+ }
+ }
+ /* no USB Keyboard found */
+ return -1;
+}
+
+
+/* deregistering the keyboard */
+int usb_kbd_deregister(void)
+{
+#ifdef CONFIG_SYS_STDIO_DEREGISTER
+ return stdio_deregister(DEVNAME);
+#else
+ return 1;
+#endif
+}
+
+/**************************************************************************
+ * Low Level drivers
+ */
+
+/* set the LEDs. Since this is used in the irq routine, the control job
+ is issued with a timeout of 0. This means, that the job is queued without
+ waiting for job completion */
+
+static void usb_kbd_setled(struct usb_device *dev)
+{
+ struct usb_interface *iface;
+ iface = &dev->config.if_desc[0];
+ leds=0;
+ if(scroll_lock!=0)
+ leds|=1;
+ leds<<=1;
+ if(caps_lock!=0)
+ leds|=1;
+ leds<<=1;
+ if(num_lock!=0)
+ leds|=1;
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0);
+
+}
+
+
+#define CAPITAL_MASK 0x20
+/* Translate the scancode in ASCII */
+static int usb_kbd_translate(unsigned char scancode,unsigned char modifier,int pressed)
+{
+ unsigned char keycode;
+
+ if(pressed==0) {
+ /* key released */
+ repeat_delay=0;
+ return 0;
+ }
+ if(pressed==2) {
+ repeat_delay++;
+ if(repeat_delay<REPEAT_DELAY)
+ return 0;
+ repeat_delay=REPEAT_DELAY;
+ }
+ keycode=0;
+ if((scancode>3) && (scancode<=0x1d)) { /* alpha numeric values */
+ keycode=scancode-4 + 0x61;
+ if(caps_lock)
+ keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+ if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) {
+ if(keycode & CAPITAL_MASK)
+ keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+ else
+ keycode|=CAPITAL_MASK; /* switch to non capital Letters */
+ }
+ }
+ if((scancode>0x1d) && (scancode<0x3A)) {
+ if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) /* shifted */
+ keycode=usb_kbd_numkey_shifted[scancode-0x1e];
+ else /* non shifted */
+ keycode=usb_kbd_numkey[scancode-0x1e];
+ }
+
+ if (ctrl)
+ keycode = scancode - 0x3;
+
+ if(pressed==1) {
+ if(scancode==NUM_LOCK) {
+ num_lock=~num_lock;
+ return 1;
+ }
+ if(scancode==CAPS_LOCK) {
+ caps_lock=~caps_lock;
+ return 1;
+ }
+ if(scancode==SCROLL_LOCK) {
+ scroll_lock=~scroll_lock;
+ return 1;
+ }
+ }
+ if(keycode!=0) {
+ USB_KBD_PRINTF("%c",keycode);
+ usb_kbd_put_queue(keycode);
+ }
+ return 0;
+}
+
+/* Interrupt service routine */
+static int usb_kbd_irq(struct usb_device *dev)
+{
+ int i,res;
+
+ if((dev->irq_status!=0)||(dev->irq_act_len!=8))
+ {
+ USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",dev->irq_status,dev->irq_act_len);
+ return 1;
+ }
+ res=0;
+
+ switch (new[0]) {
+ case 0x0: /* No combo key pressed */
+ ctrl = 0;
+ break;
+ case 0x01: /* Left Ctrl pressed */
+ case 0x10: /* Right Ctrl pressed */
+ ctrl = 1;
+ break;
+ }
+
+ for (i = 2; i < 8; i++) {
+ if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) {
+ res|=usb_kbd_translate(old[i],new[0],0);
+ }
+ if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) {
+ res|=usb_kbd_translate(new[i],new[0],1);
+ }
+ }
+ if((new[2]>3) && (old[2]==new[2])) /* still pressed */
+ res|=usb_kbd_translate(new[2],new[0],2);
+ if(res==1)
+ usb_kbd_setled(dev);
+ memcpy(&old[0],&new[0], 8);
+ return 1; /* install IRQ Handler again */
+}
+
+/* probes the USB device dev for keyboard type */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe,maxp;
+
+ if (dev->descriptor.bNumConfigurations != 1) return 0;
+ iface = &dev->config.if_desc[ifnum];
+
+ if (iface->desc.bInterfaceClass != 3)
+ return 0;
+ if (iface->desc.bInterfaceSubClass != 1)
+ return 0;
+ if (iface->desc.bInterfaceProtocol != 1)
+ return 0;
+ if (iface->desc.bNumEndpoints != 1)
+ return 0;
+
+ ep = &iface->ep_desc[0];
+
+ if (!(ep->bEndpointAddress & 0x80)) return 0;
+ if ((ep->bmAttributes & 3) != 3) return 0;
+ USB_KBD_PRINTF("USB KBD found set protocol...\n");
+ /* ok, we found a USB Keyboard, install it */
+ /* usb_kbd_get_hid_desc(dev); */
+ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
+ USB_KBD_PRINTF("USB KBD found set idle...\n");
+ usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
+ memset(&new[0], 0, 8);
+ memset(&old[0], 0, 8);
+ repeat_delay=0;
+ pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe);
+ dev->irq_handle=usb_kbd_irq;
+ USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
+ usb_submit_int_msg(dev,pipe,&new[0], maxp > 8 ? 8 : maxp,ep->bInterval);
+ return 1;
+}
+
+
+#if 0
+struct usb_hid_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType; /* 0x21 for HID */
+ unsigned short bcdHID; /* release number */
+ unsigned char bCountryCode;
+ unsigned char bNumDescriptors;
+ unsigned char bReportDescriptorType;
+ unsigned short wDescriptorLength;
+} __attribute__ ((packed));
+
+/*
+ * We parse each description item into this structure. Short items data
+ * values are expanded to 32-bit signed int, long items contain a pointer
+ * into the data area.
+ */
+
+struct hid_item {
+ unsigned char format;
+ unsigned char size;
+ unsigned char type;
+ unsigned char tag;
+ union {
+ unsigned char u8;
+ char s8;
+ unsigned short u16;
+ short s16;
+ unsigned long u32;
+ long s32;
+ unsigned char *longdata;
+ } data;
+};
+
+/*
+ * HID report item format
+ */
+
+#define HID_ITEM_FORMAT_SHORT 0
+#define HID_ITEM_FORMAT_LONG 1
+
+/*
+ * Special tag indicating long items
+ */
+
+#define HID_ITEM_TAG_LONG 15
+
+
+static struct usb_hid_descriptor usb_kbd_hid_desc;
+
+void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
+{
+ printf("USB_HID_DESC:\n");
+ printf(" bLenght 0x%x\n",hid->bLength);
+ printf(" bcdHID 0x%x\n",hid->bcdHID);
+ printf(" bCountryCode %d\n",hid->bCountryCode);
+ printf(" bNumDescriptors 0x%x\n",hid->bNumDescriptors);
+ printf(" bReportDescriptorType 0x%x\n",hid->bReportDescriptorType);
+ printf(" wDescriptorLength 0x%x\n",hid->wDescriptorLength);
+}
+
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static int fetch_item(unsigned char *start,unsigned char *end, struct hid_item *item)
+{
+ if((end - start) > 0) {
+ unsigned char b = *start++;
+ item->type = (b >> 2) & 3;
+ item->tag = (b >> 4) & 15;
+ if (item->tag == HID_ITEM_TAG_LONG) {
+ item->format = HID_ITEM_FORMAT_LONG;
+ if ((end - start) >= 2) {
+ item->size = *start++;
+ item->tag = *start++;
+ if ((end - start) >= item->size) {
+ item->data.longdata = start;
+ start += item->size;
+ return item->size;
+ }
+ }
+ } else {
+ item->format = HID_ITEM_FORMAT_SHORT;
+ item->size = b & 3;
+ switch (item->size) {
+ case 0:
+ return item->size;
+ case 1:
+ if ((end - start) >= 1) {
+ item->data.u8 = *start++;
+ return item->size;
+ }
+ break;
+ case 2:
+ if ((end - start) >= 2) {
+ item->data.u16 = le16_to_cpu((unsigned short *)start);
+ start+=2;
+ return item->size;
+ }
+ case 3:
+ item->size++;
+ if ((end - start) >= 4) {
+ item->data.u32 = le32_to_cpu((unsigned long *)start);
+ start+=4;
+ return item->size;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * HID report descriptor item type (prefix bit 2,3)
+ */
+
+#define HID_ITEM_TYPE_MAIN 0
+#define HID_ITEM_TYPE_GLOBAL 1
+#define HID_ITEM_TYPE_LOCAL 2
+#define HID_ITEM_TYPE_RESERVED 3
+/*
+ * HID report descriptor main item tags
+ */
+
+#define HID_MAIN_ITEM_TAG_INPUT 8
+#define HID_MAIN_ITEM_TAG_OUTPUT 9
+#define HID_MAIN_ITEM_TAG_FEATURE 11
+#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
+#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
+/*
+ * HID report descriptor main item contents
+ */
+
+#define HID_MAIN_ITEM_CONSTANT 0x001
+#define HID_MAIN_ITEM_VARIABLE 0x002
+#define HID_MAIN_ITEM_RELATIVE 0x004
+#define HID_MAIN_ITEM_WRAP 0x008
+#define HID_MAIN_ITEM_NONLINEAR 0x010
+#define HID_MAIN_ITEM_NO_PREFERRED 0x020
+#define HID_MAIN_ITEM_NULL_STATE 0x040
+#define HID_MAIN_ITEM_VOLATILE 0x080
+#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100
+
+/*
+ * HID report descriptor collection item types
+ */
+
+#define HID_COLLECTION_PHYSICAL 0
+#define HID_COLLECTION_APPLICATION 1
+#define HID_COLLECTION_LOGICAL 2
+/*
+ * HID report descriptor global item tags
+ */
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5
+#define HID_GLOBAL_ITEM_TAG_UNIT 6
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9
+#define HID_GLOBAL_ITEM_TAG_PUSH 10
+#define HID_GLOBAL_ITEM_TAG_POP 11
+
+/*
+ * HID report descriptor local item tags
+ */
+
+#define HID_LOCAL_ITEM_TAG_USAGE 0
+#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1
+#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7
+#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8
+#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9
+#define HID_LOCAL_ITEM_TAG_DELIMITER 10
+
+
+static void usb_kbd_show_item(struct hid_item *item)
+{
+ switch(item->type) {
+ case HID_ITEM_TYPE_MAIN:
+ switch(item->tag) {
+ case HID_MAIN_ITEM_TAG_INPUT:
+ printf("Main Input");
+ break;
+ case HID_MAIN_ITEM_TAG_OUTPUT:
+ printf("Main Output");
+ break;
+ case HID_MAIN_ITEM_TAG_FEATURE:
+ printf("Main Feature");
+ break;
+ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+ printf("Main Begin Collection");
+ break;
+ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+ printf("Main End Collection");
+ break;
+ default:
+ printf("Main reserved %d",item->tag);
+ break;
+ }
+ break;
+ case HID_ITEM_TYPE_GLOBAL:
+ switch(item->tag) {
+ case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+ printf("- Global Usage Page");
+ break;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+ printf("- Global Logical Minimum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+ printf("- Global Logical Maximum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+ printf("- Global physical Minimum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+ printf("- Global physical Maximum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+ printf("- Global Unit Exponent");
+ break;
+ case HID_GLOBAL_ITEM_TAG_UNIT:
+ printf("- Global Unit");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+ printf("- Global Report Size");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+ printf("- Global Report ID");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+ printf("- Global Report Count");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PUSH:
+ printf("- Global Push");
+ break;
+ case HID_GLOBAL_ITEM_TAG_POP:
+ printf("- Global Pop");
+ break;
+ default:
+ printf("- Global reserved %d",item->tag);
+ break;
+ }
+ break;
+ case HID_ITEM_TYPE_LOCAL:
+ switch(item->tag) {
+ case HID_LOCAL_ITEM_TAG_USAGE:
+ printf("-- Local Usage");
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ printf("-- Local Usage Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ printf("-- Local Usage Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
+ printf("-- Local Designator Index");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
+ printf("-- Local Designator Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
+ printf("-- Local Designator Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_INDEX:
+ printf("-- Local String Index");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
+ printf("-- Local String Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
+ printf("-- Local String Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+ printf("-- Local Delimiter");
+ break;
+ default:
+ printf("-- Local reserved %d",item->tag);
+ break;
+ }
+ break;
+ default:
+ printf("--- reserved %d",item->type);
+ break;
+ }
+ switch(item->size) {
+ case 1:
+ printf(" %d",item->data.u8);
+ break;
+ case 2:
+ printf(" %d",item->data.u16);
+ break;
+ case 4:
+ printf(" %ld",item->data.u32);
+ break;
+ }
+ printf("\n");
+}
+
+
+static int usb_kbd_get_hid_desc(struct usb_device *dev)
+{
+ unsigned char buffer[256];
+ struct usb_descriptor_header *head;
+ struct usb_config_descriptor *config;
+ int index,len,i;
+ unsigned char *start, *end;
+ struct hid_item item;
+
+ if(usb_get_configuration_no(dev,&buffer[0],0)==-1)
+ return -1;
+ head =(struct usb_descriptor_header *)&buffer[0];
+ if(head->bDescriptorType!=USB_DT_CONFIG) {
+ printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
+ return -1;
+ }
+ index=head->bLength;
+ config=(struct usb_config_descriptor *)&buffer[0];
+ len=le16_to_cpu(config->wTotalLength);
+ /* Ok the first entry must be a configuration entry, now process the others */
+ head=(struct usb_descriptor_header *)&buffer[index];
+ while(index+1 < len) {
+ if(head->bDescriptorType==USB_DT_HID) {
+ printf("HID desc found\n");
+ memcpy(&usb_kbd_hid_desc,&buffer[index],buffer[index]);
+ le16_to_cpus(&usb_kbd_hid_desc.bcdHID);
+ le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength);
+ usb_kbd_display_hid(&usb_kbd_hid_desc);
+ len=0;
+ break;
+ }
+ index+=head->bLength;
+ head=(struct usb_descriptor_header *)&buffer[index];
+ }
+ if(len>0)
+ return -1;
+ len=usb_kbd_hid_desc.wDescriptorLength;
+ if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) {
+ printf("reading report descriptor failed\n");
+ return -1;
+ }
+ printf(" report descriptor (size %u, read %d)\n", len, index);
+ start = &buffer[0];
+ end = &buffer[len];
+ i=0;
+ do {
+ index=fetch_item(start,end,&item);
+ i+=index;
+ i++;
+ if(index>=0)
+ usb_kbd_show_item(&item);
+
+ start+=index;
+ start++;
+ } while(index>=0);
+
+}
+
+#endif
diff --git a/u-boot/common/usb_storage.c b/u-boot/common/usb_storage.c
new file mode 100644
index 0000000..1e6cd6a
--- /dev/null
+++ b/u-boot/common/usb_storage.c
@@ -0,0 +1,1449 @@
+/*
+ * Most of this source has been derived from the Linux USB
+ * project:
+ * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * (c) 2000 Yggdrasil Computing, Inc.
+ *
+ *
+ * Adapted for U-Boot:
+ * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ *
+ * For BBB support (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * BBB support based on /sys/dev/usb/umass.c from
+ * FreeBSD.
+ *
+ * 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
+ *
+ */
+
+/* Note:
+ * Currently only the CBI transport protocoll has been implemented, and it
+ * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
+ * transport protocoll may work as well.
+ */
+/*
+ * New Note:
+ * Support for USB Mass Storage Devices (BBB) has been added. It has
+ * only been tested with USB memory sticks.
+ */
+
+
+#include <common.h>
+#include <command.h>
+#include <asm/byteorder.h>
+#include <asm/processor.h>
+
+#include <part.h>
+#include <usb.h>
+
+#undef USB_STOR_DEBUG
+#undef BBB_COMDAT_TRACE
+#undef BBB_XPORT_TRACE
+
+#ifdef USB_STOR_DEBUG
+#define USB_STOR_PRINTF(fmt, args...) printf(fmt , ##args)
+#else
+#define USB_STOR_PRINTF(fmt, args...)
+#endif
+
+#include <scsi.h>
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+static const unsigned char us_direction[256/8] = {
+ 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+ 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+static unsigned char usb_stor_buf[512];
+static ccb usb_ccb;
+
+/*
+ * CBI style
+ */
+
+#define US_CBI_ADSC 0
+
+/*
+ * BULK only
+ */
+#define US_BBB_RESET 0xff
+#define US_BBB_GET_MAX_LUN 0xfe
+
+/* Command Block Wrapper */
+typedef struct {
+ __u32 dCBWSignature;
+# define CBWSIGNATURE 0x43425355
+ __u32 dCBWTag;
+ __u32 dCBWDataTransferLength;
+ __u8 bCBWFlags;
+# define CBWFLAGS_OUT 0x00
+# define CBWFLAGS_IN 0x80
+ __u8 bCBWLUN;
+ __u8 bCDBLength;
+# define CBWCDBLENGTH 16
+ __u8 CBWCDB[CBWCDBLENGTH];
+} umass_bbb_cbw_t;
+#define UMASS_BBB_CBW_SIZE 31
+static __u32 CBWTag;
+
+/* Command Status Wrapper */
+typedef struct {
+ __u32 dCSWSignature;
+# define CSWSIGNATURE 0x53425355
+ __u32 dCSWTag;
+ __u32 dCSWDataResidue;
+ __u8 bCSWStatus;
+# define CSWSTATUS_GOOD 0x0
+# define CSWSTATUS_FAILED 0x1
+# define CSWSTATUS_PHASE 0x2
+} umass_bbb_csw_t;
+#define UMASS_BBB_CSW_SIZE 13
+
+#define USB_MAX_STOR_DEV 5
+static int usb_max_devs; /* number of highest available usb device */
+
+static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
+
+struct us_data;
+typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
+typedef int (*trans_reset)(struct us_data *data);
+
+struct us_data {
+ struct usb_device *pusb_dev; /* this usb_device */
+
+ unsigned int flags; /* from filter initially */
+ unsigned char ifnum; /* interface number */
+ unsigned char ep_in; /* in endpoint */
+ unsigned char ep_out; /* out ....... */
+ unsigned char ep_int; /* interrupt . */
+ unsigned char subclass; /* as in overview */
+ unsigned char protocol; /* .............. */
+ unsigned char attention_done; /* force attn on first cmd */
+ unsigned short ip_data; /* interrupt data */
+ int action; /* what to do */
+ int ip_wanted; /* needed */
+ int *irq_handle; /* for USB int requests */
+ unsigned int irqpipe; /* pipe for release_irq */
+ unsigned char irqmaxp; /* max packed for irq Pipe */
+ unsigned char irqinterval; /* Intervall for IRQ Pipe */
+ ccb *srb; /* current srb */
+ trans_reset transport_reset; /* reset routine */
+ trans_cmnd transport; /* transport routine */
+};
+
+static struct us_data usb_stor[USB_MAX_STOR_DEV];
+
+
+#define USB_STOR_TRANSPORT_GOOD 0
+#define USB_STOR_TRANSPORT_FAILED -1
+#define USB_STOR_TRANSPORT_ERROR -2
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
+ block_dev_desc_t *dev_desc);
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss);
+unsigned long usb_stor_read(int device, unsigned long blknr,
+ unsigned long blkcnt, void *buffer);
+unsigned long usb_stor_write(int device, unsigned long blknr,
+ unsigned long blkcnt, const void *buffer);
+struct usb_device * usb_get_dev_index(int index);
+void uhci_show_temp_int_td(void);
+
+block_dev_desc_t *usb_stor_get_dev(int index)
+{
+ return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
+}
+
+
+void usb_show_progress(void)
+{
+ debug(".");
+}
+
+/*******************************************************************************
+ * show info on storage devices; 'usb start/init' must be invoked earlier
+ * as we only retrieve structures populated during devices initialization
+ */
+int usb_stor_info(void)
+{
+ int i;
+
+ if (usb_max_devs > 0) {
+ for (i = 0; i < usb_max_devs; i++) {
+ printf(" Device %d: ", i);
+ dev_print(&usb_dev_desc[i]);
+ }
+ return 0;
+ }
+
+ printf("No storage devices, perhaps not 'usb start'ed..?\n");
+ return 1;
+}
+
+static unsigned int usb_get_max_lun(struct us_data *us)
+{
+ int len;
+ unsigned char result;
+ len = usb_control_msg(us->pusb_dev,
+ usb_rcvctrlpipe(us->pusb_dev, 0),
+ US_BBB_GET_MAX_LUN,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ 0, us->ifnum,
+ &result, sizeof(result),
+ USB_CNTL_TIMEOUT * 5);
+ USB_STOR_PRINTF("Get Max LUN -> len = %i, result = %i\n",
+ len, (int) result);
+ return (len > 0) ? result : 0;
+}
+
+/*******************************************************************************
+ * scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_stor_scan(int mode)
+{
+ unsigned char i;
+ struct usb_device *dev;
+
+ /* GJ */
+ memset(usb_stor_buf, 0, sizeof(usb_stor_buf));
+
+ if (mode == 1)
+ printf(" scanning bus for storage devices... ");
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ for (i = 0; i < USB_MAX_STOR_DEV; i++) {
+ memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t));
+ usb_dev_desc[i].if_type = IF_TYPE_USB;
+ usb_dev_desc[i].dev = i;
+ usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+ usb_dev_desc[i].target = 0xff;
+ usb_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+ usb_dev_desc[i].block_read = usb_stor_read;
+ usb_dev_desc[i].block_write = usb_stor_write;
+ }
+
+ usb_max_devs = 0;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i); /* get device */
+ USB_STOR_PRINTF("i=%d\n", i);
+ if (dev == NULL)
+ break; /* no more devices avaiable */
+
+ if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
+ /* OK, it's a storage device. Iterate over its LUNs
+ * and populate `usb_dev_desc'.
+ */
+ int lun, max_lun, start = usb_max_devs;
+
+ max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
+ for (lun = 0;
+ lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
+ lun++) {
+ usb_dev_desc[usb_max_devs].lun = lun;
+ if (usb_stor_get_info(dev, &usb_stor[start],
+ &usb_dev_desc[usb_max_devs]) == 1) {
+ usb_max_devs++;
+ }
+ }
+ }
+ /* if storage device */
+ if (usb_max_devs == USB_MAX_STOR_DEV) {
+ printf("max USB Storage Device reached: %d stopping\n",
+ usb_max_devs);
+ break;
+ }
+ } /* for */
+
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ printf("%d Storage Device(s) found\n", usb_max_devs);
+ if (usb_max_devs > 0)
+ return 0;
+ return -1;
+}
+
+static int usb_stor_irq(struct usb_device *dev)
+{
+ struct us_data *us;
+ us = (struct us_data *)dev->privptr;
+
+ if (us->ip_wanted)
+ us->ip_wanted = 0;
+ return 0;
+}
+
+
+#ifdef USB_STOR_DEBUG
+
+static void usb_show_srb(ccb *pccb)
+{
+ int i;
+ printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
+ for (i = 0; i < 12; i++)
+ printf("%02X ", pccb->cmd[i]);
+ printf("\n");
+}
+
+static void display_int_status(unsigned long tmp)
+{
+ printf("Status: %s %s %s %s %s %s %s\n",
+ (tmp & USB_ST_ACTIVE) ? "Active" : "",
+ (tmp & USB_ST_STALLED) ? "Stalled" : "",
+ (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
+ (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
+ (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
+ (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
+ (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
+}
+#endif
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+{
+ int max_size;
+ int this_xfer;
+ int result;
+ int partial;
+ int maxtry;
+ int stat;
+
+ /* determine the maximum packet size for these transfers */
+ max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
+
+ /* while we have data left to transfer */
+ while (length) {
+
+ /* calculate how long this will be -- maximum or a remainder */
+ this_xfer = length > max_size ? max_size : length;
+ length -= this_xfer;
+
+ /* setup the retry counter */
+ maxtry = 10;
+
+ /* set up the transfer loop */
+ do {
+ /* transfer the data */
+ USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n",
+ (unsigned int)buf, this_xfer, 11 - maxtry);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+ this_xfer, &partial,
+ USB_CNTL_TIMEOUT * 5);
+ USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n",
+ result, partial, this_xfer);
+ if (us->pusb_dev->status != 0) {
+ /* if we stall, we need to clear it before
+ * we go on
+ */
+#ifdef USB_STOR_DEBUG
+ display_int_status(us->pusb_dev->status);
+#endif
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe);
+ stat = us->pusb_dev->status;
+ usb_clear_halt(us->pusb_dev, pipe);
+ us->pusb_dev->status = stat;
+ if (this_xfer == partial) {
+ USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n", us->pusb_dev->status);
+ return 0;
+ }
+ else
+ return result;
+ }
+ if (us->pusb_dev->status & USB_ST_NAK_REC) {
+ USB_STOR_PRINTF("Device NAKed bulk_msg\n");
+ return result;
+ }
+ USB_STOR_PRINTF("bulk transferred with error");
+ if (this_xfer == partial) {
+ USB_STOR_PRINTF(" %d, but data ok\n",
+ us->pusb_dev->status);
+ return 0;
+ }
+ /* if our try counter reaches 0, bail out */
+ USB_STOR_PRINTF(" %d, data %d\n",
+ us->pusb_dev->status, partial);
+ if (!maxtry--)
+ return result;
+ }
+ /* update to show what data was transferred */
+ this_xfer -= partial;
+ buf += partial;
+ /* continue until this transfer is done */
+ } while (this_xfer);
+ }
+
+ /* if we get here, we're done and successful */
+ return 0;
+}
+
+static int usb_stor_BBB_reset(struct us_data *us)
+{
+ int result;
+ unsigned int pipe;
+
+ /*
+ * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
+ *
+ * For Reset Recovery the host shall issue in the following order:
+ * a) a Bulk-Only Mass Storage Reset
+ * b) a Clear Feature HALT to the Bulk-In endpoint
+ * c) a Clear Feature HALT to the Bulk-Out endpoint
+ *
+ * This is done in 3 steps.
+ *
+ * If the reset doesn't succeed, the device should be port reset.
+ *
+ * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
+ */
+ USB_STOR_PRINTF("BBB_reset\n");
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_BBB_RESET,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT * 5);
+
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("RESET:stall\n");
+ return -1;
+ }
+
+ /* long wait for reset */
+ wait_ms(150);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n", result,
+ us->pusb_dev->status);
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ /* long wait for reset */
+ wait_ms(150);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",
+ result, us->pusb_dev->status);
+ /* long wait for reset */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ wait_ms(150);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X"
+ " clearing OUT endpoint\n", result,
+ us->pusb_dev->status);
+ USB_STOR_PRINTF("BBB_reset done\n");
+ return 0;
+}
+
+/* FIXME: this reset function doesn't really reset the port, and it
+ * should. Actually it should probably do what it's doing here, and
+ * reset the port physically
+ */
+static int usb_stor_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ int result;
+
+ USB_STOR_PRINTF("CB_reset\n");
+ memset(cmd, 0xff, sizeof(cmd));
+ cmd[0] = SCSI_SEND_DIAG;
+ cmd[1] = 4;
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd),
+ USB_CNTL_TIMEOUT * 5);
+
+ /* long wait for reset */
+ wait_ms(1500);
+ USB_STOR_PRINTF("CB_reset result %d: status %X"
+ " clearing endpoint halt\n", result,
+ us->pusb_dev->status);
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+ USB_STOR_PRINTF("CB_reset done\n");
+ return 0;
+}
+
+/*
+ * Set up the command for a BBB device. Note that the actual SCSI
+ * command is copied into cbw.CBWCDB.
+ */
+int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
+{
+ int result;
+ int actlen;
+ int dir_in;
+ unsigned int pipe;
+ umass_bbb_cbw_t cbw;
+
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+#ifdef BBB_COMDAT_TRACE
+ printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n",
+ dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
+ srb->pdata);
+ if (srb->cmdlen) {
+ for (result = 0; result < srb->cmdlen; result++)
+ printf("cmd[%d] %#x ", result, srb->cmd[result]);
+ printf("\n");
+ }
+#endif
+ /* sanity checks */
+ if (!(srb->cmdlen <= CBWCDBLENGTH)) {
+ USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n");
+ return -1;
+ }
+
+ /* always OUT to the ep */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ cbw.dCBWSignature = cpu_to_le32(CBWSIGNATURE);
+ cbw.dCBWTag = cpu_to_le32(CBWTag++);
+ cbw.dCBWDataTransferLength = cpu_to_le32(srb->datalen);
+ cbw.bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
+ cbw.bCBWLUN = srb->lun;
+ cbw.bCDBLength = srb->cmdlen;
+ /* copy the command data into the CBW command data buffer */
+ /* DST SRC LEN!!! */
+ memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen);
+ result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE,
+ &actlen, USB_CNTL_TIMEOUT * 5);
+ if (result < 0)
+ USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n");
+ return result;
+}
+
+/* FIXME: we also need a CBI_command which sets up the completion
+ * interrupt, and waits for it
+ */
+int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
+{
+ int result = 0;
+ int dir_in, retry;
+ unsigned int pipe;
+ unsigned long status;
+
+ retry = 5;
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+ if (dir_in)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ while (retry--) {
+ USB_STOR_PRINTF("CBI gets a command: Try %d\n", 5 - retry);
+#ifdef USB_STOR_DEBUG
+ usb_show_srb(srb);
+#endif
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev , 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum,
+ srb->cmd, srb->cmdlen,
+ USB_CNTL_TIMEOUT * 5);
+ USB_STOR_PRINTF("CB_transport: control msg returned %d,"
+ " status %X\n", result, us->pusb_dev->status);
+ /* check the return code for the command */
+ if (result < 0) {
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ status = us->pusb_dev->status;
+ USB_STOR_PRINTF(" stall during command found,"
+ " clear pipe\n");
+ usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev, 0));
+ us->pusb_dev->status = status;
+ }
+ USB_STOR_PRINTF(" error during command %02X"
+ " Stat = %X\n", srb->cmd[0],
+ us->pusb_dev->status);
+ return result;
+ }
+ /* transfer the data payload for this command, if one exists*/
+
+ USB_STOR_PRINTF("CB_transport: control msg returned %d,"
+ " direction is %s to go 0x%lx\n", result,
+ dir_in ? "IN" : "OUT", srb->datalen);
+ if (srb->datalen) {
+ result = us_one_transfer(us, pipe, (char *)srb->pdata,
+ srb->datalen);
+ USB_STOR_PRINTF("CBI attempted to transfer data,"
+ " result is %d status %lX, len %d\n",
+ result, us->pusb_dev->status,
+ us->pusb_dev->act_len);
+ if (!(us->pusb_dev->status & USB_ST_NAK_REC))
+ break;
+ } /* if (srb->datalen) */
+ else
+ break;
+ }
+ /* return result */
+
+ return result;
+}
+
+
+int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
+{
+ int timeout;
+
+ us->ip_wanted = 1;
+ submit_int_msg(us->pusb_dev, us->irqpipe,
+ (void *) &us->ip_data, us->irqmaxp, us->irqinterval);
+ timeout = 1000;
+ while (timeout--) {
+ if ((volatile int *) us->ip_wanted == 0)
+ break;
+ wait_ms(10);
+ }
+ if (us->ip_wanted) {
+ printf(" Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ USB_STOR_PRINTF
+ ("Got interrupt data 0x%x, transfered %d status 0x%lX\n",
+ us->ip_data, us->pusb_dev->irq_act_len,
+ us->pusb_dev->irq_status);
+ /* UFI gives us ASC and ASCQ, like a request sense */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmd[0] == SCSI_REQ_SENSE ||
+ srb->cmd[0] == SCSI_INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD; /* Good */
+ else if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* otherwise, we interpret the data normally */
+ switch (us->ip_data) {
+ case 0x0001:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0002:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ } /* switch */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+#define USB_TRANSPORT_UNKNOWN_RETRY 5
+#define USB_TRANSPORT_NOT_READY_RETRY 10
+
+/* clear a stall on an endpoint - special for BBB devices */
+int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
+{
+ int result;
+
+ /* ENDPOINT_HALT = 0, so set value to 0 */
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+ 0, endpt, 0, 0, USB_CNTL_TIMEOUT * 5);
+ return result;
+}
+
+int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
+{
+ int result, retry;
+ int dir_in;
+ int actlen, data_actlen;
+ unsigned int pipe, pipein, pipeout;
+ umass_bbb_csw_t csw;
+#ifdef BBB_XPORT_TRACE
+ unsigned char *ptr;
+ int index;
+#endif
+
+ dir_in = US_DIRECTION(srb->cmd[0]);
+
+ /* COMMAND phase */
+ USB_STOR_PRINTF("COMMAND phase\n");
+ result = usb_stor_BBB_comdat(srb, us);
+ if (result < 0) {
+ USB_STOR_PRINTF("failed to send CBW status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+ wait_ms(5);
+ pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ /* DATA phase + error handling */
+ data_actlen = 0;
+ /* no data, go immediately to the STATUS phase */
+ if (srb->datalen == 0)
+ goto st;
+ USB_STOR_PRINTF("DATA phase\n");
+ if (dir_in)
+ pipe = pipein;
+ else
+ pipe = pipeout;
+ result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
+ &data_actlen, USB_CNTL_TIMEOUT * 5);
+ /* special handling of STALL in DATA phase */
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("DATA:stall\n");
+ /* clear the STALL on the endpoint */
+ result = usb_stor_BBB_clear_endpt_stall(us,
+ dir_in ? us->ep_in : us->ep_out);
+ if (result >= 0)
+ /* continue on to STATUS phase */
+ goto st;
+ }
+ if (result < 0) {
+ USB_STOR_PRINTF("usb_bulk_msg error status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+#ifdef BBB_XPORT_TRACE
+ for (index = 0; index < data_actlen; index++)
+ printf("pdata[%d] %#x ", index, srb->pdata[index]);
+ printf("\n");
+#endif
+ /* STATUS phase + error handling */
+st:
+ retry = 0;
+again:
+ USB_STOR_PRINTF("STATUS phase\n");
+ result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE,
+ &actlen, USB_CNTL_TIMEOUT*5);
+
+ /* special handling of STALL in STATUS phase */
+ if ((result < 0) && (retry < 1) &&
+ (us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("STATUS:stall\n");
+ /* clear the STALL on the endpoint */
+ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
+ if (result >= 0 && (retry++ < 1))
+ /* do a retry */
+ goto again;
+ }
+ if (result < 0) {
+ USB_STOR_PRINTF("usb_bulk_msg error status %ld\n",
+ us->pusb_dev->status);
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+#ifdef BBB_XPORT_TRACE
+ ptr = (unsigned char *)&csw;
+ for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
+ printf("ptr[%d] %#x ", index, ptr[index]);
+ printf("\n");
+#endif
+ /* misuse pipe to get the residue */
+ pipe = le32_to_cpu(csw.dCSWDataResidue);
+ if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
+ pipe = srb->datalen - data_actlen;
+ if (CSWSIGNATURE != le32_to_cpu(csw.dCSWSignature)) {
+ USB_STOR_PRINTF("!CSWSIGNATURE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if ((CBWTag - 1) != le32_to_cpu(csw.dCSWTag)) {
+ USB_STOR_PRINTF("!Tag\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw.bCSWStatus > CSWSTATUS_PHASE) {
+ USB_STOR_PRINTF(">PHASE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw.bCSWStatus == CSWSTATUS_PHASE) {
+ USB_STOR_PRINTF("=PHASE\n");
+ usb_stor_BBB_reset(us);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (data_actlen > srb->datalen) {
+ USB_STOR_PRINTF("transferred %dB instead of %dB\n",
+ data_actlen, srb->datalen);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else if (csw.bCSWStatus == CSWSTATUS_FAILED) {
+ USB_STOR_PRINTF("FAILED\n");
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ return result;
+}
+
+int usb_stor_CB_transport(ccb *srb, struct us_data *us)
+{
+ int result, status;
+ ccb *psrb;
+ ccb reqsrb;
+ int retry, notready;
+
+ psrb = &reqsrb;
+ status = USB_STOR_TRANSPORT_GOOD;
+ retry = 0;
+ notready = 0;
+ /* issue the command */
+do_retry:
+ result = usb_stor_CB_comdat(srb, us);
+ USB_STOR_PRINTF("command / Data returned %d, status %X\n",
+ result, us->pusb_dev->status);
+ /* if this is an CBI Protocol, get IRQ */
+ if (us->protocol == US_PR_CBI) {
+ status = usb_stor_CBI_get_status(srb, us);
+ /* if the status is error, report it */
+ if (status == USB_STOR_TRANSPORT_ERROR) {
+ USB_STOR_PRINTF(" USB CBI Command Error\n");
+ return status;
+ }
+ srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
+ srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
+ if (!us->ip_data) {
+ /* if the status is good, report it */
+ if (status == USB_STOR_TRANSPORT_GOOD) {
+ USB_STOR_PRINTF(" USB CBI Command Good\n");
+ return status;
+ }
+ }
+ }
+ /* do we have to issue an auto request? */
+ /* HERE we have to check the result */
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("ERROR %X\n", us->pusb_dev->status);
+ us->transport_reset(us);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ if ((us->protocol == US_PR_CBI) &&
+ ((srb->cmd[0] == SCSI_REQ_SENSE) ||
+ (srb->cmd[0] == SCSI_INQUIRY))) {
+ /* do not issue an autorequest after request sense */
+ USB_STOR_PRINTF("No auto request and good\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* issue an request_sense */
+ memset(&psrb->cmd[0], 0, 12);
+ psrb->cmd[0] = SCSI_REQ_SENSE;
+ psrb->cmd[1] = srb->lun << 5;
+ psrb->cmd[4] = 18;
+ psrb->datalen = 18;
+ psrb->pdata = &srb->sense_buf[0];
+ psrb->cmdlen = 12;
+ /* issue the command */
+ result = usb_stor_CB_comdat(psrb, us);
+ USB_STOR_PRINTF("auto request returned %d\n", result);
+ /* if this is an CBI Protocol, get IRQ */
+ if (us->protocol == US_PR_CBI)
+ status = usb_stor_CBI_get_status(psrb, us);
+
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",
+ us->pusb_dev->status);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
+ /* Check the auto request result */
+ if ((srb->sense_buf[2] == 0) &&
+ (srb->sense_buf[12] == 0) &&
+ (srb->sense_buf[13] == 0)) {
+ /* ok, no sense */
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* Check the auto request result */
+ switch (srb->sense_buf[2]) {
+ case 0x01:
+ /* Recovered Error */
+ return USB_STOR_TRANSPORT_GOOD;
+ break;
+ case 0x02:
+ /* Not Ready */
+ if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X (NOT READY)\n", srb->cmd[0],
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else {
+ wait_ms(100);
+ goto do_retry;
+ }
+ break;
+ default:
+ if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ } else
+ goto do_retry;
+ break;
+ }
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+
+static int usb_inquiry(ccb *srb, struct us_data *ss)
+{
+ int retry, i;
+ retry = 5;
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_INQUIRY;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[4] = 36;
+ srb->datalen = 36;
+ srb->cmdlen = 12;
+ i = ss->transport(srb, ss);
+ USB_STOR_PRINTF("inquiry returns %d\n", i);
+ if (i == 0)
+ break;
+ } while (--retry);
+
+ if (!retry) {
+ printf("error in inquiry\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int usb_request_sense(ccb *srb, struct us_data *ss)
+{
+ char *ptr;
+
+ ptr = (char *)srb->pdata;
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_REQ_SENSE;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[4] = 18;
+ srb->datalen = 18;
+ srb->pdata = &srb->sense_buf[0];
+ srb->cmdlen = 12;
+ ss->transport(srb, ss);
+ USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ srb->pdata = (uchar *)ptr;
+ return 0;
+}
+
+static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
+{
+ int retries = 10;
+
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_TST_U_RDY;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 0;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
+ return 0;
+ usb_request_sense(srb, ss);
+ wait_ms(100);
+ } while (retries--);
+
+ return -1;
+}
+
+static int usb_read_capacity(ccb *srb, struct us_data *ss)
+{
+ int retry;
+ /* XXX retries */
+ retry = 3;
+ do {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_RD_CAPAC;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 8;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
+ return 0;
+ } while (retry--);
+
+ return -1;
+}
+
+static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
+ unsigned short blocks)
+{
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_READ10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ USB_STOR_PRINTF("read10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
+}
+
+static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
+ unsigned short blocks)
+{
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_WRITE10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ USB_STOR_PRINTF("write10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
+}
+
+
+#ifdef CONFIG_USB_BIN_FIXUP
+/*
+ * Some USB storage devices queried for SCSI identification data respond with
+ * binary strings, which if output to the console freeze the terminal. The
+ * workaround is to modify the vendor and product strings read from such
+ * device with proper values (as reported by 'usb info').
+ *
+ * Vendor and product length limits are taken from the definition of
+ * block_dev_desc_t in include/part.h.
+ */
+static void usb_bin_fixup(struct usb_device_descriptor descriptor,
+ unsigned char vendor[],
+ unsigned char product[]) {
+ const unsigned char max_vendor_len = 40;
+ const unsigned char max_product_len = 20;
+ if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
+ strncpy((char *)vendor, "SMSC", max_vendor_len);
+ strncpy((char *)product, "Flash Media Cntrller",
+ max_product_len);
+ }
+}
+#endif /* CONFIG_USB_BIN_FIXUP */
+
+#define USB_MAX_READ_BLK 20
+
+unsigned long usb_stor_read(int device, unsigned long blknr,
+ unsigned long blkcnt, void *buffer)
+{
+ unsigned long start, blks, buf_addr;
+ unsigned short smallblks;
+ struct usb_device *dev;
+ int retry, i;
+ ccb *srb = &usb_ccb;
+
+ if (blkcnt == 0)
+ return 0;
+
+ device &= 0xff;
+ /* Setup device */
+ USB_STOR_PRINTF("\nusb_read: dev %d \n", device);
+ dev = NULL;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i);
+ if (dev == NULL)
+ return 0;
+ if (dev->devnum == usb_dev_desc[device].target)
+ break;
+ }
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+ srb->lun = usb_dev_desc[device].lun;
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ if (usb_test_unit_ready(srb, (struct us_data *)dev->privptr)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X"
+ " %02X\n", srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ return 0;
+ }
+
+ USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx"
+ " buffer %lx\n", device, start, blks, buf_addr);
+
+ do {
+ /* XXX need some comment here */
+ retry = 2;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (blks > USB_MAX_READ_BLK)
+ smallblks = USB_MAX_READ_BLK;
+ else
+ smallblks = (unsigned short) blks;
+retry_it:
+ if (smallblks == USB_MAX_READ_BLK)
+ usb_show_progress();
+ srb->datalen = usb_dev_desc[device].blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_read_10(srb, (struct us_data *)dev->privptr, start,
+ smallblks)) {
+ USB_STOR_PRINTF("Read ERROR\n");
+ usb_request_sense(srb, (struct us_data *)dev->privptr);
+ if (retry--)
+ goto retry_it;
+ blkcnt -= blks;
+ break;
+ }
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if (blkcnt >= USB_MAX_READ_BLK)
+ debug("\n");
+ return blkcnt;
+}
+
+#define USB_MAX_WRITE_BLK 20
+
+unsigned long usb_stor_write(int device, unsigned long blknr,
+ unsigned long blkcnt, const void *buffer)
+{
+ unsigned long start, blks, buf_addr;
+ unsigned short smallblks;
+ struct usb_device *dev;
+ int retry, i;
+ ccb *srb = &usb_ccb;
+
+ if (blkcnt == 0)
+ return 0;
+
+ device &= 0xff;
+ /* Setup device */
+ USB_STOR_PRINTF("\nusb_write: dev %d \n", device);
+ dev = NULL;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i);
+ if (dev == NULL)
+ return 0;
+ if (dev->devnum == usb_dev_desc[device].target)
+ break;
+ }
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ srb->lun = usb_dev_desc[device].lun;
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ if (usb_test_unit_ready(srb, (struct us_data *)dev->privptr)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X"
+ " %02X\n", srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ return 0;
+ }
+
+ USB_STOR_PRINTF("\nusb_write: dev %d startblk %lx, blccnt %lx"
+ " buffer %lx\n", device, start, blks, buf_addr);
+
+ do {
+ /* If write fails retry for max retry count else
+ * return with number of blocks written successfully.
+ */
+ retry = 2;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (blks > USB_MAX_WRITE_BLK)
+ smallblks = USB_MAX_WRITE_BLK;
+ else
+ smallblks = (unsigned short) blks;
+retry_it:
+ if (smallblks == USB_MAX_WRITE_BLK)
+ usb_show_progress();
+ srb->datalen = usb_dev_desc[device].blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_write_10(srb, (struct us_data *)dev->privptr, start,
+ smallblks)) {
+ USB_STOR_PRINTF("Write ERROR\n");
+ usb_request_sense(srb, (struct us_data *)dev->privptr);
+ if (retry--)
+ goto retry_it;
+ blkcnt -= blks;
+ break;
+ }
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ USB_STOR_PRINTF("usb_write: end startblk %lx, blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if (blkcnt >= USB_MAX_WRITE_BLK)
+ debug("\n");
+ return blkcnt;
+
+}
+
+/* Probe to see if a new device is actually a Storage device */
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss)
+{
+ struct usb_interface *iface;
+ int i;
+ unsigned int flags = 0;
+
+ int protocol = 0;
+ int subclass = 0;
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+
+#if 0
+ /* this is the place to patch some storage devices */
+ USB_STOR_PRINTF("iVendor %X iProduct %X\n", dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+
+ if ((dev->descriptor.idVendor) == 0x066b &&
+ (dev->descriptor.idProduct) == 0x0103) {
+ USB_STOR_PRINTF("patched for E-USB\n");
+ protocol = US_PR_CB;
+ subclass = US_SC_UFI; /* an assumption */
+ }
+#endif
+
+ if (dev->descriptor.bDeviceClass != 0 ||
+ iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+ iface->desc.bInterfaceSubClass < US_SC_MIN ||
+ iface->desc.bInterfaceSubClass > US_SC_MAX) {
+ /* if it's not a mass storage, we go no further */
+ return 0;
+ }
+
+ memset(ss, 0, sizeof(struct us_data));
+
+ /* At this point, we know we've got a live one */
+ USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n");
+
+ /* Initialize the us_data structure with some useful info */
+ ss->flags = flags;
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->attention_done = 0;
+
+ /* If the device has subclass and protocol, then use that. Otherwise,
+ * take data from the specific interface.
+ */
+ if (subclass) {
+ ss->subclass = subclass;
+ ss->protocol = protocol;
+ } else {
+ ss->subclass = iface->desc.bInterfaceSubClass;
+ ss->protocol = iface->desc.bInterfaceProtocol;
+ }
+
+ /* set the handler pointers based on the protocol */
+ USB_STOR_PRINTF("Transport: ");
+ switch (ss->protocol) {
+ case US_PR_CB:
+ USB_STOR_PRINTF("Control/Bulk\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+
+ case US_PR_CBI:
+ USB_STOR_PRINTF("Control/Bulk/Interrupt\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+ case US_PR_BULK:
+ USB_STOR_PRINTF("Bulk/Bulk/Bulk\n");
+ ss->transport = usb_stor_BBB_transport;
+ ss->transport_reset = usb_stor_BBB_reset;
+ break;
+ default:
+ printf("USB Storage Transport unknown / not yet implemented\n");
+ return 0;
+ break;
+ }
+
+ /*
+ * We are expecting a minimum of 2 endpoints - in and out (bulk).
+ * An optional interrupt is OK (necessary for CBI protocol).
+ * We will ignore any others.
+ */
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+ ss->ep_in = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ else
+ ss->ep_out =
+ iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = iface->ep_desc[i].bInterval;
+ }
+ }
+ USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out ||
+ (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+ USB_STOR_PRINTF("Problems with device\n");
+ return 0;
+ }
+ /* set class specific stuff */
+ /* We only handle certain protocols. Currently, these are
+ * the only ones.
+ * The SFF8070 accepts the requests used in u-boot
+ */
+ if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
+ ss->subclass != US_SC_8070) {
+ printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
+ return 0;
+ }
+ if (ss->ep_int) {
+ /* we had found an interrupt endpoint, prepare irq pipe
+ * set up the IRQ pipe and handler
+ */
+ ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
+ dev->irq_handle = usb_stor_irq;
+ }
+ dev->privptr = (void *)ss;
+ return 1;
+}
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
+ block_dev_desc_t *dev_desc)
+{
+ unsigned char perq, modi;
+ unsigned long cap[2];
+ unsigned long *capacity, *blksz;
+ ccb *pccb = &usb_ccb;
+
+ /* for some reasons a couple of devices would not survive this reset */
+ if (
+ /* Sony USM256E */
+ (dev->descriptor.idVendor == 0x054c &&
+ dev->descriptor.idProduct == 0x019e)
+ ||
+ /* USB007 Mini-USB2 Flash Drive */
+ (dev->descriptor.idVendor == 0x066f &&
+ dev->descriptor.idProduct == 0x2010)
+ ||
+ /* SanDisk Corporation Cruzer Micro 20044318410546613953 */
+ (dev->descriptor.idVendor == 0x0781 &&
+ dev->descriptor.idProduct == 0x5151)
+ ||
+ /*
+ * SanDisk Corporation U3 Cruzer Micro 1/4GB
+ * Flash Drive 000016244373FFB4
+ */
+ (dev->descriptor.idVendor == 0x0781 &&
+ dev->descriptor.idProduct == 0x5406)
+ )
+ USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n");
+ else
+ ss->transport_reset(ss);
+
+ pccb->pdata = usb_stor_buf;
+
+ dev_desc->target = dev->devnum;
+ pccb->lun = dev_desc->lun;
+ USB_STOR_PRINTF(" address %d\n", dev_desc->target);
+
+ if (usb_inquiry(pccb, ss))
+ return -1;
+
+ perq = usb_stor_buf[0];
+ modi = usb_stor_buf[1];
+
+ if ((perq & 0x1f) == 0x1f) {
+ /* skip unknown devices */
+ return 0;
+ }
+ if ((modi&0x80) == 0x80) {
+ /* drive is removable */
+ dev_desc->removable = 1;
+ }
+ memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
+ memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
+ memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
+ dev_desc->vendor[8] = 0;
+ dev_desc->product[16] = 0;
+ dev_desc->revision[4] = 0;
+#ifdef CONFIG_USB_BIN_FIXUP
+ usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
+ (uchar *)dev_desc->product);
+#endif /* CONFIG_USB_BIN_FIXUP */
+ USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
+ usb_stor_buf[3]);
+ if (usb_test_unit_ready(pccb, ss)) {
+ printf("Device NOT ready\n"
+ " Request Sense returned %02X %02X %02X\n",
+ pccb->sense_buf[2], pccb->sense_buf[12],
+ pccb->sense_buf[13]);
+ if (dev_desc->removable == 1) {
+ dev_desc->type = perq;
+ return 1;
+ }
+ return 0;
+ }
+ pccb->pdata = (unsigned char *)&cap[0];
+ memset(pccb->pdata, 0, 8);
+ if (usb_read_capacity(pccb, ss) != 0) {
+ printf("READ_CAP ERROR\n");
+ cap[0] = 2880;
+ cap[1] = 0x200;
+ }
+ USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0],
+ cap[1]);
+#if 0
+ if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
+ cap[0] >>= 16;
+#endif
+ cap[0] = cpu_to_be32(cap[0]);
+ cap[1] = cpu_to_be32(cap[1]);
+
+ /* this assumes bigendian! */
+ cap[0] += 1;
+ capacity = &cap[0];
+ blksz = &cap[1];
+ USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",
+ *capacity, *blksz);
+ dev_desc->lba = *capacity;
+ dev_desc->blksz = *blksz;
+ dev_desc->type = perq;
+ USB_STOR_PRINTF(" address %d\n", dev_desc->target);
+ USB_STOR_PRINTF("partype: %d\n", dev_desc->part_type);
+
+ init_part(dev_desc);
+
+ USB_STOR_PRINTF("partype: %d\n", dev_desc->part_type);
+ return 1;
+}
diff --git a/u-boot/common/xyzModem.c b/u-boot/common/xyzModem.c
new file mode 100644
index 0000000..7a46805
--- /dev/null
+++ b/u-boot/common/xyzModem.c
@@ -0,0 +1,849 @@
+/*
+ *==========================================================================
+ *
+ * xyzModem.c
+ *
+ * RedBoot stream handler for xyzModem protocol
+ *
+ *==========================================================================
+ *####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating System.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2002 Gary Thomas
+ *
+ * eCos 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 or (at your option) any later version.
+ *
+ * eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * As a special exception, if other files instantiate templates or use macros
+ * or inline functions from this file, or you compile this file and link it
+ * with other works to produce a work based on this file, this file does not
+ * by itself cause the resulting work to be covered by the GNU General Public
+ * License. However the source code for this file must still be made available
+ * in accordance with section (3) of the GNU General Public License.
+ *
+ * This exception does not invalidate any other reasons why a work based on
+ * this file might be covered by the GNU General Public License.
+ *
+ * Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+ * at http: *sources.redhat.com/ecos/ecos-license/
+ * -------------------------------------------
+ *####ECOSGPLCOPYRIGHTEND####
+ *==========================================================================
+ *#####DESCRIPTIONBEGIN####
+ *
+ * Author(s): gthomas
+ * Contributors: gthomas, tsmith, Yoshinori Sato
+ * Date: 2000-07-14
+ * Purpose:
+ * Description:
+ *
+ * This code is part of RedBoot (tm).
+ *
+ *####DESCRIPTIONEND####
+ *
+ *==========================================================================
+ */
+#include <common.h>
+#include <xyzModem.h>
+#include <stdarg.h>
+#include <crc.h>
+
+/* Assumption - run xyzModem protocol over the console port */
+
+/* Values magic to the protocol */
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define BSP 0x08
+#define NAK 0x15
+#define CAN 0x18
+#define EOF 0x1A /* ^Z for DOS officionados */
+
+#define USE_YMODEM_LENGTH
+
+/* Data & state local to the protocol */
+static struct
+{
+#ifdef REDBOOT
+ hal_virtual_comm_table_t *__chan;
+#else
+ int *__chan;
+#endif
+ unsigned char pkt[1024], *bufp;
+ unsigned char blk, cblk, crc1, crc2;
+ unsigned char next_blk; /* Expected block */
+ int len, mode, total_retries;
+ int total_SOH, total_STX, total_CAN;
+ bool crc_mode, at_eof, tx_ack;
+#ifdef USE_YMODEM_LENGTH
+ unsigned long file_length, read_length;
+#endif
+} xyz;
+
+#define xyzModem_CHAR_TIMEOUT 2000 /* 2 seconds */
+#define xyzModem_MAX_RETRIES 20
+#define xyzModem_MAX_RETRIES_WITH_CRC 10
+#define xyzModem_CAN_COUNT 3 /* Wait for 3 CAN before quitting */
+
+
+#ifndef REDBOOT /*SB */
+typedef int cyg_int32;
+int
+CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c)
+{
+#define DELAY 20
+ unsigned long counter = 0;
+ while (!tstc () && (counter < xyzModem_CHAR_TIMEOUT * 1000 / DELAY))
+ {
+ udelay (DELAY);
+ counter++;
+ }
+ if (tstc ())
+ {
+ *c = getc ();
+ return 1;
+ }
+ return 0;
+}
+
+void
+CYGACC_COMM_IF_PUTC (char x, char y)
+{
+ putc (y);
+}
+
+/* Validate a hex character */
+__inline__ static bool
+_is_hex (char c)
+{
+ return (((c >= '0') && (c <= '9')) ||
+ ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
+}
+
+/* Convert a single hex nibble */
+__inline__ static int
+_from_hex (char c)
+{
+ int ret = 0;
+
+ if ((c >= '0') && (c <= '9'))
+ {
+ ret = (c - '0');
+ }
+ else if ((c >= 'a') && (c <= 'f'))
+ {
+ ret = (c - 'a' + 0x0a);
+ }
+ else if ((c >= 'A') && (c <= 'F'))
+ {
+ ret = (c - 'A' + 0x0A);
+ }
+ return ret;
+}
+
+/* Convert a character to lower case */
+__inline__ static char
+_tolower (char c)
+{
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ c = (c - 'A') + 'a';
+ }
+ return c;
+}
+
+/* Parse (scan) a number */
+bool
+parse_num (char *s, unsigned long *val, char **es, char *delim)
+{
+ bool first = true;
+ int radix = 10;
+ char c;
+ unsigned long result = 0;
+ int digit;
+
+ while (*s == ' ')
+ s++;
+ while (*s)
+ {
+ if (first && (s[0] == '0') && (_tolower (s[1]) == 'x'))
+ {
+ radix = 16;
+ s += 2;
+ }
+ first = false;
+ c = *s++;
+ if (_is_hex (c) && ((digit = _from_hex (c)) < radix))
+ {
+ /* Valid digit */
+#ifdef CYGPKG_HAL_MIPS
+ /* FIXME: tx49 compiler generates 0x2539018 for MUL which */
+ /* isn't any good. */
+ if (16 == radix)
+ result = result << 4;
+ else
+ result = 10 * result;
+ result += digit;
+#else
+ result = (result * radix) + digit;
+#endif
+ }
+ else
+ {
+ if (delim != (char *) 0)
+ {
+ /* See if this character is one of the delimiters */
+ char *dp = delim;
+ while (*dp && (c != *dp))
+ dp++;
+ if (*dp)
+ break; /* Found a good delimiter */
+ }
+ return false; /* Malformatted number */
+ }
+ }
+ *val = result;
+ if (es != (char **) 0)
+ {
+ *es = s;
+ }
+ return true;
+}
+
+#endif
+
+#define USE_SPRINTF
+#ifdef DEBUG
+#ifndef USE_SPRINTF
+/*
+ * Note: this debug setup only works if the target platform has two serial ports
+ * available so that the other one (currently only port 1) can be used for debug
+ * messages.
+ */
+static int
+zm_dprintf (char *fmt, ...)
+{
+ int cur_console;
+ va_list args;
+
+ va_start (args, fmt);
+#ifdef REDBOOT
+ cur_console =
+ CYGACC_CALL_IF_SET_CONSOLE_COMM
+ (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM (1);
+#endif
+ diag_vprintf (fmt, args);
+#ifdef REDBOOT
+ CYGACC_CALL_IF_SET_CONSOLE_COMM (cur_console);
+#endif
+}
+
+static void
+zm_flush (void)
+{
+}
+
+#else
+/*
+ * Note: this debug setup works by storing the strings in a fixed buffer
+ */
+#define FINAL
+#ifdef FINAL
+static char *zm_out = (char *) 0x00380000;
+static char *zm_out_start = (char *) 0x00380000;
+#else
+static char zm_buf[8192];
+static char *zm_out = zm_buf;
+static char *zm_out_start = zm_buf;
+
+#endif
+static int
+zm_dprintf (char *fmt, ...)
+{
+ int len;
+ va_list args;
+
+ va_start (args, fmt);
+ len = diag_vsprintf (zm_out, fmt, args);
+ zm_out += len;
+ return len;
+}
+
+static void
+zm_flush (void)
+{
+#ifdef REDBOOT
+ char *p = zm_out_start;
+ while (*p)
+ mon_write_char (*p++);
+#endif
+ zm_out = zm_out_start;
+}
+#endif
+
+static void
+zm_dump_buf (void *buf, int len)
+{
+#ifdef REDBOOT
+ diag_vdump_buf_with_offset (zm_dprintf, buf, len, 0);
+#else
+
+#endif
+}
+
+static unsigned char zm_buf[2048];
+static unsigned char *zm_bp;
+
+static void
+zm_new (void)
+{
+ zm_bp = zm_buf;
+}
+
+static void
+zm_save (unsigned char c)
+{
+ *zm_bp++ = c;
+}
+
+static void
+zm_dump (int line)
+{
+ zm_dprintf ("Packet at line: %d\n", line);
+ zm_dump_buf (zm_buf, zm_bp - zm_buf);
+}
+
+#define ZM_DEBUG(x) x
+#else
+#define ZM_DEBUG(x)
+#endif
+
+/* Wait for the line to go idle */
+static void
+xyzModem_flush (void)
+{
+ int res;
+ char c;
+ while (true)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ if (!res)
+ return;
+ }
+}
+
+static int
+xyzModem_get_hdr (void)
+{
+ char c;
+ int res;
+ bool hdr_found = false;
+ int i, can_total, hdr_chars;
+ unsigned short cksum;
+
+ ZM_DEBUG (zm_new ());
+ /* Find the start of a header */
+ can_total = 0;
+ hdr_chars = 0;
+
+ if (xyz.tx_ack)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ xyz.tx_ack = false;
+ }
+ while (!hdr_found)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ ZM_DEBUG (zm_save (c));
+ if (res)
+ {
+ hdr_chars++;
+ switch (c)
+ {
+ case SOH:
+ xyz.total_SOH++;
+ case STX:
+ if (c == STX)
+ xyz.total_STX++;
+ hdr_found = true;
+ break;
+ case CAN:
+ xyz.total_CAN++;
+ ZM_DEBUG (zm_dump (__LINE__));
+ if (++can_total == xyzModem_CAN_COUNT)
+ {
+ return xyzModem_cancel;
+ }
+ else
+ {
+ /* Wait for multiple CAN to avoid early quits */
+ break;
+ }
+ case EOT:
+ /* EOT only supported if no noise */
+ if (hdr_chars == 1)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("ACK on EOT #%d\n", __LINE__));
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_eof;
+ }
+ default:
+ /* Ignore, waiting for start of header */
+ ;
+ }
+ }
+ else
+ {
+ /* Data stream timed out */
+ xyzModem_flush (); /* Toss any current input */
+ ZM_DEBUG (zm_dump (__LINE__));
+ CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
+ return xyzModem_timeout;
+ }
+ }
+
+ /* Header found, now read the data */
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk);
+ ZM_DEBUG (zm_save (xyz.blk));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk);
+ ZM_DEBUG (zm_save (xyz.cblk));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ xyz.len = (c == SOH) ? 128 : 1024;
+ xyz.bufp = xyz.pkt;
+ for (i = 0; i < xyz.len; i++)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
+ ZM_DEBUG (zm_save (c));
+ if (res)
+ {
+ xyz.pkt[i] = c;
+ }
+ else
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1);
+ ZM_DEBUG (zm_save (xyz.crc1));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ if (xyz.crc_mode)
+ {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2);
+ ZM_DEBUG (zm_save (xyz.crc2));
+ if (!res)
+ {
+ ZM_DEBUG (zm_dump (__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ ZM_DEBUG (zm_dump (__LINE__));
+ /* Validate the message */
+ if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF)
+ {
+ ZM_DEBUG (zm_dprintf
+ ("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk,
+ (xyz.blk ^ xyz.cblk)));
+ ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len));
+ xyzModem_flush ();
+ return xyzModem_frame;
+ }
+ /* Verify checksum/CRC */
+ if (xyz.crc_mode)
+ {
+ cksum = cyg_crc16 (xyz.pkt, xyz.len);
+ if (cksum != ((xyz.crc1 << 8) | xyz.crc2))
+ {
+ ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x\n",
+ xyz.crc1, xyz.crc2, cksum & 0xFFFF));
+ return xyzModem_cksum;
+ }
+ }
+ else
+ {
+ cksum = 0;
+ for (i = 0; i < xyz.len; i++)
+ {
+ cksum += xyz.pkt[i];
+ }
+ if (xyz.crc1 != (cksum & 0xFF))
+ {
+ ZM_DEBUG (zm_dprintf
+ ("Checksum error - recvd: %x, computed: %x\n", xyz.crc1,
+ cksum & 0xFF));
+ return xyzModem_cksum;
+ }
+ }
+ /* If we get here, the message passes [structural] muster */
+ return 0;
+}
+
+int
+xyzModem_stream_open (connection_info_t * info, int *err)
+{
+#ifdef REDBOOT
+ int console_chan;
+#endif
+ int stat = 0;
+ int retries = xyzModem_MAX_RETRIES;
+ int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
+
+/* ZM_DEBUG(zm_out = zm_out_start); */
+#ifdef xyzModem_zmodem
+ if (info->mode == xyzModem_zmodem)
+ {
+ *err = xyzModem_noZmodem;
+ return -1;
+ }
+#endif
+
+#ifdef REDBOOT
+ /* Set up the I/O channel. Note: this allows for using a different port in the future */
+ console_chan =
+ CYGACC_CALL_IF_SET_CONSOLE_COMM
+ (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ if (info->chan >= 0)
+ {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM (info->chan);
+ }
+ else
+ {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan);
+ }
+ xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS ();
+
+ CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan);
+ CYGACC_COMM_IF_CONTROL (*xyz.__chan, __COMMCTL_SET_TIMEOUT,
+ xyzModem_CHAR_TIMEOUT);
+#else
+/* TODO: CHECK ! */
+ int dummy = 0;
+ xyz.__chan = &dummy;
+#endif
+ xyz.len = 0;
+ xyz.crc_mode = true;
+ xyz.at_eof = false;
+ xyz.tx_ack = false;
+ xyz.mode = info->mode;
+ xyz.total_retries = 0;
+ xyz.total_SOH = 0;
+ xyz.total_STX = 0;
+ xyz.total_CAN = 0;
+#ifdef USE_YMODEM_LENGTH
+ xyz.read_length = 0;
+ xyz.file_length = 0;
+#endif
+
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+
+ if (xyz.mode == xyzModem_xmodem)
+ {
+ /* X-modem doesn't have an information header - exit here */
+ xyz.next_blk = 1;
+ return 0;
+ }
+
+ while (retries-- > 0)
+ {
+ stat = xyzModem_get_hdr ();
+ if (stat == 0)
+ {
+ /* Y-modem file information header */
+ if (xyz.blk == 0)
+ {
+#ifdef USE_YMODEM_LENGTH
+ /* skip filename */
+ while (*xyz.bufp++);
+ /* get the length */
+ parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " ");
+#endif
+ /* The rest of the file name data block quietly discarded */
+ xyz.tx_ack = true;
+ }
+ xyz.next_blk = 1;
+ xyz.len = 0;
+ return 0;
+ }
+ else if (stat == xyzModem_timeout)
+ {
+ if (--crc_retries <= 0)
+ xyz.crc_mode = false;
+ CYGACC_CALL_IF_DELAY_US (5 * 100000); /* Extra delay for startup */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
+ }
+ if (stat == xyzModem_cancel)
+ {
+ break;
+ }
+ }
+ *err = stat;
+ ZM_DEBUG (zm_flush ());
+ return -1;
+}
+
+int
+xyzModem_stream_read (char *buf, int size, int *err)
+{
+ int stat, total, len;
+ int retries;
+
+ total = 0;
+ stat = xyzModem_cancel;
+ /* Try and get 'size' bytes into the buffer */
+ while (!xyz.at_eof && (size > 0))
+ {
+ if (xyz.len == 0)
+ {
+ retries = xyzModem_MAX_RETRIES;
+ while (retries-- > 0)
+ {
+ stat = xyzModem_get_hdr ();
+ if (stat == 0)
+ {
+ if (xyz.blk == xyz.next_blk)
+ {
+ xyz.tx_ack = true;
+ ZM_DEBUG (zm_dprintf
+ ("ACK block %d (%d)\n", xyz.blk, __LINE__));
+ xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
+
+#if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH)
+ if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0)
+ {
+#else
+ if (1)
+ {
+#endif
+ /* Data blocks can be padded with ^Z (EOF) characters */
+ /* This code tries to detect and remove them */
+ if ((xyz.bufp[xyz.len - 1] == EOF) &&
+ (xyz.bufp[xyz.len - 2] == EOF) &&
+ (xyz.bufp[xyz.len - 3] == EOF))
+ {
+ while (xyz.len
+ && (xyz.bufp[xyz.len - 1] == EOF))
+ {
+ xyz.len--;
+ }
+ }
+ }
+
+#ifdef USE_YMODEM_LENGTH
+ /*
+ * See if accumulated length exceeds that of the file.
+ * If so, reduce size (i.e., cut out pad bytes)
+ * Only do this for Y-modem (and Z-modem should it ever
+ * be supported since it can fall back to Y-modem mode).
+ */
+ if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length)
+ {
+ xyz.read_length += xyz.len;
+ if (xyz.read_length > xyz.file_length)
+ {
+ xyz.len -= (xyz.read_length - xyz.file_length);
+ }
+ }
+#endif
+ break;
+ }
+ else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF))
+ {
+ /* Just re-ACK this so sender will get on with it */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ continue; /* Need new header */
+ }
+ else
+ {
+ stat = xyzModem_sequence;
+ }
+ }
+ if (stat == xyzModem_cancel)
+ {
+ break;
+ }
+ if (stat == xyzModem_eof)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("ACK (%d)\n", __LINE__));
+ if (xyz.mode == xyzModem_ymodem)
+ {
+ CYGACC_COMM_IF_PUTC (*xyz.__chan,
+ (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("Reading Final Header\n"));
+ stat = xyzModem_get_hdr ();
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
+ ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)\n", __LINE__));
+ }
+ xyz.at_eof = true;
+ break;
+ }
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
+ }
+ if (stat < 0)
+ {
+ *err = stat;
+ xyz.len = -1;
+ return total;
+ }
+ }
+ /* Don't "read" data from the EOF protocol package */
+ if (!xyz.at_eof)
+ {
+ len = xyz.len;
+ if (size < len)
+ len = size;
+ memcpy (buf, xyz.bufp, len);
+ size -= len;
+ buf += len;
+ total += len;
+ xyz.len -= len;
+ xyz.bufp += len;
+ }
+ }
+ return total;
+}
+
+void
+xyzModem_stream_close (int *err)
+{
+ diag_printf
+ ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n",
+ xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
+ xyz.total_CAN, xyz.total_retries);
+ ZM_DEBUG (zm_flush ());
+}
+
+/* Need to be able to clean out the input buffer, so have to take the */
+/* getc */
+void
+xyzModem_stream_terminate (bool abort, int (*getc) (void))
+{
+ int c;
+
+ if (abort)
+ {
+ ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!\n"));
+ switch (xyz.mode)
+ {
+ case xyzModem_xmodem:
+ case xyzModem_ymodem:
+ /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */
+ /* number of Backspaces is a friendly way to get the other end to abort. */
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
+ /* Now consume the rest of what's waiting on the line. */
+ ZM_DEBUG (zm_dprintf ("Flushing serial line.\n"));
+ xyzModem_flush ();
+ xyz.at_eof = true;
+ break;
+#ifdef xyzModem_zmodem
+ case xyzModem_zmodem:
+ /* Might support it some day I suppose. */
+#endif
+ break;
+ }
+ }
+ else
+ {
+ ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...\n"));
+ /*
+ * Consume any trailing crap left in the inbuffer from
+ * previous recieved blocks. Since very few files are an exact multiple
+ * of the transfer block size, there will almost always be some gunk here.
+ * If we don't eat it now, RedBoot will think the user typed it.
+ */
+ ZM_DEBUG (zm_dprintf ("Trailing gunk:\n"));
+ while ((c = (*getc) ()) > -1);
+ ZM_DEBUG (zm_dprintf ("\n"));
+ /*
+ * Make a small delay to give terminal programs like minicom
+ * time to get control again after their file transfer program
+ * exits.
+ */
+ CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
+ }
+}
+
+char *
+xyzModem_error (int err)
+{
+ switch (err)
+ {
+ case xyzModem_access:
+ return "Can't access file";
+ break;
+ case xyzModem_noZmodem:
+ return "Sorry, zModem not available yet";
+ break;
+ case xyzModem_timeout:
+ return "Timed out";
+ break;
+ case xyzModem_eof:
+ return "End of file";
+ break;
+ case xyzModem_cancel:
+ return "Cancelled";
+ break;
+ case xyzModem_frame:
+ return "Invalid framing";
+ break;
+ case xyzModem_cksum:
+ return "CRC/checksum error";
+ break;
+ case xyzModem_sequence:
+ return "Block sequence error";
+ break;
+ default:
+ return "Unknown error";
+ break;
+ }
+}
+
+/*
+ * RedBoot interface
+ */
+#if 0 /* SB */
+GETC_IO_FUNCS (xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
+ xyzModem_stream_terminate, xyzModem_stream_read,
+ xyzModem_error);
+RedBoot_load (xmodem, xyzModem_io, false, false, xyzModem_xmodem);
+RedBoot_load (ymodem, xyzModem_io, false, false, xyzModem_ymodem);
+#endif