diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/cmd_ace.c | 31 | ||||
-rw-r--r-- | common/cmd_bdinfo.c | 14 | ||||
-rw-r--r-- | common/cmd_bootm.c | 4 | ||||
-rw-r--r-- | common/cmd_dcr.c | 2 | ||||
-rw-r--r-- | common/cmd_elf.c | 4 | ||||
-rw-r--r-- | common/cmd_flash.c | 201 | ||||
-rw-r--r-- | common/cmd_fpga.c | 97 | ||||
-rw-r--r-- | common/cmd_jffs2.c | 2012 | ||||
-rw-r--r-- | common/cmd_mii.c | 2 | ||||
-rw-r--r-- | common/cmd_scsi.c | 19 | ||||
-rw-r--r-- | common/cmd_usb.c | 36 | ||||
-rw-r--r-- | common/environment.c | 5 | ||||
-rw-r--r-- | common/hush.c | 18 | ||||
-rw-r--r-- | common/lcd.c | 33 | ||||
-rw-r--r-- | common/lynxkdi.c | 2 | ||||
-rw-r--r-- | common/miiphybb.c | 328 | ||||
-rw-r--r-- | common/miiphyutil.c | 8 | ||||
-rw-r--r-- | common/usb.c | 271 | ||||
-rw-r--r-- | common/usb_storage.c | 134 |
19 files changed, 2757 insertions, 464 deletions
diff --git a/common/cmd_ace.c b/common/cmd_ace.c index c5b08bf772..fb4d3584b5 100644 --- a/common/cmd_ace.c +++ b/common/cmd_ace.c @@ -31,6 +31,12 @@ * available to cmd_fat.c:get_dev and filling in a block device * description that has all the bits needed for FAT support to * read sectors. + * + * According to Xilinx technical support, before accessing the + * SystemACE CF you need to set the following control bits: + * FORCECFGMODE : 1 + * CFGMODE : 0 + * CFGSTART : 0 */ # include <common.h> @@ -95,7 +101,9 @@ static int get_cf_lock(void) int retry = 10; /* CONTROLREG = LOCKREG */ - ace_writew(0x0002, 0x18); + unsigned val=ace_readw(0x18); + val|=0x0002; + ace_writew((val&0xffff), 0x18); /* Wait for MPULOCK in STATUSREG[15:0] */ while (! (ace_readw(0x04) & 0x0002)) { @@ -112,8 +120,9 @@ static int get_cf_lock(void) static void release_cf_lock(void) { - /* CONTROLREG = none */ - ace_writew(0x0000, 0x18); + unsigned val=ace_readw(0x18); + val&=~(0x0002); + ace_writew((val&0xffff), 0x18); } block_dev_desc_t * systemace_get_dev(int dev) @@ -127,6 +136,9 @@ block_dev_desc_t * systemace_get_dev(int dev) systemace_dev.blksz = 512; systemace_dev.removable = 1; systemace_dev.block_read = systemace_read; + + init_part(&systemace_dev); + } return &systemace_dev; @@ -145,6 +157,7 @@ static unsigned long systemace_read(int dev, int retry; unsigned blk_countdown; unsigned char*dp = (unsigned char*)buffer; + unsigned val; if (get_cf_lock() < 0) { unsigned status = ace_readw(0x04); @@ -165,7 +178,7 @@ static unsigned long systemace_read(int dev, retry = 2000; for (;;) { - unsigned val = ace_readw(0x04); + val = ace_readw(0x04); /* If CFDETECT is false, card is missing. */ if (! (val & 0x0010)) { @@ -212,6 +225,11 @@ static unsigned long systemace_read(int dev, /* Write sector count | ReadMemCardData. */ ace_writew((trans&0xff) | 0x0300, 0x14); + /* Reset the configruation controller */ + val = ace_readw(0x18); + val|=0x0080; + ace_writew(val, 0x18); + retry = trans * 16; while (retry > 0) { int idx; @@ -231,6 +249,11 @@ static unsigned long systemace_read(int dev, retry -= 1; } + /* Clear the configruation controller reset */ + val = ace_readw(0x18); + val&=~0x0080; + ace_writew(val, 0x18); + /* Count the blocks we transfer this time. */ start += trans; blk_countdown -= trans; diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index ca834732b8..40e28dd9d2 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -61,24 +61,26 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #endif print_num ("bootflags", bd->bi_bootflags ); #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ - defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300) + defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300) || \ + defined(CONFIG_440EP) || defined(CONFIG_440GR) 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_ML300) +#if defined(CONFIG_405GP) || defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300) || \ + defined(CONFIG_440EP) || defined(CONFIG_440GR) print_str ("pci_busfreq", strmhz(buf, bd->bi_pci_busfreq)); #endif -#else /* ! CONFIG_405GP, CONFIG_405CR, CONFIG_405EP, CONFIG_XILINX_ML300 */ -#if defined(CONFIG_8260) || defined(CONFIG_MPC8560) +#else /* ! CONFIG_405GP, CONFIG_405CR, CONFIG_405EP, CONFIG_XILINX_ML300, 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_8260) || defined(CONFIG_MPC8560) +#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_ML300 */ +#endif /* CONFIG_405GP, CONFIG_405CR, CONFIG_405EP, CONFIG_XILINX_ML300, CONFIG_440EP CONFIG_440GR */ #if defined(CONFIG_MPC8220) print_str ("inpfreq", strmhz(buf, bd->bi_inpfreq)); print_str ("flbfreq", strmhz(buf, bd->bi_flbfreq)); diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index a90735f3f2..c200fd8b86 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -580,12 +580,12 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, kbd->bi_flbfreq /= 1000000L; kbd->bi_vcofreq /= 1000000L; #endif -#if defined(CONFIG_8260) || defined(CONFIG_MPC8560) +#if defined(CONFIG_CPM2) kbd->bi_cpmfreq /= 1000000L; kbd->bi_brgfreq /= 1000000L; kbd->bi_sccfreq /= 1000000L; kbd->bi_vco /= 1000000L; -#endif /* CONFIG_8260 */ +#endif #if defined(CONFIG_MPC5xxx) kbd->bi_ipbfreq /= 1000000L; kbd->bi_pcifreq /= 1000000L; diff --git a/common/cmd_dcr.c b/common/cmd_dcr.c index a91db66e02..3e4e08f95b 100644 --- a/common/cmd_dcr.c +++ b/common/cmd_dcr.c @@ -29,7 +29,7 @@ #include <config.h> #include <command.h> -#if defined(CONFIG_4xx) && defined(CFG_CMD_SETGETDCR) +#if defined(CONFIG_4xx) && (CONFIG_COMMANDS & CFG_CMD_SETGETDCR) /* ====================================================================== * Interpreter command to retrieve an IBM PPC 4xx Device Control Register diff --git a/common/cmd_elf.c b/common/cmd_elf.c index 37286e86a8..eccf2e9e7b 100644 --- a/common/cmd_elf.c +++ b/common/cmd_elf.c @@ -78,7 +78,7 @@ int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * ====================================================================== */ int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { -#if defined(CONFIG_WALNUT405) || \ +#if defined(CONFIG_WALNUT) || \ defined(CFG_VXWORKS_MAC_PTR) DECLARE_GLOBAL_DATA_PTR; #endif @@ -121,7 +121,7 @@ int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * This will vary from board to board */ -#if defined(CONFIG_WALNUT405) +#if defined(CONFIG_WALNUT) tmp = (char *) CFG_NVRAM_BASE_ADDR + 0x500; memcpy ((char *) tmp, (char *) &gd->bd->bi_enetaddr[3], 3); #elif defined(CFG_VXWORKS_MAC_PTR) diff --git a/common/cmd_flash.c b/common/cmd_flash.c index b2728ab1d3..d5be30c54d 100644 --- a/common/cmd_flash.c +++ b/common/cmd_flash.c @@ -27,13 +27,22 @@ #include <common.h> #include <command.h> - #ifdef CONFIG_HAS_DATAFLASH #include <dataflash.h> #endif #if (CONFIG_COMMANDS & CFG_CMD_FLASH) +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +#include <jffs2/jffs2.h> + +/* parition 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 + extern flash_info_t flash_info[]; /* info for FLASH chips */ /* @@ -96,6 +105,95 @@ abbrev_spec (char *str, flash_info_t ** pinfo, int *psf, int *psl) return 1; } +/* + * 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 len_used = 0; /* indicates if the "start +length" form used */ + char *ep; + + *addr_first = simple_strtoul(arg1, &ep, 16); + if (ep == arg1 || *ep != '\0') + return -1; + + if (arg2 && *arg2 == '+'){ + len_used = 1; + ++arg2; + } + + *addr_last = simple_strtoul(arg2, &ep, 16); + if (ep == arg2 || *ep != '\0') + return -1; + + if (len_used){ + char found = 0; + ulong bank; + + /* + * *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. + */ + + /* find the end addr of the sector where the *addr_last is */ + for (bank = 0; bank < CFG_MAX_FLASH_BANKS && !found; ++bank){ + int i; + flash_info_t *info = &flash_info[bank]; + for (i = 0; i < info->sector_count && !found; ++i){ + /* get the end address of the sector */ + ulong sector_end_addr; + 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_last <= sector_end_addr && + *addr_last >= info->start[i]){ + /* sector found */ + found = 1; + /* adjust *addr_last if necessary */ + if (*addr_last < sector_end_addr){ + *addr_last = sector_end_addr; + } + } + } /* sector */ + } /* bank */ + if (!found){ + /* error, addres not in flash */ + printf("Error: end address (0x%08lx) not in flash!\n", + *addr_last); + 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, @@ -206,11 +304,17 @@ int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) flash_print_info (&flash_info[bank-1]); return 0; } + int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { flash_info_t *info; ulong bank, addr_first, addr_last; int n, sect_first, sect_last; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + struct mtd_device *dev; + struct part_info *part; + u8 dev_type, dev_num, pnum; +#endif int rcode = 0; if (argc < 2) { @@ -238,6 +342,32 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return rcode; } +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + /* erase <part-id> - erase partition */ + if ((argc == 2) && (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 Parition %s, " + "bank %d, 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) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; @@ -256,8 +386,10 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return rcode; } - addr_first = simple_strtoul(argv[1], NULL, 16); - addr_last = simple_strtoul(argv[2], NULL, 16); + if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){ + printf ("Bad address format\n"); + return 1; + } if (addr_first >= addr_last) { printf ("Usage:\n%s\n", cmdtp->usage); @@ -310,6 +442,11 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) flash_info_t *info; ulong bank, addr_first, addr_last; int i, p, n, sect_first, sect_last; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + struct mtd_device *dev; + struct part_info *part; + u8 dev_type, dev_num, pnum; +#endif int rcode = 0; #ifdef CONFIG_HAS_DATAFLASH int status; @@ -398,6 +535,33 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return rcode; } +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + /* protect on/off <part-id> */ + if ((argc == 3) && (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 Parition %s, " + "bank %d, 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) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; @@ -435,8 +599,10 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return rcode; } - addr_first = simple_strtoul(argv[2], NULL, 16); - addr_last = simple_strtoul(argv[3], NULL, 16); + if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){ + printf("Bad address format\n"); + return 1; + } if (addr_first >= addr_last) { printf ("Usage:\n%s\n", cmdtp->usage); @@ -498,6 +664,15 @@ int flash_sect_protect (int p, ulong addr_first, ulong addr_last) /**************************************************/ +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +# 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, @@ -511,8 +686,12 @@ U_BOOT_CMD( "erase - erase FLASH memory\n", "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\n" ); @@ -521,16 +700,28 @@ U_BOOT_CMD( "protect - enable or disable FLASH write protection\n", "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\n" ); +#undef TMP_ERASE +#undef TMP_PROT_ON +#undef TMP_PROT_OFF + #endif /* CFG_CMD_FLASH */ diff --git a/common/cmd_fpga.c b/common/cmd_fpga.c index 900d35aa44..c4b7392949 100644 --- a/common/cmd_fpga.c +++ b/common/cmd_fpga.c @@ -59,25 +59,30 @@ static int fpga_get_op (char *opstr); /* Convert bitstream data and load into the fpga */ int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size) { - int length; - char* swapdata; - int swapsize; + unsigned int length; + unsigned char* swapdata; + unsigned int swapsize; char buffer[80]; - char *ptr; - char *dataptr; - int data; - int i; + unsigned char *ptr; + unsigned char *dataptr; + unsigned char data; + unsigned int i; int rc; dataptr = fpgadata; #if CFG_FPGA_XILINX - /* skip the first 13 bytes of the bitsteam, their meaning is unknown */ - dataptr+=13; + /* 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("fpga_loadbitstream: Design name identifier not recognized in bitstream.\n"); + PRINTF ("%s: Design name identifier not recognized in bitstream\n", + __FUNCTION__ ); return FPGA_FAIL; } @@ -86,61 +91,71 @@ int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size) for(i=0;i<length;i++) buffer[i]=*dataptr++; - buffer[length-5]='\0'; /* remove filename extension */ - PRINTF("fpga_loadbitstream: design name = \"%s\".\n",buffer); + printf(" design filename = \"%s\"\n", buffer); /* get part number (identifier, length, string) */ if (*dataptr++ != 0x62) { - printf("fpga_loadbitstream: Part number identifier not recognized in bitstream.\n"); + printf("%s: Part number identifier not recognized in bitstream\n", + __FUNCTION__ ); return FPGA_FAIL; } - length = (*dataptr << 8) + *(dataptr+1); dataptr+=2; + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; for(i=0;i<length;i++) buffer[i]=*dataptr++; - PRINTF("fpga_loadbitstream: part number = \"%s\".\n",buffer); + printf(" part number = \"%s\"\n", buffer); /* get date (identifier, length, string) */ if (*dataptr++ != 0x63) { - printf("fpga_loadbitstream: Date identifier not recognized in bitstream.\n"); + printf("%s: Date identifier not recognized in bitstream\n", + __FUNCTION__); return FPGA_FAIL; } - length = (*dataptr << 8) + *(dataptr+1); dataptr+=2; + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; for(i=0;i<length;i++) buffer[i]=*dataptr++; - PRINTF("fpga_loadbitstream: date = \"%s\".\n",buffer); + printf(" date = \"%s\"\n", buffer); /* get time (identifier, length, string) */ if (*dataptr++ != 0x64) { - printf("fpga_loadbitstream: Time identifier not recognized in bitstream.\n"); + printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__); return FPGA_FAIL; } - length = (*dataptr << 8) + *(dataptr+1); dataptr+=2; + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; for(i=0;i<length;i++) buffer[i]=*dataptr++; - PRINTF("fpga_loadbitstream: time = \"%s\".\n",buffer); + printf(" time = \"%s\"\n", buffer); /* get fpga data length (identifier, length) */ if (*dataptr++ != 0x65) { - printf("fpga_loadbitstream: Data length identifier not recognized in bitstream.\n"); + printf("%s: Data length identifier not recognized in bitstream\n", + __FUNCTION__); return FPGA_FAIL; } - swapsize = ((long)*dataptr<<24) + ((long)*(dataptr+1)<<16) + ((long)*(dataptr+2)<<8) + (long)*(dataptr+3); + swapsize = ((unsigned int) *dataptr <<24) + + ((unsigned int) *(dataptr+1) <<16) + + ((unsigned int) *(dataptr+2) <<8 ) + + ((unsigned int) *(dataptr+3) ) ; dataptr+=4; - PRINTF("fpga_loadbitstream: bytes in bitstream = %d.\n",swapsize); + printf(" bytes in bitstream = %d\n", swapsize); /* check consistency of length obtained */ if (swapsize >= size) { - printf("fpga_loadbitstream: Could not find right length of data in bitstream.\n"); + printf("%s: Could not find right length of data in bitstream\n", + __FUNCTION__); return FPGA_FAIL; } /* allocate memory */ - swapdata = (char *)malloc(swapsize); + swapdata = (unsigned char *)malloc(swapsize); if (swapdata == NULL) { - printf("fpga_loadbitstream: Could not allocate %d bytes memory !\n",swapsize); + printf("%s: Could not allocate %d bytes memory !\n", + __FUNCTION__, swapsize); return FPGA_FAIL; } @@ -164,7 +179,7 @@ int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size) free(swapdata); return rc; #else - printf("Bitstream support only for Xilinx devices.\n"); + printf("Bitstream support only for Xilinx devices\n"); return FPGA_FAIL; #endif } @@ -196,25 +211,25 @@ int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) data_size = simple_strtoul (argv[4], NULL, 16); case 4: /* fpga <op> <dev> <data> */ fpga_data = (void *) simple_strtoul (argv[3], NULL, 16); - PRINTF ("do_fpga: fpga_data = 0x%x\n", - (uint) 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 ("do_fpga: device = %d\n", dev); + 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 ("do_fpga: Assuming buffer pointer in arg 3\n"); + PRINTF ("%s: Assuming buffer pointer in arg 3\n", + __FUNCTION__); fpga_data = (void *) dev; - PRINTF ("do_fpga: fpga_data = 0x%x\n", - (uint) 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 ("do_fpga: Too many or too few args (%d)\n", - argc); + PRINTF ("%s: Too many or too few args (%d)\n", + __FUNCTION__, argc); op = FPGA_NONE; /* force usage display */ break; } @@ -241,7 +256,7 @@ int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) break; default: - printf ("Unknown operation.\n"); + printf ("Unknown operation\n"); fpga_usage (cmdtp); break; } @@ -281,8 +296,8 @@ U_BOOT_CMD (fpga, 6, 1, do_fpga, "fpga - loadable FPGA image support\n", "fpga [operation type] [device number] [image address] [image size]\n" "fpga operations:\n" - "\tinfo\tlist known device information.\n" - "\tload\tLoad device from memory buffer.\n" - "\tloadb\tLoad device from bitstream buffer (Xilinx devices only).\n" - "\tdump\tLoad device to memory buffer.\n"); + "\tinfo\tlist known device information\n" + "\tload\tLoad device from memory buffer\n" + "\tloadb\tLoad device from bitstream buffer (Xilinx devices only)\n" + "\tdump\tLoad device to memory buffer\n"); #endif /* CONFIG_FPGA && CONFIG_COMMANDS & CFG_CMD_FPGA */ diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c index 45713a38bc..7ab6e9ca7a 100644 --- a/common/cmd_jffs2.c +++ b/common/cmd_jffs2.c @@ -1,11 +1,23 @@ /* * (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. * @@ -26,103 +38,1729 @@ */ /* - * Boot support + * 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'<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 <s_record.h> -#include <jffs2/load_kernel.h> -#include <net.h> +#include <malloc.h> +#include <jffs2/jffs2.h> +#include <linux/mtd/nand.h> +#include <linux/list.h> +#include <linux/ctype.h> #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) #include <cramfs/cramfs_fs.h> +/* enable/disable debugging messages */ +#define DEBUG +#undef DEBUG + +#ifdef DEBUG +# 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 1 + +#ifdef CONFIG_JFFS2_CMDLINE +/* default values for mtdids and mtdparts variables */ +#if defined(MTDIDS_DEFAULT) +static const char *const mtdids_default = MTDIDS_DEFAULT; +#else +#warning "MTDIDS_DEFAULT not defined!" +static const char *const mtdids_default = NULL; +#endif + +#if defined(MTDPARTS_DEFAULT) +static const char *const mtdparts_default = MTDPARTS_DEFAULT; +#else +#warning "MTDPARTS_DEFAULT not defined!" +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; +#endif /* #ifdef CONFIG_JFFS2_CMDLINE */ + +/* current active device and partition number */ +static struct mtd_device *current_dev = NULL; +static u8 current_partnum = 0; + 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); -static int part_num=0; +static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num); -#ifndef CFG_JFFS_CUSTOM_PART +/* command line only routines */ +#ifdef CONFIG_JFFS2_CMDLINE -#define CFG_JFFS_SINGLE_PART 1 +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); -static struct part_info part; +/** + * 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); -#ifndef CONFIG_JFFS2_NAND + switch (**retptr) { + case 'G': + case 'g': + ret <<= 10; + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + (*retptr)++; + default: + break; + } -struct part_info* -jffs2_part_info(int part_num) + 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) { - extern flash_info_t flash_info[]; /* info for FLASH chips */ +#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, "%lug", size/SIZE_GB); + else if ((size % SIZE_MB) == 0) + sprintf(buf, "%lum", size/SIZE_MB); + else if (size % SIZE_KB == 0) + sprintf(buf, "%luk", size/SIZE_KB); + else + sprintf(buf, "%lu", size); +} + +/** + * Save current device and partition in environment variable 'partition'. + */ +static void current_save(void) +{ + char buf[16]; + + DEBUGF("--- current_save ---\n"); + + if (current_dev) { + sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type), + current_dev->id->num, current_partnum); + + setenv("partition", buf); + strncpy(last_partition, buf, 16); + + DEBUGF("=> partition %s\n", buf); + } else { + setenv("partition", NULL); + last_partition[0] = '\0'; + + DEBUGF("=> partition NULL\n"); + } +} + +/** + * Performs sanity check for supplied NOR flash partition. Table of existing + * NOR flash devices is searched and partition device is located. Alignment + * with the granularity of NOR flash sectors 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_nor(struct mtdids *id, struct part_info *part) +{ +#if (CONFIG_COMMANDS & CFG_CMD_FLASH) + /* info for FLASH chips */ + extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + flash_info_t *flash; + int offset_aligned; + u32 end_offset; int i; - if(part_num==0){ + flash = &flash_info[id->num]; + + offset_aligned = 0; + for (i = 0; i < flash->sector_count; i++) { + if ((flash->start[i] - flash->start[0]) == part->offset) { + offset_aligned = 1; + break; + } + } + if (offset_aligned == 0) { + printf("%s%d: partition (%s) start offset alignment incorrect\n", + MTD_DEV_TYPE(id->type), id->num, part->name); + return 1; + } + + end_offset = part->offset + part->size; + for (i = 0; i < flash->sector_count; i++) { + if ((flash->start[i] - flash->start[0]) == end_offset) + return 0; + } + + if (flash->size == end_offset) + return 0; + + printf("%s%d: partition (%s) size alignment incorrect\n", + MTD_DEV_TYPE(id->type), id->num, part->name); +#endif + return 1; +} - if(part.usr_priv==(void*)1) - return ∂ +/** + * Performs sanity check for supplied NAND flash partition. Table of existing + * NAND 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_nand(struct mtdids *id, struct part_info *part) +{ +#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) + /* info for NAND chips */ + extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; + struct nand_chip *nand; - memset(&part, 0, sizeof(part)); + nand = &nand_dev_desc[id->num]; -#if defined(CFG_JFFS2_FIRST_SECTOR) - part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR]; + if ((unsigned long)(part->offset) % nand->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 % nand->erasesize) { + printf("%s%d: partition (%s) size alignment incorrect\n", + MTD_DEV_TYPE(id->type), id->num, part->name); + return 1; + } + + return 0; #else - part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[0]; + return 1; #endif +} + +/** + * 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 %08lx beyond flash size %08lx\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; + } + + if (id->type == MTD_DEV_TYPE_NAND) + return part_validate_nand(id, part); + else if (id->type == MTD_DEV_TYPE_NOR) + return part_validate_nor(id, part); + else + DEBUGF("part_validate: invalid dev type\n"); + + return 1; +} + +/** + * 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) +{ + /* 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_dev) { + /* we are modyfing partitions for the current device, + * update current */ + struct part_info *curr_pi; + curr_pi = jffs2_part_info(current_dev, current_partnum); + + if (curr_pi) { + if (curr_pi == part) { + printf("current partition deleted, resetting current to 0\n"); + current_partnum = 0; + current_save(); + } else if (part->offset <= curr_pi->offset) { + current_partnum--; + current_save(); + } + } + } + + + jffs2_free_cache(part); + list_del(&part->link); + free(part); + dev->num_parts--; + + 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); + + jffs2_free_cache(part_tmp); + 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)) { + DEBUGF("part_sort_add: list empty\n"); + list_add(&part->link, &dev->parts); + 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_dev) + curr_pi = jffs2_part_info(current_dev, current_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); + + if (curr_pi && (pi->offset <= curr_pi->offset)) { + /* we are modyfing partitions for the current + * device, update current */ + current_partnum++; + current_save(); + } + + return 0; + } + } + list_add_tail(&part->link, &dev->parts); + 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; - /* Figure out flash partition size */ - for (i = CFG_JFFS2_FIRST_BANK; i < CFG_JFFS2_NUM_BANKS+CFG_JFFS2_FIRST_BANK; i++) - part.size += flash_info[i].size; + /* partition is ok, add it to the list */ + if (part_sort_add(dev, part) != 0) + return 1; -#if defined(CFG_JFFS2_FIRST_SECTOR) && (CFG_JFFS2_FIRST_SECTOR > 0) - part.size -= - flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] - - flash_info[CFG_JFFS2_FIRST_BANK].start[0]; + dev->num_parts++; + 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 */ + DEBUGF("'-': 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; + 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); + + DEBUGF("+ 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; +} +#endif/* #ifdef CONFIG_JFFS2_CMDLINE */ + +/** + * 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 device_validate(u8 type, u8 num, u32 *size) +{ + if (type == MTD_DEV_TYPE_NOR) { +#if (CONFIG_COMMANDS & CFG_CMD_FLASH) + if (num < CFG_MAX_FLASH_BANKS) { + extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + *size = flash_info[num].size; + return 0; + } + + printf("no such FLASH device: %s%d (valid range 0 ... %d\n", + MTD_DEV_TYPE(type), num, CFG_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) && (CONFIG_COMMANDS & CFG_CMD_NAND) + if (num < CFG_MAX_NAND_DEVICE) { + extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; + *size = nand_dev_desc[num].totlen; + return 0; + } + + printf("no such NAND device: %s%d (valid range 0 ... %d)\n", + MTD_DEV_TYPE(type), num, CFG_MAX_NAND_DEVICE - 1); +#else + printf("support for NAND devices not present\n"); #endif + } + + return 1; +} + +#ifdef CONFIG_JFFS2_CMDLINE +/** + * 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_dev) { + /* we just deleted current device */ + if (list_empty(&devices)) { + current_dev = NULL; + } else { + /* reset first partition from first dev from the + * devices list as current */ + current_dev = list_entry(devices.next, struct mtd_device, link); + current_partnum = 0; + } + current_save(); + } + + + 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 + */ +static 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) +{ + if (list_empty(&devices)) { + current_dev = dev; + current_partnum = 0; + current_save(); + } + + list_add_tail(&dev->link, &devices); +} + +/** + * 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; + + p = mtd_dev; + *retdev = NULL; + *ret = NULL; + + DEBUGF("===device_parse===\n"); + + /* fetch <mtd-id> */ + mtd_id = p; + 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; + } + + DEBUGF("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, ';'); + DEBUGF("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; + } + + DEBUGF("\ntotal partitions: %d\n", num_parts); + + /* check for next device presence */ + if (p) { + if (*p == ';') { + *ret = ++p; + } else if (*p == '\0') { + *ret = p; + } else { + printf("unexpected character '%c' at the end of device\n", *p); + *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 = 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; + + DEBUGF("===\n\n"); + return 0; +} + +/** + * Initialize global device list. + * + * @return 0 on success, 1 otherwise + */ +static int devices_init(void) +{ + last_parts[0] = '\0'; + current_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; + + DEBUGF("--- 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); + + DEBUGF("entry: '%s' (len = %d)\n", + id->mtd_id, strlen(id->mtd_id)); - /* Mark the struct as ready */ - part.usr_priv=(void*)1; + if (mtd_id_len != strlen(id->mtd_id)) + continue; + if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0) + return id; + } + + return NULL; +} +#endif /* #ifdef CONFIG_JFFS2_CMDLINE */ + +/** + * Parse device id string <dev-id> := 'nand'|'nor'<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 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 { + 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; +} + +#ifdef CONFIG_JFFS2_CMDLINE +/** + * 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; + + DEBUGF("--- 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) { + 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; +} + +/** + * Format and print out a partition list for each device from global device + * list. + */ +static void list_partitions(void) +{ + struct list_head *dentry, *pentry; + struct part_info *part; + struct mtd_device *dev; + int part_num; + + DEBUGF("\n---list_partitions---\n"); + list_for_each(dentry, &devices) { + dev = list_entry(dentry, struct mtd_device, link); + 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\t\tsize\t\toffset\t\tmask_flags\n"); + + /* list partitions for given device */ + part_num = 0; + list_for_each(pentry, &dev->parts) { + part = list_entry(pentry, struct part_info, link); + printf(" %d: %-22s\t0x%08x\t0x%08x\t%d\n", + part_num, part->name, part->size, + part->offset, part->mask_flags); + + part_num++; + } + } + if (list_empty(&devices)) + printf("no partitions defined\n"); + + /* current_dev is not NULL only when we have non empty device list */ + if (current_dev) { + part = jffs2_part_info(current_dev, current_partnum); + if (part) { + printf("\nactive partition: %s%d,%d - (%s) 0x%08lx @ 0x%08lx\n", + MTD_DEV_TYPE(current_dev->id->type), + current_dev->id->num, current_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); + printf("mtdparts: %s\n", mtdparts_default); +} + +/** + * 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 + * @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) +{ + u8 type, dnum, pnum; + const char *p; + + DEBUGF("--- find_dev_and_part ---\nid = %s\n", id); + + p = id; + *dev = NULL; + *part = NULL; + *part_num = 0; + + if (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; + } - return ∂ + if ((*dev = device_find(type, dnum)) == NULL) { + printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum); + return 1; } + + if ((*part = jffs2_part_info(*dev, pnum)) == NULL) { + printf("no such partition\n"); + *dev = NULL; + return 1; + } + + *part_num = pnum; + return 0; } -#else /* CONFIG_JFFS2_NAND */ +/** + * 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) { + + DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\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; +} -struct part_info* -jffs2_part_info(int part_num) +/** + * 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) { - if(part_num==0){ + const char *p = mtdparts; + struct mtd_device *dev; + int err = 1; + + DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p); + + /* delete all devices and partitions */ + if (devices_init() != 0) { + printf("could not initialise device list\n"); + return err; + } - if(part.usr_priv==(void*)1) - return ∂ + /* re-read 'mtdparts' variable, devices_init may be updating env */ + p = getenv("mtdparts"); - memset(&part, 0, sizeof(part)); + 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; + + DEBUGF("+ 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; + } - part.offset = (char *)CONFIG_JFFS2_NAND_OFF; - part.size = CONFIG_JFFS2_NAND_SIZE; /* the bigger size the slower jffs2 */ + 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; -#ifndef CONFIG_JFFS2_NAND_DEV -#define CONFIG_JFFS2_NAND_DEV 0 + DEBUGF("\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); + DEBUGF("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'<dev-num> */ + if (id_parse(p, &p, &type, &num) != 0) + break; + + if (*p != '=') { + printf("mtdids: incorrect <dev-num>\n"); + break; + } + p++; + + /* check if requested device exists */ + if (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); + + DEBUGF("+ 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]; + + DEBUGF("\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); + + DEBUGF("last_ids : %s\n", last_ids); + DEBUGF("env_ids : %s\n", ids); + DEBUGF("last_parts: %s\n", last_parts); + DEBUGF("env_parts : %s\n\n", parts); + + DEBUGF("last_partition : %s\n", last_partition); + DEBUGF("env_partition : %s\n", current_partition); + + /* if mtdids varible is empty try to use defaults */ + if (!ids) { + if (mtdids_default) { + DEBUGF("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) { + device_delall(&devices); + 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_dev = list_entry(devices.next, struct mtd_device, link); + current_partnum = 0; + current_save(); + + DEBUGF("mtdparts_init: current_dev = %s%d, current_partnum = %d\n", + MTD_DEV_TYPE(current_dev->id->type), + current_dev->id->num, current_partnum); + } + + /* mtdparts variable was reset to NULL, delete all devices/partitions */ + if (!parts && (last_parts[0] != '\0')) + return 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; + + DEBUGF("--- getting current partition: %s\n", tmp_ep); + + if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) { + current_dev = cdev; + current_partnum = pnum; + current_save(); + } + } else if (getenv("partition") == NULL) { + DEBUGF("no partition variable set, setting...\n"); + current_save(); + } + + return 0; +} +#else /* #ifdef CONFIG_JFFS2_CMDLINE */ +/* + * 'Static' version of command line mtdparts_init() routine. Single partition on + * a single device configuration. + */ + +/** + * 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; + u32 size; + char *dev_name; + + DEBUGF("\n---mtdparts_init---\n"); + if (!initialized) { + struct mtdids *id; + struct part_info *part; + + initialized = 1; + current_dev = (struct mtd_device *) + malloc(sizeof(struct mtd_device) + + sizeof(struct part_info) + + sizeof(struct mtdids)); + if (!current_dev) { + printf("out of memory\n"); + return 1; + } + memset(current_dev, 0, sizeof(struct mtd_device) + + sizeof(struct part_info) + sizeof(struct mtdids)); + + id = (struct mtdids *)(current_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 - /* nand device with the JFFS2 parition plus 1 */ - part.usr_priv = (void*)(CONFIG_JFFS2_NAND_DEV+1); - return ∂ + + if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) || + (device_validate(id->type, id->num, &size) != 0)) { + printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num); + free(current_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_dev; + INIT_LIST_HEAD(&part->link); + + /* recalculate size if needed */ + if (part->size == SIZE_REMAINING) + part->size = id->size - part->offset; + + DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n", + part->name, part->size, part->offset); + + /* device */ + current_dev->id = id; + INIT_LIST_HEAD(¤t_dev->link); + current_dev->num_parts = 1; + INIT_LIST_HEAD(¤t_dev->parts); + list_add(&part->link, ¤t_dev->parts); } + return 0; } +#endif /* #ifdef CONFIG_JFFS2_CMDLINE */ -#endif /* CONFIG_JFFS2_NAND */ -#endif /* ifndef CFG_JFFS_CUSTOM_PART */ +/** + * 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); -int -do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) + 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 *argv[]) { - struct part_info* jffs2_part_info(int); - int jffs2_1pass_load(char *, struct part_info *,const char *); char *fsname; char *filename; int size; @@ -143,7 +1781,11 @@ do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) filename = argv[2]; } - if (0 != (part=jffs2_part_info(part_num))){ + /* make sure we are in sync with env variables */ + if (mtdparts_init() !=0) + return 1; + + if ((part = jffs2_part_info(current_dev, current_partnum))){ /* check partition type for cramfs */ fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2"); @@ -168,15 +1810,21 @@ do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return !(size > 0); } - puts ("Active partition not valid\n"); - return 0; + return 1; } -int -do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +/** + * 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 *argv[]) { - struct part_info* jffs2_part_info(int); - int jffs2_1pass_ls(struct part_info *,char *); char *filename = "/"; int ret; struct part_info *part; @@ -184,7 +1832,11 @@ do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) if (argc == 2) filename = argv[1]; - if (0 != (part=jffs2_part_info(part_num))){ + /* make sure we are in sync with env variables */ + if (mtdparts_init() !=0) + return 1; + + if ((part = jffs2_part_info(current_dev, current_partnum))){ /* check partition type for cramfs */ if (cramfs_check(part)) { @@ -194,22 +1846,32 @@ do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) ret = jffs2_1pass_ls(part, filename); } - return (ret == 1); + return ret ? 0 : 1; } - puts ("Active partition not valid\n"); - return 0; + return 1; } -int -do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +/** + * 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 *argv[]) { - struct part_info* jffs2_part_info(int); - int jffs2_1pass_info(struct part_info *); struct part_info *part; char *fsname; int ret; - if ((part=jffs2_part_info(part_num))){ + /* make sure we are in sync with env variables */ + if (mtdparts_init() !=0) + return 1; + + if ((part = jffs2_part_info(current_dev, current_partnum))){ /* check partition type for cramfs */ fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2"); @@ -222,50 +1884,161 @@ do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) ret = jffs2_1pass_info(part); } - return (ret == 1); + return ret ? 0 : 1; + } + return 1; +} + +/* command line only */ +#ifdef CONFIG_JFFS2_CMDLINE +/** + * 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_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *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; } - puts ("Active partition not valid\n"); + + if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0) + return 1; + + current_dev = dev; + current_partnum = pnum; + current_save(); + + printf("partition changed to %s%d,%d\n", + MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum); + return 0; } -#ifndef CFG_JFFS_SINGLE_PART -int -do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +/** + * 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_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { - int tmp_part; - char str_part_num[3]; - struct part_info* jffs2_part_info(int); + if (argc == 2) { + if (strcmp(argv[1], "default") == 0) { + setenv("mtdids", (char *)mtdids_default); + setenv("mtdparts", (char *)mtdparts_default); + setenv("partition", NULL); - if (argc >= 2) { - tmp_part = simple_strtoul(argv[1], NULL, 16); - } else { - puts ("Need partition number in argument list\n"); - return 0; + 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); + + /* devices_init() calls current_save() */ + return devices_init(); + } } - if (jffs2_part_info(tmp_part)){ - printf("Partition changed to %d\n",tmp_part); - part_num=tmp_part; - sprintf(str_part_num, "%d", part_num); - setenv("partition", str_part_num); + /* make sure we are in sync with env variables */ + if (mtdparts_init() != 0) + return 1; + + if (argc == 1) { + list_partitions(); return 0; } - printf("Partition %d is not valid partiton\n",tmp_part); - return 0; + /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ + if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) { +#define PART_ADD_DESC_MAXLEN 64 + char tmpbuf[PART_ADD_DESC_MAXLEN]; + u8 type, num, len; + struct mtd_device *dev; + struct mtd_device *dev_tmp; + struct mtdids *id; + struct part_info *p; -} + if (id_parse(argv[2], NULL, &type, &num) != 0) + return 1; -U_BOOT_CMD( - chpart, 2, 0, do_jffs2_chpart, - "chpart\t- change active partition\n", - " - change active partition\n" -); -#endif /* CFG_JFFS_SINGLE_PART */ + 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] : ""); + DEBUGF("add tmpbuf: %s\n", tmpbuf); + + if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) + return 1; + + DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), + dev->id->num, dev->id->mtd_id); + + if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) { + device_add(dev); + } else { + /* merge new partition with existing ones*/ + p = list_entry(dev->parts.next, struct part_info, link); + if (part_add(dev_tmp, p) != 0) { + 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)) { + DEBUGF("del: part-id = %s\n", argv[2]); + + return delete_partition(argv[2]); + } + + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} +#endif /* #ifdef CONFIG_JFFS2_CMDLINE */ +/***************************************************/ U_BOOT_CMD( fsload, 3, 0, do_jffs2_fsload, "fsload\t- load binary file from a filesystem image\n", @@ -273,6 +2046,12 @@ U_BOOT_CMD( " - load binary file from flash bank\n" " with offset 'off'\n" ); +U_BOOT_CMD( + ls, 2, 1, do_jffs2_ls, + "ls\t- list files in a directory (default /)\n", + "[ directory ]\n" + " - list files in a directory.\n" +); U_BOOT_CMD( fsinfo, 1, 1, do_jffs2_fsinfo, @@ -280,11 +2059,50 @@ U_BOOT_CMD( " - print information about filesystems\n" ); +#ifdef CONFIG_JFFS2_CMDLINE U_BOOT_CMD( - ls, 2, 1, do_jffs2_ls, - "ls\t- list files in a directory (default /)\n", - "[ directory ]\n" - " - list files in a directory.\n" + chpart, 2, 0, do_jffs2_chpart, + "chpart\t- change active partition\n", + "part-id\n" + " - change active partition (e.g. part-id = nand0,1)\n" ); +U_BOOT_CMD( + mtdparts, 6, 0, do_jffs2_mtdparts, + "mtdparts- define flash/nand partitions\n", + "\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" + "mtdparts default\n" + " - reset partition table to defaults\n\n" + "-----\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'<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)\n" +); +#endif /* #ifdef CONFIG_JFFS2_CMDLINE */ + +/***************************************************/ + #endif /* CFG_CMD_JFFS2 */ diff --git a/common/cmd_mii.c b/common/cmd_mii.c index 5be4e6374d..3d260ab9bd 100644 --- a/common/cmd_mii.c +++ b/common/cmd_mii.c @@ -549,7 +549,7 @@ int do_mii (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) U_BOOT_CMD( mii, 5, 1, do_mii, "mii - MII utility commands\n", - "info <addr> - display MII PHY info\n" + "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" diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c index 7ee9d8efb1..ec53790f81 100644 --- a/common/cmd_scsi.c +++ b/common/cmd_scsi.c @@ -585,4 +585,23 @@ void scsi_setup_inquiry(ccb * pccb) pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ } + +U_BOOT_CMD( + scsi, 5, 1, do_scsi, + "scsi - SCSI sub-system\n", + "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'\n" +); + +U_BOOT_CMD( + scsiboot, 3, 1, do_scsiboot, + "scsiboot- boot from SCSI device\n", + "loadAddr dev:part\n" +); + #endif /* #if (CONFIG_COMMANDS & CFG_CMD_SCSI) */ diff --git a/common/cmd_usb.c b/common/cmd_usb.c index fbddb12dfd..0738f55303 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -448,11 +448,16 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) block_dev_desc_t *stor_dev; #endif - if ((strncmp(argv[1],"reset",5) == 0) || - (strncmp(argv[1],"start",5) == 0)){ + if ((strncmp(argv[1], "reset", 5) == 0) || + (strncmp(argv[1], "start", 5) == 0)){ usb_stop(); printf("(Re)start USB...\n"); - usb_init(); + i = usb_init(); +#ifdef CONFIG_USB_STORAGE + /* try to recognize storage devices immediately */ + if (i >= 0) + usb_stor_curr_dev = usb_stor_scan(1); +#endif return 0; } if (strncmp(argv[1],"stop",4) == 0) { @@ -513,15 +518,18 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } #ifdef CONFIG_USB_STORAGE - if (strncmp(argv[1],"scan",4) == 0) { - printf("Scan for storage device:\n"); - usb_stor_curr_dev=usb_stor_scan(1); - if (usb_stor_curr_dev==-1) { - printf("No device found. Not initialized?\n"); - return 1; - } + if (strncmp(argv[1], "scan", 4) == 0) { + printf(" NOTE: this command is obsolete and will be phased out\n"); + printf(" please use 'usb storage' for USB storage devices information\n\n"); + usb_stor_info(); return 0; } + + if (strncmp(argv[1], "stor", 4) == 0) { + usb_stor_info(); + return 0; + } + if (strncmp(argv[1],"part",4) == 0) { int devno, ok; for (ok=0, devno=0; devno<USB_MAX_STOR_DEV; ++devno) { @@ -560,8 +568,8 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 1; } } - if (strcmp(argv[1],"dev") == 0) { - if (argc==3) { + if (strncmp(argv[1], "dev", 3) == 0) { + if (argc == 3) { int dev = (int)simple_strtoul(argv[2], NULL, 10); printf ("\nUSB device %d: ", dev); if (dev >= USB_MAX_STOR_DEV) { @@ -608,8 +616,8 @@ U_BOOT_CMD( "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 scan - (re-)scan USB bus for storage devices\n" - "usb device [dev] - show or set current USB storage device\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" diff --git a/common/environment.c b/common/environment.c index 61a8d245f9..c7f54c6bd8 100644 --- a/common/environment.c +++ b/common/environment.c @@ -21,7 +21,12 @@ * 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> /* diff --git a/common/hush.c b/common/hush.c index 47680edec3..eb7f7f1560 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1022,12 +1022,30 @@ static void get_user_input(struct in_str *i) int n; static char the_command[CFG_CBSIZE]; +#ifdef CONFIG_BOOT_RETRY_TIME +# ifdef CONFIG_RESET_TO_RETRY + extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +# else +# 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(CFG_PROMPT); } else { n = readline(CFG_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; diff --git a/common/lcd.c b/common/lcd.c index 66506381a5..a85599dd76 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -58,6 +58,15 @@ /************************************************************************/ #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) +# error Default Color Map overlaps with Logo Color Map +# endif +#endif ulong lcd_setmem (ulong addr); @@ -269,7 +278,7 @@ static void lcd_drawchars (ushort x, ushort y, uchar *str, int count) static inline void lcd_puts_xy (ushort x, ushort y, uchar *s) { -#if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO) +#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO) lcd_drawchars (x, y+BMP_LOGO_HEIGHT, s, strlen (s)); #else lcd_drawchars (x, y, s, strlen (s)); @@ -280,7 +289,7 @@ static inline void lcd_puts_xy (ushort x, ushort y, uchar *s) static inline void lcd_putc_xy (ushort x, ushort y, uchar c) { -#if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO) +#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); @@ -420,7 +429,7 @@ static int lcd_init (void *lcdbase) /* Initialize the console */ console_col = 0; -#ifdef LCD_INFO_BELOW_LOGO +#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 */ @@ -673,12 +682,12 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) static void *lcd_logo (void) { -#ifdef LCD_INFO +#ifdef CONFIG_LCD_INFO DECLARE_GLOBAL_DATA_PTR; char info[80]; char temp[32]; -#endif /* LCD_INFO */ +#endif /* CONFIG_LCD_INFO */ #ifdef CONFIG_SPLASH_SCREEN char *s; @@ -700,7 +709,7 @@ static void *lcd_logo (void) #endif /* CONFIG_LCD_LOGO */ #ifdef CONFIG_MPC823 -#ifdef LCD_INFO +# ifdef CONFIG_LCD_INFO sprintf (info, "%s (%s - %s) ", U_BOOT_VERSION, __DATE__, __TIME__); lcd_drawchars (LCD_INFO_X, LCD_INFO_Y, info, strlen(info)); @@ -711,7 +720,7 @@ static void *lcd_logo (void) sprintf (info, " Wolfgang DENK, wd@denx.de"); lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 2, info, strlen(info)); -#ifdef LCD_INFO_BELOW_LOGO +# ifdef CONFIG_LCD_INFO_BELOW_LOGO sprintf (info, "MPC823 CPU at %s MHz", strmhz(temp, gd->cpu_clk)); lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 3, @@ -721,7 +730,7 @@ static void *lcd_logo (void) gd->bd->bi_flashsize >> 20 ); lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 4, info, strlen(info)); -#else +# else /* leave one blank line */ sprintf (info, "MPC823 CPU at %s MHz, %ld MB RAM, %ld MB Flash", @@ -731,15 +740,15 @@ static void *lcd_logo (void) lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 4, info, strlen(info)); +# endif /* CONFIG_LCD_INFO_BELOW_LOGO */ +# endif /* CONFIG_LCD_INFO */ #endif /* CONFIG_MPC823 */ -#endif /* LCD_INFO_BELOW_LOGO */ -#endif /* LCD_INFO */ -#if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO) +#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 */ +#endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */ } /************************************************************************/ diff --git a/common/lynxkdi.c b/common/lynxkdi.c index 14aa175b18..797d8cc880 100644 --- a/common/lynxkdi.c +++ b/common/lynxkdi.c @@ -20,7 +20,7 @@ #if defined(CONFIG_LYNXKDI) #include <lynxkdi.h> -#if defined(CONFIG_MPC8260) +#if defined(CONFIG_MPC8260) || defined(CONFIG_440EP) || defined(CONFIG_440GR) void lynxkdi_boot ( image_header_t *hdr ) { void (*lynxkdi)(void) = (void(*)(void))hdr->ih_ep; diff --git a/common/miiphybb.c b/common/miiphybb.c index b4cbb70305..b6af88f7d6 100644 --- a/common/miiphybb.c +++ b/common/miiphybb.c @@ -38,72 +38,79 @@ * Utility to send the preamble, address, and register (common to read * and write). */ -static void miiphy_pre(char read, - unsigned char addr, - unsigned char reg) +static void miiphy_pre (char read, unsigned char addr, unsigned char reg) { - int j; /* counter */ - volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); - - /* - * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. - * The IEEE spec says this is a PHY optional requirement. The AMD - * 79C874 requires one after power up and one after a MII communications - * error. This means that we are doing more preambles than we need, - * but it is safer and will be much more robust. - */ - - MDIO_ACTIVE; - MDIO(1); - for(j = 0; j < 32; j++) - { - MDC(0); - MIIDELAY; - MDC(1); - MIIDELAY; - } - - /* send the start bit (01) and the read opcode (10) or write (10) */ - MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY; - MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY; - MDC(0); MDIO(read); MIIDELAY; MDC(1); MIIDELAY; - MDC(0); MDIO(!read); MIIDELAY; MDC(1); MIIDELAY; - - /* send the PHY address */ - for(j = 0; j < 5; j++) - { - MDC(0); - if((addr & 0x10) == 0) - { - MDIO(0); - } - else - { - MDIO(1); - } - MIIDELAY; - MDC(1); - MIIDELAY; - addr <<= 1; - } - - /* send the register address */ - for(j = 0; j < 5; j++) - { - MDC(0); - if((reg & 0x10) == 0) - { - MDIO(0); - } - else - { - MDIO(1); - } - MIIDELAY; - MDC(1); - MIIDELAY; - reg <<= 1; - } + int j; /* counter */ +#ifndef CONFIG_EP8248 + volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT); +#endif + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. + * The IEEE spec says this is a PHY optional requirement. The AMD + * 79C874 requires one after power up and one after a MII communications + * error. This means that we are doing more preambles than we need, + * but it is safer and will be much more robust. + */ + + MDIO_ACTIVE; + MDIO (1); + for (j = 0; j < 32; j++) { + MDC (0); + MIIDELAY; + MDC (1); + MIIDELAY; + } + + /* send the start bit (01) and the read opcode (10) or write (10) */ + MDC (0); + MDIO (0); + MIIDELAY; + MDC (1); + MIIDELAY; + MDC (0); + MDIO (1); + MIIDELAY; + MDC (1); + MIIDELAY; + MDC (0); + MDIO (read); + MIIDELAY; + MDC (1); + MIIDELAY; + MDC (0); + MDIO (!read); + MIIDELAY; + MDC (1); + MIIDELAY; + + /* send the PHY address */ + for (j = 0; j < 5; j++) { + MDC (0); + if ((addr & 0x10) == 0) { + MDIO (0); + } else { + MDIO (1); + } + MIIDELAY; + MDC (1); + MIIDELAY; + addr <<= 1; + } + + /* send the register address */ + for (j = 0; j < 5; j++) { + MDC (0); + if ((reg & 0x10) == 0) { + MDIO (0); + } else { + MDIO (1); + } + MIIDELAY; + MDC (1); + MIIDELAY; + reg <<= 1; + } } @@ -114,66 +121,63 @@ static void miiphy_pre(char read, * Returns: * 0 on success */ -int miiphy_read(unsigned char addr, - unsigned char reg, - unsigned short *value) +int miiphy_read (unsigned char addr, unsigned char reg, unsigned short *value) { - short rdreg; /* register working value */ - int j; /* counter */ - volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); - - miiphy_pre(1, addr, reg); - - /* tri-state our MDIO I/O pin so we can read */ - MDC(0); - MDIO_TRISTATE; - MIIDELAY; - MDC(1); - MIIDELAY; - - /* check the turnaround bit: the PHY should be driving it to zero */ - if(MDIO_READ != 0) - { - /* puts ("PHY didn't drive TA low\n"); */ - for(j = 0; j < 32; j++) - { - MDC(0); - MIIDELAY; - MDC(1); - MIIDELAY; - } - return(-1); - } - - MDC(0); - MIIDELAY; - - /* read 16 bits of register data, MSB first */ - rdreg = 0; - for(j = 0; j < 16; j++) - { - MDC(1); - MIIDELAY; - rdreg <<= 1; - rdreg |= MDIO_READ; - MDC(0); - MIIDELAY; - } - - MDC(1); - MIIDELAY; - MDC(0); - MIIDELAY; - MDC(1); - MIIDELAY; - - *value = rdreg; + short rdreg; /* register working value */ + int j; /* counter */ +#ifndef CONFIG_EP8248 + volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT); +#endif + + miiphy_pre (1, addr, reg); + + /* tri-state our MDIO I/O pin so we can read */ + MDC (0); + MDIO_TRISTATE; + MIIDELAY; + MDC (1); + MIIDELAY; + + /* check the turnaround bit: the PHY should be driving it to zero */ + if (MDIO_READ != 0) { + /* puts ("PHY didn't drive TA low\n"); */ + for (j = 0; j < 32; j++) { + MDC (0); + MIIDELAY; + MDC (1); + MIIDELAY; + } + return (-1); + } + + MDC (0); + MIIDELAY; + + /* read 16 bits of register data, MSB first */ + rdreg = 0; + for (j = 0; j < 16; j++) { + MDC (1); + MIIDELAY; + rdreg <<= 1; + rdreg |= MDIO_READ; + MDC (0); + MIIDELAY; + } + + MDC (1); + MIIDELAY; + MDC (0); + MIIDELAY; + MDC (1); + MIIDELAY; + + *value = rdreg; #ifdef DEBUG - printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value); + printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value); #endif - return 0; + return 0; } @@ -184,47 +188,51 @@ int miiphy_read(unsigned char addr, * Returns: * 0 on success */ -int miiphy_write(unsigned char addr, - unsigned char reg, - unsigned short value) +int miiphy_write (unsigned char addr, unsigned char reg, unsigned short value) { - int j; /* counter */ - volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT); - - miiphy_pre(0, addr, reg); - - /* send the turnaround (10) */ - MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY; - MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY; - - /* write 16 bits of register data, MSB first */ - for(j = 0; j < 16; j++) - { - MDC(0); - if((value & 0x00008000) == 0) - { - MDIO(0); - } - else - { - MDIO(1); - } - MIIDELAY; - MDC(1); - MIIDELAY; - value <<= 1; - } - - /* - * Tri-state the MDIO line. - */ - MDIO_TRISTATE; - MDC(0); - MIIDELAY; - MDC(1); - MIIDELAY; - - return 0; + int j; /* counter */ +#ifndef CONFIG_EP8248 + volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT); +#endif + + miiphy_pre (0, addr, reg); + + /* send the turnaround (10) */ + MDC (0); + MDIO (1); + MIIDELAY; + MDC (1); + MIIDELAY; + MDC (0); + MDIO (0); + MIIDELAY; + MDC (1); + MIIDELAY; + + /* write 16 bits of register data, MSB first */ + for (j = 0; j < 16; j++) { + MDC (0); + if ((value & 0x00008000) == 0) { + MDIO (0); + } else { + MDIO (1); + } + MIIDELAY; + MDC (1); + MIIDELAY; + value <<= 1; + } + + /* + * Tri-state the MDIO line. + */ + MDIO_TRISTATE; + MDC (0); + MIIDELAY; + MDC (1); + MIIDELAY; + + return 0; } #endif /* CONFIG_BITBANGMII */ diff --git a/common/miiphyutil.c b/common/miiphyutil.c index 2b0dcf4f2c..13b9c65dc8 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -93,7 +93,13 @@ int miiphy_reset (unsigned char addr) unsigned short reg; int loop_cnt; - if (miiphy_write (addr, PHY_BMCR, 0x8000) != 0) { + if (miiphy_read (addr, PHY_BMCR, ®) != 0) { +#ifdef DEBUG + printf ("PHY status read failed\n"); +#endif + return (-1); + } + if (miiphy_write (addr, PHY_BMCR, reg | 0x8000) != 0) { #ifdef DEBUG puts ("PHY reset failed\n"); #endif diff --git a/common/usb.c b/common/usb.c index 4136f8d776..d9515e659c 100644 --- a/common/usb.c +++ b/common/usb.c @@ -1,9 +1,19 @@ /* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland * * Most of this source has been derived from the Linux USB - * project. + * 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. @@ -37,6 +47,7 @@ #include <common.h> #include <command.h> #include <asm/processor.h> +#include <linux/ctype.h> #if (CONFIG_COMMANDS & CFG_CMD_USB) @@ -45,8 +56,7 @@ #include <405gp_pci.h> #endif - -/* #define USB_DEBUG */ +#undef USB_DEBUG #ifdef USB_DEBUG #define USB_PRINTF(fmt,args...) printf (fmt ,##args) @@ -70,6 +80,7 @@ void usb_scan_devices(void); int usb_hub_probe(struct usb_device *dev, int ifnum); void usb_hub_reset(void); + /*********************************************************************** * wait_ms */ @@ -157,6 +168,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, { 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; @@ -330,8 +342,7 @@ int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) int usb_clear_halt(struct usb_device *dev, int pipe) { int result; - unsigned short status; - int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); + 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); @@ -339,15 +350,14 @@ int usb_clear_halt(struct usb_device *dev, int pipe) /* don't clear if failed */ if (result < 0) return result; - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp, - &status, sizeof(status), USB_CNTL_TIMEOUT * 3); - if (result < 0) - return result; - USB_PRINTF("usb_clear_halt: status 0x%x\n",status); - if (status & 1) - return -1; /* still halted */ + + /* + * 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; @@ -423,7 +433,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_interface_descriptor *if_face = NULL; int ret, i; - for (i=0; i<dev->config.bNumInterfaces; i++) { + for (i = 0; i < dev->config.bNumInterfaces; i++) { if (dev->config.if_desc[i].bInterfaceNumber == interface) { if_face = &dev->config.if_desc[i]; break; @@ -439,8 +449,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0) return ret; - if_face->act_altsetting = (unsigned char)alternate; - usb_set_maxpacket(dev); return 0; } @@ -511,11 +519,74 @@ int usb_get_class_descriptor(struct usb_device *dev, int ifnum, */ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) { - return 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); + 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. @@ -535,7 +606,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) /* get langid for strings if it's not yet known */ if (!dev->have_langid) { - err = usb_get_string(dev, 0, 0, tbuf, 4); + err = usb_string_sub(dev, 0, 0, tbuf); if (err < 0) { USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status); return -1; @@ -550,22 +621,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) dev->devnum, dev->string_langid); } } - /* Just ask for a maximum length string and then take the length - * that was returned. */ - err = usb_get_string(dev, dev->string_langid, index, tbuf, 4); - if (err < 0) - return err; - u=tbuf[0]; - USB_PRINTF("Strn Len %d, index %d\n",u,index); - - if (u > USB_BUFSIZ) { - USB_PRINTF("usb_string: failed to get string - too long: %d\n", u); - return -1; - } - err = usb_get_string(dev, dev->string_langid, index, tbuf, u); + 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) @@ -641,11 +701,66 @@ int usb_new_device(struct usb_device *dev) /* We still haven't set the Address yet */ addr = dev->devnum; dev->devnum = 0; + +#undef NEW_INIT_SEQ +#ifdef NEW_INIT_SEQ + /* this is a Windows scheme of initialization sequence, with double + * reset of the device. 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 + */ + int j; + 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. */ + + desc = (struct usb_device_descriptor *)tmpbuf; + desc->bMaxPacketSize0 = 0; + for (j = 0; j < 3; ++j) { + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); + if (err < 0) { + USB_PRINTF("usb_new_device: 64 byte descr\n"); + break; + } + } + dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; + + /* find the port number we're at */ + if (parent) { + + 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; + } + } +#else + /* and this is the old and known way of initializing devices */ 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; } +#endif + dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { @@ -723,7 +838,7 @@ void usb_scan_devices(void) /* device 0 is always present (root hub, so let it analyze) */ dev=usb_alloc_new_device(); usb_new_device(dev); - printf("%d USB Devices found\n",dev_index); + printf("%d USB Device(s) found\n",dev_index); /* insert "driver" if possible */ #ifdef CONFIG_USB_KEYBOARD drv_usb_kbd_init(); @@ -821,39 +936,15 @@ struct usb_hub_device *usb_hub_allocate(void) #define MAX_TRIES 5 -void usb_hub_port_connect_change(struct usb_device *dev, int port) +static int hub_port_reset(struct usb_device *dev, int port, + unsigned short *portstat) { - struct usb_device *usb; + int tries; struct usb_port_status portsts; unsigned short portstatus, portchange; - int tries; - /* Check status */ - if (usb_get_port_status(dev, port + 1, &portsts)<0) { - USB_HUB_PRINTF("get_port_status failed\n"); - return; - } - - portstatus = swap_16(portsts.wPortStatus); - portchange = swap_16(portsts.wPortChange); - USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange, - portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed"); - - /* 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 */ + 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); @@ -861,7 +952,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) if (usb_get_port_status(dev, port + 1, &portsts)<0) { USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status); - return; + return -1; } portstatus = swap_16(portsts.wPortStatus); portchange = swap_16(portsts.wPortChange); @@ -873,10 +964,12 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); if ((portchange & USB_PORT_STAT_C_CONNECTION) || !(portstatus & USB_PORT_STAT_CONNECTION)) - return; + return -1; + + if (portstatus & USB_PORT_STAT_ENABLE) { - if (portstatus & USB_PORT_STAT_ENABLE) break; + } wait_ms(200); } @@ -884,10 +977,52 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) 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; + 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 = swap_16(portsts.wPortStatus); + portchange = swap_16(portsts.wPortChange); + USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange, + portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed"); + + /* 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 */ diff --git a/common/usb_storage.c b/common/usb_storage.c index 605a1ceb9b..69d195af60 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -1,12 +1,19 @@ /* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland + * 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 <gj@denx.de> * - * Most of this source has been derived from the Linux USB - * project. BBB support based on /sys/dev/usb/umass.c from + * BBB support based on /sys/dev/usb/umass.c from * FreeBSD. * * See file CREDITS for list of people who contributed to this @@ -121,7 +128,7 @@ typedef struct { #define UMASS_BBB_CSW_SIZE 13 #define USB_MAX_STOR_DEV 5 -static int usb_max_devs; /* number of highest available usb device */ +static int usb_max_devs = 0; /* number of highest available usb device */ static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV]; @@ -177,7 +184,24 @@ void usb_show_progress(void) } /********************************************************************************* - * (re)-scan the usb and reports device info + * show info on storage devices; 'usb start/init' must be invoked earlier + * as we only retrieve structures populated during devices initialization + */ +void 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]); + } + else + printf("No storage devices, perhaps not 'usb start'ed..?\n"); +} + +/********************************************************************************* + * scan the usb and reports device info * to the user if mode = 1 * returns current device or -1 if no */ @@ -190,7 +214,7 @@ int usb_stor_scan(int mode) memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); if(mode==1) { - printf(" scanning bus for storage devices...\n"); + printf(" scanning bus for storage devices... "); } usb_disable_asynch(1); /* asynch transfer not allowed */ @@ -202,6 +226,7 @@ int usb_stor_scan(int mode) usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN; usb_dev_desc[i].block_read=usb_stor_read; } + usb_max_devs=0; for(i=0;i<USB_MAX_DEVICE;i++) { dev=usb_get_dev_index(i); /* get device */ @@ -211,21 +236,17 @@ int usb_stor_scan(int mode) } if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */ /* get info and fill it in */ - - if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) { - if(mode==1) { - printf (" Device %d: ", usb_max_devs); - dev_print(&usb_dev_desc[usb_max_devs]); - } /* if mode */ + if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) usb_max_devs++; - } /* if get info ok */ } /* 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; else @@ -367,11 +388,13 @@ static int usb_stor_BBB_reset(struct us_data *us) 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); @@ -640,7 +663,9 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) 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); + 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"); @@ -797,7 +822,7 @@ do_retry: static int usb_inquiry(ccb *srb,struct us_data *ss) { int retry,i; - retry=3; + retry=5; do { memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_INQUIRY; @@ -838,7 +863,7 @@ static int usb_request_sense(ccb *srb,struct us_data *ss) static int usb_test_unit_ready(ccb *srb,struct us_data *ss) { - int retries=10; + int retries = 10; do { memset(&srb->cmd[0],0,12); @@ -859,7 +884,7 @@ static int usb_test_unit_ready(ccb *srb,struct us_data *ss) static int usb_read_capacity(ccb *srb,struct us_data *ss) { int retry; - retry=2; /* retries */ + retry = 3; /* retries */ do { memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_RD_CAPAC; @@ -972,9 +997,6 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data int protocol = 0; int subclass = 0; - - memset(ss, 0, sizeof(struct us_data)); - /* let's examine the device now */ iface = &dev->config.if_desc[ifnum]; @@ -996,6 +1018,8 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data 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"); @@ -1103,50 +1127,62 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t unsigned char perq,modi; unsigned long cap[2]; unsigned long *capacity,*blksz; - ccb *pccb=&usb_ccb; - - /* For some mysterious reason the 256MB flash disk of Ours Technology, Inc - * doesn't survive this reset */ - if (dev->descriptor.idVendor != 0xea0 || dev->descriptor.idProduct != 0x6828) + 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) + ) + 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; + 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) { + + perq = usb_stor_buf[0]; + modi = usb_stor_buf[1]; + if((perq & 0x1f) == 0x1f) { return 0; /* skip unknown devices */ } - if((modi&0x80)==0x80) {/* drive is removable */ - dev_desc->removable=1; + 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; + dev_desc->vendor[8] = 0; + dev_desc->product[16] = 0; + dev_desc->revision[4] = 0; 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; + if(dev_desc->removable == 1) { + dev_desc->type = perq; return 1; } else return 0; } - pccb->pdata=(unsigned char *)&cap[0]; + pccb->pdata = (unsigned char *)&cap[0]; memset(pccb->pdata,0,8); - if(usb_read_capacity(pccb,ss)!=0) { + if(usb_read_capacity(pccb,ss) != 0) { printf("READ_CAP ERROR\n"); - cap[0]=2880; - cap[1]=0x200; + cap[0] = 2880; + cap[1] = 0x200; } USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]); #if 0 @@ -1166,13 +1202,13 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); #endif /* this assumes bigendian! */ - cap[0]+=1; - capacity=&cap[0]; - blksz=&cap[1]; + 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; + 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); |