diff -uNr u-boot-3.4.16.orig/board/mv_feroceon/config_kw/Makefile u-boot-3.4.16/board/mv_feroceon/config_kw/Makefile --- u-boot-3.4.16.orig/board/mv_feroceon/config_kw/Makefile 2008-10-08 04:58:04.000000000 +0900 +++ u-boot-3.4.16/board/mv_feroceon/config_kw/Makefile 2009-04-28 13:34:26.000000000 +0900 @@ -39,7 +39,8 @@ $(USP_DIR)/mv_pci.o $(USP_DIR)/mv_nand.o \ $(USP_DIR)/mv_ide.o $(USP_DIR)/mv_egiga.o \ $(USP_DIR)/mv_fs.o $(USP_DIR)/mv_loadnet.o $(USP_DIR)/mv_protectionUnit.o \ - $(USP_DIR)/mv_i2c.o $(USP_DIR)/mv_ext2_boot.o $(USP_ETH_SWITCH_DIR)/mvSwitch.o + $(USP_DIR)/mv_i2c.o $(USP_DIR)/mv_ext2_boot.o $(USP_ETH_SWITCH_DIR)/mvSwitch.o \ + $(USP_DIR)/sdio/mmc.o ifeq ($(NAND_BOOT), y) USP_OBJS += $(USP_DIR)/nBootloader.o diff -uNr u-boot-3.4.16.orig/board/mv_feroceon/USP/sdio/mmc.c u-boot-3.4.16/board/mv_feroceon/USP/sdio/mmc.c --- u-boot-3.4.16.orig/board/mv_feroceon/USP/sdio/mmc.c 2008-09-04 08:31:50.000000000 +0900 +++ u-boot-3.4.16/board/mv_feroceon/USP/sdio/mmc.c 2009-04-29 15:10:05.000000000 +0900 @@ -20,18 +20,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ +//#define DEBUG #include #include -#include "mustang_sdiodef.h" +#include "mvsdmmc.h" #include #include #include #include "mvOs.h" #ifdef CONFIG_MMC -#define DELAY 50 -//#define debug printf + +static int is_sdhc; + extern int fat_register_device(block_dev_desc_t *dev_desc, int part_no); @@ -49,39 +51,140 @@ static uchar mmc_buf[MMC_BLOCK_SIZE]; static mmc_csd_t mmc_csd; static int mmc_ready = 0; -static int rca ; +/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code + that expects it to be shifted. */ +static u_int16_t rca = 0; + +static u_int32_t mmc_size(const struct mmc_csd *csd) +{ + u_int32_t block_len, mult, blocknr; + + block_len = csd->read_bl_len << 12; + mult = csd->c_size_mult1 << 8; + blocknr = (csd->c_size+1) * mult; + + return blocknr * block_len; +} + +static int isprint (unsigned char ch) +{ + if (ch >= 32 && ch < 127) + return (1); + + return (0); +} + +static int toprint(char *dst, char c) +{ + if (isprint(c)) { + *dst = c; + return 1; + } + + return sprintf(dst,"\\x%02x", c); + +} + +static void print_mmc_cid(mmc_cid_t *cid) +{ + printf("MMC found. Card desciption is:\n"); + printf("Manufacturer ID = %02x%02x%02x\n", + cid->id[0], cid->id[1], cid->id[2]); + printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev); + cid->hwrev = cid->fwrev = 0; /* null terminate string */ + printf("Product Name = %s\n",cid->name); + printf("Serial Number = %02x%02x%02x\n", + cid->sn[0], cid->sn[1], cid->sn[2]); + printf("Month = %d\n",cid->month); + printf("Year = %d\n",1997 + cid->year); +} + +static void print_sd_cid(sd_cid_t *cid) +{ + int len; + char tbuf[64]; + + printf("SD%s found. Card desciption is:\n", is_sdhc?"HC":""); + + len = 0; + len += toprint(&tbuf[len], cid->oid_0); + len += toprint(&tbuf[len], cid->oid_1); + tbuf[len] = 0; + + printf("Manufacturer: 0x%02x, OEM \"%s\"\n", + cid->mid, tbuf); + + len = 0; + len += toprint(&tbuf[len], cid->pnm_0); + len += toprint(&tbuf[len], cid->pnm_1); + len += toprint(&tbuf[len], cid->pnm_2); + len += toprint(&tbuf[len], cid->pnm_3); + len += toprint(&tbuf[len], cid->pnm_4); + tbuf[len] = 0; + + printf("Product name: \"%s\", revision %d.%d\n", + tbuf, + cid->prv >> 4, cid->prv & 15); + + printf("Serial number: %u\n", + cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 | + cid->psn_3); + printf("Manufacturing date: %d/%d\n", + cid->mdt_1 & 15, + 2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4)); + + printf("CRC: 0x%02x, b0 = %d\n", + cid->crc >> 1, cid->crc & 1); +} + +static void mvsdmmc_set_clock(unsigned int clock) +{ + unsigned int m; + + m = MVSDMMC_BASE_FAST_CLOCK/(2*clock) - 1; + debug("mvsdmmc_set_clock: dividor = 0x%x clock=%d\n", + m, clock); + + SDIO_REG_WRITE32(SDIO_CLK_DIV, m & 0x7ff); + + if (isprint(1)) + udelay(10*1000); +} -static uchar * + +static ulong * /****************************************************/ mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype) /****************************************************/ { static ulong resp[4]; - int count ; ushort done ; int err = 0 ; + ulong curr, start, diff, hz; + ushort response[8], resp_indx = 0; debug("mmc_cmd %x, arg: %x,xfer: %x,resp: %x, wait : %x\n", cmd, arg, xfermode, resptype, waittype); + //clear status - SDIO_REG_WRITE16(SDIO_ERR_INTR_EN, SDIO_REG_READ16(SDIO_ERR_INTR_STATUS)); - SDIO_REG_WRITE16(SDIO_NOR_INTR_EN, SDIO_REG_READ16(SDIO_NOR_INTR_STATUS)); - //disable interrupts - SDIO_REG_WRITE16(SDIO_NOR_INTR_EN, 0); - SDIO_REG_WRITE16(SDIO_ERR_INTR_EN, 0); - - udelay(2000); -/* count = 10000 ; + SDIO_REG_WRITE16(SDIO_NOR_INTR_STATUS, 0xffff); + SDIO_REG_WRITE16(SDIO_ERR_INTR_STATUS, 0xffff); + + start = get_ticks(); + hz = get_tbclk(); + while((SDIO_REG_READ16(SDIO_PRESENT_STATE0) & CARD_BUSY)) { - udelay(DELAY); - if (--count <= 0 ) { - // card busy, can't sent cmd + curr = get_ticks(); + diff = (long) curr - (long) start; + if (diff > (3*hz)) + { + // 3 seconds timeout, card busy, can't sent cmd printf("card too busy \n"); return 0; } } -*/ + SDIO_REG_WRITE16(SDIO_ARG_LOW, (ushort)(arg&0xffff) ); SDIO_REG_WRITE16(SDIO_ARG_HI, (ushort)(arg>>16) ); SDIO_REG_WRITE16(SDIO_XFER_MODE, xfermode); @@ -96,53 +199,55 @@ } done = SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & waittype; - count = 10000 ; + start = get_ticks(); while( done!=waittype) { -// udelay(DELAY); - udelay(2000); done = SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & waittype; -/* if( SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & 0x8000 ) + + if( SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & 0x8000 ) { - printf("Error! cmd : %d, err : %x\n", cmd, SDIO_REG_READ16(SDIO_ERR_INTR_STATUS) ) ; + printf("Error! cmd : %d, err : %04x\n", cmd, SDIO_REG_READ16(SDIO_ERR_INTR_STATUS) ) ; return 0 ; // error happen } - if( --count <= 0 ) + + curr = get_ticks(); + diff = (long) curr - (long) start; + if (diff > (3*hz)) { - debug("cmd timeout, status : %x\n", SDIO_REG_READ16(SDIO_NOR_INTR_STATUS)); - debug("xfer mode : %x\n", SDIO_REG_READ16(SDIO_XFER_MODE)); + printf("cmd timeout, status : %04x\n", SDIO_REG_READ16(SDIO_NOR_INTR_STATUS)); + printf("xfer mode : %04x\n", SDIO_REG_READ16(SDIO_XFER_MODE)); err = 1 ; break; - //return 0 ; } -*/ } - // write clear the status - SDIO_REG_WRITE16(SDIO_NOR_INTR_STATUS, waittype); - //SDIO_REG_WRITE16(SDIO_NOR_INTR_EN, SDIO_REG_READ16(SDIO_NOR_INTR_STATUS)); + for (resp_indx = 0 ; resp_indx < 8; resp_indx++) + response[resp_indx] = SDIO_REG_READ16(SDIO_RSP(resp_indx)); + + memset(resp, 0, sizeof(resp)); switch (resptype & 0x3) { case SDIO_CMD_RSP_48: case SDIO_CMD_RSP_48BUSY: - resp[0] = ( SDIO_REG_READ16(SDIO_RSP0) << (16+6)) | - (SDIO_REG_READ16(SDIO_RSP1) << 6) | - ((SDIO_REG_READ16(SDIO_RSP2))& 0x3f) ; + resp[0] = ((response[2] & 0x3f) << (8 - 8)) | + ((response[1] & 0xffff) << (14 - 8)) | + ((response[0] & 0x3ff) << (30 - 8)); + resp[1] = ((response[0] & 0xfc00) >> 10); break; case SDIO_CMD_RSP_136: - resp[0] = ( SDIO_REG_READ16(SDIO_RSP5) << (16+14)) | - (SDIO_REG_READ16(SDIO_RSP6) << 14) | - ((SDIO_REG_READ16(SDIO_RSP7))& 0x3fff) ; - resp[1] = ( SDIO_REG_READ16(SDIO_RSP3) << (16+14)) | - (SDIO_REG_READ16(SDIO_RSP4) << 14) | - ((SDIO_REG_READ16(SDIO_RSP5)>> 2 )& 0x3fff) ; - resp[2] = ( SDIO_REG_READ16(SDIO_RSP1) << (16+14)) | - (SDIO_REG_READ16(SDIO_RSP2) << 14) | - ((SDIO_REG_READ16(SDIO_RSP3)>> 2 )& 0x3fff) ; - resp[3] = (SDIO_REG_READ16(SDIO_RSP0) << 14) | - ((SDIO_REG_READ16(SDIO_RSP1)>> 2 )& 0x3fff) ; + resp[3] = ((response[7] & 0x3fff) << 8) | + ((response[6] & 0x3ff) << 22); + resp[2] = ((response[6] & 0xfc00) >> 10) | + ((response[5] & 0xffff) << 6) | + ((response[4] & 0x3ff) << 22); + resp[1] = ((response[4] & 0xfc00) >> 10) | + ((response[3] & 0xffff) << 6) | + ((response[2] & 0x3ff) << 22); + resp[0] = ((response[2] & 0xfc00) >> 10) | + ((response[1] & 0xffff) << 6) | + ((response[0] & 0x3ff) << 22); break; default: return 0; @@ -156,9 +261,9 @@ printf("\n"); #endif if( err ) - return 0 ; + return NULL ; else - return (uchar*)resp; + return resp; } int @@ -166,7 +271,7 @@ mmc_block_read(uchar *dst, ulong src, ulong len) /****************************************************/ { - uchar *resp; + ulong *resp; //ushort argh, argl; //ulong status; @@ -174,24 +279,35 @@ return 0; } + if (is_sdhc) { + /* SDHC: use block address */ + src >>= 9; + } + debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len); - //mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype); +#if 0 /* set block len */ resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + if (!resp) { + printf("mmc_block_read: set blk len fails\n"); + return -EIO; + } +#endif // prepare for dma transfer - //SDIO_REG_WRITE16(SDIO_SYS_ADDR_LOW,((ulong)(dst)>>16)&0xffff); SDIO_REG_WRITE16(SDIO_SYS_ADDR_LOW,((ulong)(dst))&0xffff); - //SDIO_REG_WRITE16(SDIO_SYS_ADDR_HI,((ulong)(dst))&0xffff); - SDIO_REG_WRITE16(SDIO_SYS_ADDR_HI,(0x8000 | ((ulong)(dst)>>16)&0xffff)); + SDIO_REG_WRITE16(SDIO_SYS_ADDR_HI,(((ulong)dst)>>16)&0xffff); SDIO_REG_WRITE16(SDIO_BLK_SIZE,len); SDIO_REG_WRITE16(SDIO_BLK_COUNT,1); - /* send read command */ resp = mmc_cmd(MMC_CMD_READ_BLOCK, src, 0x10 , // 0x12, - SDIO_CMD_RSP_48, SDIO_NOR_DMA_INI); + SDIO_CMD_RSP_48, SDIO_NOR_XFER_DONE); + if (!resp) { + printf("mmc_block_read: mmc read block cmd fails\n"); + return -EIO; + } return 0; } @@ -303,17 +419,15 @@ } debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end); - for (; src < aligned_end; aligned_start +=mmc_block_size/4, src += mmc_block_size/4, dst += mmc_block_size/4) { + for (; src < aligned_end; aligned_start +=mmc_block_size, src += mmc_block_size, dst += mmc_block_size) { debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end); - //if ((mmc_block_read((uchar *)(dst), src, mmc_block_size)) < 0) { - if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size/4)) < 0) { -// if ((mmc_block_read((uchar*)0x2000000, aligned_start, mmc_block_size)) < 0) { + if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) { printf("mmc block read error\n"); return -1; } //printf("mem copy from %x to %x, size %d\n", (ulong)mmc_buf, (ulong)dst, mmc_block_size ); - memcpy(dst, mmc_buf, mmc_block_size/4); + memcpy(dst, mmc_buf, mmc_block_size); } debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end); @@ -415,15 +529,22 @@ /****************************************************/ { int retries, rc = -ENODEV; - uchar *resp; - uchar scrs[16] ; + ulong *resp; + int sd_ver20; + int is_sd; + ushort reg; + uchar cidbuf[64]; + + sd_ver20 = 0; + is_sdhc = 0; + is_sd = 0; // Initial Host Ctrl : Timeout : max , Normal Speed mode, 4-bit data mode // Big Endian, SD memory Card, Push_pull CMD Line SDIO_REG_WRITE16(SDIO_HOST_CTRL, - ( 0xf << SDIO_HOST_CTRL_TMOUT_SHIFT ) | + SDIO_HOST_CTRL_TMOUT(0xf) | SDIO_HOST_CTRL_DATA_WIDTH_4_BITS | - SDIO_HOST_CTRL_BIG_ENDAN | + SDIO_HOST_CTRL_BIG_ENDIAN | SDIO_HOST_CTRL_PUSH_PULL_EN | SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY ); @@ -431,11 +552,11 @@ //enable status SDIO_REG_WRITE16(SDIO_NOR_STATUS_EN, 0xffff); - SDIO_REG_WRITE16(SDIO_ERR_STATUS_EN, SDIO_ERR_INTR_MASK); + SDIO_REG_WRITE16(SDIO_ERR_STATUS_EN, 0xffff); //disable interrupts SDIO_REG_WRITE16(SDIO_NOR_INTR_EN, 0); - SDIO_REG_WRITE16(SDIO_ERR_INTR_EN, SDIO_ERR_INTR_MASK); + SDIO_REG_WRITE16(SDIO_ERR_INTR_EN, 0); SDIO_REG_WRITE16(SDIO_SW_RESET,0x100); udelay(10000); @@ -446,110 +567,192 @@ retries = 10; //mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype); resp = mmc_cmd(0, 0, 0, SDIO_CMD_RSP_NONE , SDIO_NOR_CMD_DONE ); - debug("cmd 0 resp : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); - resp = mmc_cmd(55, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); - debug("cmd 55 resp : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); - resp = mmc_cmd(41, 0xff8000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + debug("cmd 0 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); - debug("cmd 41 resp : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); - while (retries-- && resp && !(resp[3] & 0x80)) { - resp = mmc_cmd(55, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); - resp = mmc_cmd(41, 0xff8000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); - debug("cmd 41 resp : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); + debug ("trying to detect SD card version\n"); + resp = mmc_cmd(8, 0x000001aa, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + debug("cmd 8 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + if (resp && (resp[0] & 0x1ff)==0x1aa) { + debug("sd version 2.0 card detected\n"); + sd_ver20 = 1; } - if( resp[3] & 0x80 ) - printf("sd memory ready\n"); + if (sd_ver20) + retries = 50; else - { - printf("Sd memory error\n"); - return rc; + retries = 10; + + while (retries--) { + resp = mmc_cmd(55, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + debug("cmd 55 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + + if (sd_ver20) + resp = mmc_cmd(41, 0x40300000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + else + resp = mmc_cmd(41, 0x00300000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + + debug("cmd 41 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + + if (resp && (resp[0] & 0x80000000)) { + debug ("detected SD card\n"); + is_sd = 1; + break; + } + + udelay(100*1000); + } + + if (retries <= 0 && !is_sd) { + debug ("failed to detect SD card, trying MMC\n"); + retries = 10; + while (retries--) { + resp = mmc_cmd(1, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + debug("cmd 01 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + + if (resp && (resp[0] & 0x80000000)) { + debug ("detected MMC card\n"); + reg = SDIO_REG_READ16(SDIO_HOST_CTRL); + reg &= ~(0x3<<1); + reg |= SDIO_HOST_CTRL_CARD_TYPE_IO_MMC; + SDIO_REG_WRITE16(SDIO_HOST_CTRL, reg); + break; + } + + udelay(100*1000); + } + } + + if (retries <= 0) { + debug ("detect fails\n"); + return -ENODEV; } /* try to get card id */ resp = mmc_cmd(2, 0, 0, SDIO_CMD_RSP_136, SDIO_NOR_CMD_DONE ); - debug("cmd 2 resp 0 : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); - debug("cmd 2 resp 1 : %x %x %x %x\n", resp[4], resp[5], resp[6], resp[7] ); - debug("cmd 2 resp 2 : %x %x %x %x\n", resp[8], resp[9], resp[10], resp[11] ); - debug("cmd 2 resp 3 : %x %x %x %x\n", resp[12], resp[13], resp[14], resp[15] ); - if (resp) { + debug("cmd 2 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + + if (resp == NULL) { + debug ("read cid fails\n"); + return -ENODEV; + } + + if (is_sd) { + sd_cid_t *cid = (sd_cid_t *) resp; + + memcpy(cidbuf, resp, sizeof(sd_cid_t)); + + sprintf((char *) mmc_dev.vendor, + "Man %02x OEM %c%c \"%c%c%c%c%c\"", + cid->mid, cid->oid_0, cid->oid_1, + cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4); + + sprintf((char *) mmc_dev.product, "%d", + (cid->psn_0 << 24) | (cid->psn_1 <<16) | (cid->psn_2 << 8) | (cid->psn_3 << 8)); + + sprintf((char *) mmc_dev.revision, "%d.%d", cid->prv>>4, cid->prv & 0xff); + + } else { /* TODO configure mmc driver depending on card attributes */ - mmc_cid_t *cid = (mmc_cid_t *)resp; - if (verbose) { - printf("MMC found. Card desciption is:\n"); - printf("Manufacturer ID = %02x%02x%02x\n", - cid->id[0], cid->id[1], cid->id[2]); - printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev); - cid->hwrev = cid->fwrev = 0; /* null terminate string */ - printf("Product Name = %s\n",cid->name); - printf("Serial Number = %02x%02x%02x\n", - cid->sn[0], cid->sn[1], cid->sn[2]); - printf("Month = %d\n",cid->month); - printf("Year = %d\n",1997 + cid->year); - } - /* fill in device description */ - mmc_dev.if_type = IF_TYPE_MMC; - mmc_dev.part_type = PART_TYPE_DOS; - mmc_dev.dev = 0; - mmc_dev.lun = 0; - mmc_dev.type = 0; - /* FIXME fill in the correct size (is set to 128MByte) */ - mmc_dev.blksz = 512; - mmc_dev.lba = 0x40000; - printf(mmc_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x", - cid->id[0], cid->id[1], cid->id[2], - cid->sn[0], cid->sn[1], cid->sn[2]); - printf(mmc_dev.product,"%s",cid->name); - printf(mmc_dev.revision,"%x %x",cid->hwrev, cid->fwrev); - mmc_dev.removable = 0; - mmc_dev.block_read = mmc_bread; + mmc_cid_t *cid = (mmc_cid_t *) resp; - //mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype); - /* MMC exists, get CSD too */ - resp = mmc_cmd(MMC_CMD_SET_RCA, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); - rca = resp[2] | (resp[3] << 8 ) ; - resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, 0, SDIO_CMD_RSP_136,SDIO_NOR_CMD_DONE ); - if (resp) { - mmc_csd_t *csd = (mmc_csd_t *)resp; - memcpy(&mmc_csd, csd, sizeof(csd)); - debug("cmd 9 resp 0 : %x %x %x %x\n", resp[0], resp[1], resp[2], resp[3] ); - debug("cmd 9 resp 1 : %x %x %x %x\n", resp[4], resp[5], resp[6], resp[7] ); - debug("cmd 9 resp 2 : %x %x %x %x\n", resp[8], resp[9], resp[10], resp[11] ); - debug("cmd 9 resp 3 : %x %x %x %x\n", resp[12], resp[13], resp[14], resp[15] ); - rc = 0; - /* Calc device size */ - debug("cmd 9 csd->c_size : %x\n", csd->c_size ); - debug("cmd 9 csd->c_size_mult1 : %x\n", csd->c_size_mult1 ); - debug("cmd 9 csd->read_bl_len : %x\n", csd->read_bl_len ); - debug("cmd 9 csd->tran_speed : %x\n", csd->tran_speed ); - debug("cmd 9 csd->nsac : %x\n", csd->nsac ); - debug("cmd 9 csd->taac : %x\n", csd->taac ); - /* FIXME add verbose printout for csd */ - mmc_ready = 1; + memcpy(cidbuf, resp, sizeof(sd_cid_t)); + + + sprintf((char *) mmc_dev.vendor, + "Man %02x%02x%02x Snr %02x%02x%02x", + cid->id[0], cid->id[1], cid->id[2], + cid->sn[0], cid->sn[1], cid->sn[2]); + sprintf((char *) mmc_dev.product, "%s", cid->name); + sprintf((char *) mmc_dev.revision, "%x %x", cid->hwrev, cid->fwrev); + } + + /* fill in device description */ + mmc_dev.if_type = IF_TYPE_MMC; + mmc_dev.part_type = PART_TYPE_DOS; + mmc_dev.dev = 0; + mmc_dev.lun = 0; + mmc_dev.type = 0; + + /* FIXME fill in the correct size (is set to 128MByte) */ + mmc_dev.blksz = 512; + mmc_dev.lba = 0x10000; + + mmc_dev.removable = 0; + mmc_dev.block_read = mmc_bread; + + /* MMC exists, get CSD too */ + resp = mmc_cmd(MMC_CMD_SET_RCA, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + if (resp == NULL) { + debug ("set rca fails\n"); + return -ENODEV; + } + debug("cmd3 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]); + + if (is_sd) + rca = resp[0] >> 16; + else + rca = 0; + + resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, 0, SDIO_CMD_RSP_136,SDIO_NOR_CMD_DONE ); + debug("cmd 9 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + if (resp == NULL) { + debug ("read csd fails\n"); + return -ENODEV; + } + + memcpy(&mmc_csd, (mmc_csd_t *) resp, sizeof(mmc_csd_t)); + rc = 0; + mmc_ready = 1; + + /* FIXME add verbose printout for csd */ + debug ("size = %u\n", mmc_size(&mmc_csd)); + + resp = mmc_cmd(7, rca<<16, 0, SDIO_CMD_RSP_48BUSY, SDIO_NOR_CMD_DONE); + if (resp == NULL) { + debug ("select card fails\n"); + return -ENODEV; + } + debug("cmd 7 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] ); + + if (is_sd) { + resp = mmc_cmd(55, rca<<16, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + if (resp == NULL) { + debug ("cmd55 fails\n"); + return -ENODEV; + } + debug("cmd55 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]); + + resp = mmc_cmd(6, (rca<<16) | 0x2 , 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + if (resp == NULL) { + debug ("cmd55 fails\n"); + return -ENODEV; } + debug("cmd6 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]); } - resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, 0, SDIO_CMD_RSP_48BUSY, SDIO_NOR_CMD_DONE); -#if 0 - resp = mmc_cmd(MMC_CMD_SELECT_CARD, 0, 0, SDIO_CMD_RSP_48BUSY, SDIO_NOR_CMD_DONE); + resp = (ulong *) &mmc_csd; + debug("csd: 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]); - resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, 0, SDIO_CMD_RSP_48BUSY, SDIO_NOR_CMD_DONE); -#endif - resp = mmc_cmd(55, rca<<16, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + /* check SDHC */ + if ((resp[0]&0xf0000000)==0x40000000) + is_sdhc = 1; - resp = mmc_cmd(6, (rca<<16) | 0x2 , 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + /* set block len */ + resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, 512, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE ); + if (!resp) { + printf("mmc_block_read: set blk len fails\n"); + return -EIO; + } -#if 0 - // prepare for dma transfer - SDIO_REG_WRITE16(SDIO_BLK_SIZE,8); - SDIO_REG_WRITE16(SDIO_BLK_COUNT,1); - SDIO_REG_WRITE16(SDIO_SYS_ADDR_LOW,((ulong)(scrs))&0xffff); - SDIO_REG_WRITE16(SDIO_SYS_ADDR_HI,((ulong)(scrs)>>16)&0xffff); - //ACMD 51 - resp = mmc_cmd(51, 0, 0x12, SDIO_CMD_RSP_48, SDIO_NOR_DMA_INI ); + if (verbose) { + if (is_sd) + print_sd_cid((sd_cid_t *) cidbuf); + else + print_mmc_cid((mmc_cid_t *) cidbuf); + } + + mvsdmmc_set_clock(25000000); - printf("scrs : %x %x %x %x %x %x %x %x\n", scrs[0], scrs[1], scrs[2], scrs[3], scrs[4], scrs[5], scrs[6], scrs[7] ); -#endif fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */ return rc; diff -uNr u-boot-3.4.16.orig/board/mv_feroceon/USP/sdio/mvsdmmc.h u-boot-3.4.16/board/mv_feroceon/USP/sdio/mvsdmmc.h --- u-boot-3.4.16.orig/board/mv_feroceon/USP/sdio/mvsdmmc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-3.4.16/board/mv_feroceon/USP/sdio/mvsdmmc.h 2009-04-29 14:22:43.000000000 +0900 @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _MVSDMMC_INCLUDE +#define _MVSDMMC_INCLUDE + + +#define MV88F6281_SDHC_BASE 0xf1090000 // from 00-4c + +#define P(x) (MV88F6281_SDHC_BASE + (x)) + +// #define GPIO_REG_READ32(addr) (*(volatile unsigned int*)(INTEGRATOR_GPIO_BASE+addr)) +// #define GPIO_REG_WRITE32(addr, val) (*(volatile unsigned int*)(INTEGRATOR_GPIO_BASE+addr)=val) + +#define SDIO_REG_WRITE32(addr,val) (*(volatile unsigned long*)(P(addr)) = val) +#define SDIO_REG_WRITE16(addr,val) (*(volatile unsigned short*)(P(addr)) = val) +#define SDIO_REG_READ16(addr) (*(volatile unsigned short*)(P(addr))) +#define SDIO_REG_READ32(addr) (*(volatile unsigned long*)(P(addr))) + +#define MVSDMMC_DMA_SIZE 65536 + +#define MVSDMMC_CMD_TIMEOUT 2 /* 100 usec*/ + + +/* + * The base MMC clock rate + */ + +#define MVSDMMC_CLOCKRATE_MIN 100000 +#define MVSDMMC_CLOCKRATE_MAX 50000000 + +#define MVSDMMC_BASE_FAST_CLOCK 200000000//100000000 + + +/* + * SDIO register + */ + +#define SDIO_SYS_ADDR_LOW 0x000 +#define SDIO_SYS_ADDR_HI 0x004 +#define SDIO_BLK_SIZE 0x008 +#define SDIO_BLK_COUNT 0x00c +#define SDIO_ARG_LOW 0x010 +#define SDIO_ARG_HI 0x014 +#define SDIO_XFER_MODE 0x018 +#define SDIO_CMD 0x01c +#define SDIO_RSP(i) (0x020 + ((i)<<2)) +#define SDIO_RSP0 0x020 +#define SDIO_RSP1 0x024 +#define SDIO_RSP2 0x028 +#define SDIO_RSP3 0x02c +#define SDIO_RSP4 0x030 +#define SDIO_RSP5 0x034 +#define SDIO_RSP6 0x038 +#define SDIO_RSP7 0x03c +#define SDIO_BUF_DATA_PORT 0x040 +#define SDIO_RSVED 0x044 + +#define SDIO_PRESENT_STATE0 0x048 +#define SDIO_PRESENT_STATE1 0x04c +#define SDIO_HOST_CTRL 0x050 +#define SDIO_BLK_GAP_CTRL 0x054 +#define SDIO_CLK_CTRL 0x058 +#define SDIO_SW_RESET 0x05c +#define SDIO_NOR_INTR_STATUS 0x060 +#define SDIO_ERR_INTR_STATUS 0x064 +#define SDIO_NOR_STATUS_EN 0x068 +#define SDIO_ERR_STATUS_EN 0x06c +#define SDIO_NOR_INTR_EN 0x070 +#define SDIO_ERR_INTR_EN 0x074 +#define SDIO_AUTOCMD12_ERR_STATUS 0x078 +#define SDIO_CURR_BYTE_LEFT 0x07c +#define SDIO_CURR_BLK_LEFT 0x080 +#define SDIO_AUTOCMD12_ARG_LOW 0x084 +#define SDIO_AUTOCMD12_ARG_HI 0x088 +#define SDIO_AUTOCMD12_INDEX 0x08c +#define SDIO_AUTO_RSP(i) (0x090 + ((i)<<2)) +#define SDIO_AUTO_RSP0 0x090 +#define SDIO_AUTO_RSP1 0x094 +#define SDIO_AUTO_RSP2 0x098 +#define SDIO_CLK_DIV 0x128 + +#define WINDOW_CTRL(i) (0x108 + ((i) << 3)) +#define WINDOW_BASE(i) (0x10c + ((i) << 3)) + + +/* + * SDIO_PRESENT_STATE + */ + +#define CARD_BUSY (1 << 1) +#define CMD_INHIBIT (1 << 0) +#define CMD_TXACTIVE (1 << 8) +#define CMD_RXACTIVE (1 << 9) +#define CMD_AUTOCMD12ACTIVE (1 << 14) + +#define CMD_BUS_BUSY (CMD_AUTOCMD12ACTIVE| \ + CMD_RXACTIVE| \ + CMD_TXACTIVE| \ + CMD_INHIBIT| \ + CARD_BUSY) + +/* + * SDIO_CMD + */ + +#define SDIO_CMD_RSP_NONE (0 << 0) +#define SDIO_CMD_RSP_136 (1 << 0) +#define SDIO_CMD_RSP_48 (2 << 0) +#define SDIO_CMD_RSP_48BUSY (3 << 0) + +#define SDIO_CMD_CHECK_DATACRC16 (1 << 2) +#define SDIO_CMD_CHECK_CMDCRC (1 << 3) +#define SDIO_CMD_INDX_CHECK (1 << 4) +#define SDIO_CMD_DATA_PRESENT (1 << 5) +#define SDIO_UNEXPECTED_RESP (1 << 7) + + +/* + * SDIO_XFER_MODE + */ + +#define SDIO_XFER_MODE_STOP_CLK (1 << 5) +#define SDIO_XFER_MODE_HW_WR_DATA_EN (1 << 1) +#define SDIO_XFER_MODE_AUTO_CMD12 (1 << 2) +#define SDIO_XFER_MODE_INT_CHK_EN (1 << 3) +#define SDIO_XFER_MODE_TO_HOST (1 << 4) + + +/* + * SDIO_HOST_CTRL + */ + +#define SDIO_HOST_CTRL_PUSH_PULL_EN (1 << 0) + +#define SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY (0 << 1) +#define SDIO_HOST_CTRL_CARD_TYPE_IO_ONLY (1 << 1) +#define SDIO_HOST_CTRL_CARD_TYPE_IO_MEM_COMBO (2 << 1) +#define SDIO_HOST_CTRL_CARD_TYPE_IO_MMC (3 << 1) +#define SDIO_HOST_CTRL_CARD_TYPE_MASK (3 << 1) + +#define SDIO_HOST_CTRL_BIG_ENDIAN (1 << 3) +#define SDIO_HOST_CTRL_LSB_FIRST (1 << 4) +#define SDIO_HOST_CTRL_ID_MODE_LOW_FREQ (1 << 5) +#define SDIO_HOST_CTRL_HALF_SPEED (1 << 6) +#define SDIO_HOST_CTRL_DATA_WIDTH_4_BITS (1 << 9) +#define SDIO_HOST_CTRL_HI_SPEED_EN (1 << 10) + + +#define SDIO_HOST_CTRL_TMOUT_MASK (0xf << 11) +#define SDIO_HOST_CTRL_TMOUT_MAX (0xf << 11) +#define SDIO_HOST_CTRL_TMOUT(x) ((x) << 11) +#define SDIO_HOST_CTRL_TMOUT_EN (1 << 15) + +#define SDIO_HOST_CTRL_DFAULT_OPEN_DRAIN \ + (SDIO_HOST_CTRL_TMOUT(x)(0xf)) +#define SDIO_HOST_CTRL_DFAULT_PUSH_PULL \ + (SDIO_HOST_CTRL_TMOUT(x)(0xf) | SDIO_HOST_CTRL_PUSH_PULL_EN) + + +/* + * NOR status bits + */ + +#define SDIO_NOR_ERROR (1 << 15) +#define SDIO_NOR_UNEXP_RSP (1 << 14) +#define SDIO_NOR_AUTOCMD12_DONE (1 << 13) +#define SDIO_NOR_SUSPEND_ON (1 << 12) +#define SDIO_NOR_LMB_FF_8W_AVAIL (1 << 11) +#define SDIO_NOR_LMB_FF_8W_FILLED (1 << 10) +#define SDIO_NOR_READ_WAIT_ON (1 << 9) +#define SDIO_NOR_CARD_INT (1 << 8) +#define SDIO_NOR_READ_READY (1 << 5) +#define SDIO_NOR_WRITE_READY (1 << 4) +#define SDIO_NOR_DMA_INI (1 << 3) +#define SDIO_NOR_BLK_GAP_EVT (1 << 2) +#define SDIO_NOR_XFER_DONE (1 << 1) +#define SDIO_NOR_CMD_DONE (1 << 0) + + +/* + * ERR status bits + */ + +#define SDIO_ERR_CRC_STATUS (1 << 14) +#define SDIO_ERR_CRC_STARTBIT (1 << 13) +#define SDIO_ERR_CRC_ENDBIT (1 << 12) +#define SDIO_ERR_RESP_TBIT (1 << 11) +#define SDIO_ERR_SIZE (1 << 10) +#define SDIO_ERR_CMD_STARTBIT (1 << 9) +#define SDIO_ERR_AUTOCMD12 (1 << 8) +#define SDIO_ERR_DATA_ENDBIT (1 << 6) +#define SDIO_ERR_DATA_CRC (1 << 5) +#define SDIO_ERR_DATA_TIMEOUT (1 << 4) +#define SDIO_ERR_CMD_INDEX (1 << 3) +#define SDIO_ERR_CMD_ENDBIT (1 << 2) +#define SDIO_ERR_CMD_CRC (1 << 1) +#define SDIO_ERR_CMD_TIMEOUT (1 << 0) + +#define SDIO_POLL_MASK 0xffff /* enable all for polling */ + + +#define MMC_BLOCK_SIZE 512 +#define MMC_CMD_RESET 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RCA 3 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_BLOCK 17 +#define MMC_CMD_RD_BLK_MULTI 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_MAX_BLOCK_SIZE 512 + +typedef struct mmc_cid +{ + /* FIXME: BYTE_ORDER */ + uchar year:4, + month:4; + uchar sn[3]; + uchar fwrev:4, + hwrev:4; + uchar name[6]; + uchar id[3]; +} mmc_cid_t; + +typedef struct mmc_csd +{ + uchar ecc:2, + file_format:2, + tmp_write_protect:1, + perm_write_protect:1, + copy:1, + file_format_grp:1; + uint64_t content_prot_app:1, + rsvd3:4, + write_bl_partial:1, + write_bl_len:4, + r2w_factor:3, + default_ecc:2, + wp_grp_enable:1, + wp_grp_size:5, + erase_grp_mult:5, + erase_grp_size:5, + c_size_mult1:3, + vdd_w_curr_max:3, + vdd_w_curr_min:3, + vdd_r_curr_max:3, + vdd_r_curr_min:3, + c_size:12, + rsvd2:2, + dsr_imp:1, + read_blk_misalign:1, + write_blk_misalign:1, + read_bl_partial:1; + ushort read_bl_len:4, + ccc:12; + uchar tran_speed; + uchar nsac; + uchar taac; + uchar rsvd1:2, + spec_vers:4, + csd_structure:2; +} mmc_csd_t; + +typedef struct { + char pnm_0; /* product name */ + char oid_1; /* OEM/application ID */ + char oid_0; + uint8_t mid; /* manufacturer ID */ + char pnm_4; + char pnm_3; + char pnm_2; + char pnm_1; + uint8_t psn_2; /* product serial number */ + uint8_t psn_1; + uint8_t psn_0; /* MSB */ + uint8_t prv; /* product revision */ + uint8_t crc; /* CRC7 checksum, b0 is unused and set to 1 */ + uint8_t mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */ + uint8_t mdt_0; /* MSB */ + uint8_t psn_3; /* LSB */ +} sd_cid_t; + +#endif /* _MVSDMMC_INCLUDE */ diff -uNr u-boot-3.4.16.orig/cpu/arm926ejs/cpu.c u-boot-3.4.16/cpu/arm926ejs/cpu.c --- u-boot-3.4.16.orig/cpu/arm926ejs/cpu.c 2008-09-10 06:28:24.000000000 +0900 +++ u-boot-3.4.16/cpu/arm926ejs/cpu.c 2009-08-21 19:12:31.000000000 +0900 @@ -183,6 +183,15 @@ cp_delay (); write_p15_c1 (reg & ~C1_IC); } + +void dcache_enable(void) +{ + u_long reg; + reg = read_p15_c1(); + cp_delay(); + write_p15_c1(reg | C1_DC); +} + void dcache_disable (void) { ulong reg; diff -uNr u-boot-3.4.16.orig/fs/fat/fat.c u-boot-3.4.16/fs/fat/fat.c --- u-boot-3.4.16.orig/fs/fat/fat.c 2009-01-01 11:15:26.000000000 +0900 +++ u-boot-3.4.16/fs/fat/fat.c 2009-04-29 13:22:29.000000000 +0900 @@ -1,1026 +1,1026 @@ -/* - * fat.c - * - * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg - * - * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 - * 2003-03-10 - kharris@nexus-tech.net - ported to uboot - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#if (CONFIG_COMMANDS & CFG_CMD_FAT) - -/* - * Convert a string to lowercase. - */ -static void -downcase(char *str) -{ - while (*str != '\0') { - TOLOWER(*str); - str++; - } -} - -static block_dev_desc_t *cur_dev = NULL; -static unsigned long part_offset = 0; -static int cur_part = 1; - -#define DOS_PART_TBL_OFFSET 0x1be -#define DOS_PART_MAGIC_OFFSET 0x1fe -#define DOS_FS_TYPE_OFFSET 0x36 - -int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) -{ - startblock += part_offset; - if (cur_dev == NULL) - return -1; - if (cur_dev->block_read) { - return cur_dev->block_read (cur_dev->dev - , startblock, getsize, (unsigned long *)bufptr); - } - return -1; -} - - -int -fat_register_device(block_dev_desc_t *dev_desc, int part_no) -{ - unsigned char buffer[SECTOR_SIZE]; - disk_partition_t info; - - if (!dev_desc->block_read) - return -1; - cur_dev = dev_desc; - /* check if we have a MBR (on floppies we have only a PBR) */ - if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) { - printf ("** Can't read from device %d **\n", dev_desc->dev); - return -1; - } - if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || - buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { - /* no signature found */ - return -1; - } -#if (defined(CONFIG_CMD_IDE) || \ - defined(CONFIG_CMD_SCSI) || \ - defined(CONFIG_CMD_USB) || \ - defined(CONFIG_MMC) || \ - defined(CONFIG_SYSTEMACE) ) - /* First we assume, there is a MBR */ - if (!get_partition_info (dev_desc, part_no, &info)) { - part_offset = info.start; - cur_part = part_no; - } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { - /* ok, we assume we are on a PBR only */ - cur_part = 1; - part_offset = 0; - } else { - printf ("** Partition %d not valid on device %d **\n", - part_no, dev_desc->dev); - return -1; - } - -#else - if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { - /* ok, we assume we are on a PBR only */ - cur_part = 1; - part_offset = 0; - info.start = part_offset; - } else { - /* FIXME we need to determine the start block of the - * partition where the DOS FS resides. This can be done - * by using the get_partition_info routine. For this - * purpose the libpart must be included. - */ - part_offset = 32; - cur_part = 1; - } -#endif - return 0; -} - - -/* - * Get the first occurence of a directory delimiter ('/' or '\') in a string. - * Return index into string if found, -1 otherwise. - */ -static int -dirdelim(char *str) -{ - char *start = str; - - while (*str != '\0') { - if (ISDIRDELIM(*str)) return str - start; - str++; - } - return -1; -} - - -/* - * Match volume_info fs_type strings. - * Return 0 on match, -1 otherwise. - */ -static int -compare_sign(char *str1, char *str2) -{ - char *end = str1+SIGNLEN; - - while (str1 != end) { - if (*str1 != *str2) { - return -1; - } - str1++; - str2++; - } - - return 0; -} - - -/* - * Extract zero terminated short name from a directory entry. - */ -static void get_name (dir_entry *dirent, char *s_name) -{ - char *ptr; - - memcpy (s_name, dirent->name, 8); - s_name[8] = '\0'; - ptr = s_name; - while (*ptr && *ptr != ' ') - ptr++; - if (dirent->ext[0] && dirent->ext[0] != ' ') { - *ptr = '.'; - ptr++; - memcpy (ptr, dirent->ext, 3); - ptr[3] = '\0'; - while (*ptr && *ptr != ' ') - ptr++; - } - *ptr = '\0'; - if (*s_name == DELETED_FLAG) - *s_name = '\0'; - else if (*s_name == aRING) - *s_name = ''; - downcase (s_name); -} - -/* - * Get the entry at index 'entry' in a FAT (12/16/32) table. - * On failure 0x00 is returned. - */ -static __u32 -get_fatent(fsdata *mydata, __u32 entry) -{ - __u32 bufnum; - __u32 offset; - __u32 ret = 0x00; - - switch (mydata->fatsize) { - case 32: - bufnum = entry / FAT32BUFSIZE; - offset = entry - bufnum * FAT32BUFSIZE; - break; - case 16: - bufnum = entry / FAT16BUFSIZE; - offset = entry - bufnum * FAT16BUFSIZE; - break; - case 12: - bufnum = entry / FAT12BUFSIZE; - offset = entry - bufnum * FAT12BUFSIZE; - break; - - default: - /* Unsupported FAT size */ - return ret; - } - - /* Read a new block of FAT entries into the cache. */ - if (bufnum != mydata->fatbufnum) { - int getsize = FATBUFSIZE/FS_BLOCK_SIZE; - __u8 *bufptr = mydata->fatbuf; - __u32 fatlength = mydata->fatlength; - __u32 startblock = bufnum * FATBUFBLOCKS; - - fatlength *= SECTOR_SIZE; /* We want it in bytes now */ - startblock += mydata->fat_sect; /* Offset from start of disk */ - - if (getsize > fatlength) getsize = fatlength; - if (disk_read(startblock, getsize, bufptr) < 0) { - FAT_DPRINT("Error reading FAT blocks\n"); - return ret; - } - mydata->fatbufnum = bufnum; - } - - /* Get the actual entry from the table */ - switch (mydata->fatsize) { - case 32: - ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]); - break; - case 16: - ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]); - break; - case 12: { - __u32 off16 = (offset*3)/4; - __u16 val1, val2; - - switch (offset & 0x3) { - case 0: - ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); - ret &= 0xfff; - break; - case 1: - val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); - val1 &= 0xf000; - val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); - val2 &= 0x00ff; - ret = (val2 << 4) | (val1 >> 12); - break; - case 2: - val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); - val1 &= 0xff00; - val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); - val2 &= 0x000f; - ret = (val2 << 8) | (val1 >> 8); - break; - case 3: - ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);; - ret = (ret & 0xfff0) >> 4; - break; - default: - break; - } - } - break; - } - FAT_DPRINT("ret: %d, offset: %d\n", ret, offset); - - return ret; -} - - -/* - * Read at most 'size' bytes from the specified cluster into 'buffer'. - * Return 0 on success, -1 otherwise. - */ -static int -get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) -{ - int idx = 0; - __u32 startsect; - - if (clustnum > 0) { - startsect = mydata->data_begin + clustnum*mydata->clust_size; - } else { - startsect = mydata->rootdir_sect; - } - - FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); - if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) { - FAT_DPRINT("Error reading data\n"); - return -1; - } - if(size % FS_BLOCK_SIZE) { - __u8 tmpbuf[FS_BLOCK_SIZE]; - idx= size/FS_BLOCK_SIZE; - if (disk_read(startsect + idx, 1, tmpbuf) < 0) { - FAT_DPRINT("Error reading data\n"); - return -1; - } - buffer += idx*FS_BLOCK_SIZE; - - memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE); - return 0; - } - - return 0; -} - - -/* - * Read at most 'maxsize' bytes from the file associated with 'dentptr' - * into 'buffer'. - * Return the number of bytes read or -1 on fatal errors. - */ -static long -get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, - unsigned long maxsize) -{ - unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; - unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE; - __u32 curclust = START(dentptr); - __u32 endclust, newclust; - unsigned long actsize; - - FAT_DPRINT("Filesize: %ld bytes\n", filesize); - - if (maxsize > 0 && filesize > maxsize) filesize = maxsize; - - FAT_DPRINT("Reading: %ld bytes\n", filesize); - - actsize=bytesperclust; - endclust=curclust; - do { - /* search for consecutive clusters */ - while(actsize < filesize) { - newclust = get_fatent(mydata, endclust); - if((newclust -1)!=endclust) - goto getit; - if (newclust <= 0x0001 || newclust >= 0xfff0) { - FAT_DPRINT("curclust: 0x%x\n", newclust); - FAT_DPRINT("Invalid FAT entry\n"); - return gotsize; - } - endclust=newclust; - actsize+= bytesperclust; - } - /* actsize >= file size */ - actsize -= bytesperclust; - /* get remaining clusters */ - if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { - FAT_ERROR("Error reading cluster\n"); - return -1; - } - /* get remaining bytes */ - gotsize += (int)actsize; - filesize -= actsize; - buffer += actsize; - actsize= filesize; - if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) { - FAT_ERROR("Error reading cluster\n"); - return -1; - } - gotsize+=actsize; - return gotsize; -getit: - if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { - FAT_ERROR("Error reading cluster\n"); - return -1; - } - gotsize += (int)actsize; - filesize -= actsize; - buffer += actsize; - curclust = get_fatent(mydata, endclust); - if (curclust <= 0x0001 || curclust >= 0xfff0) { - FAT_DPRINT("curclust: 0x%x\n", curclust); - FAT_ERROR("Invalid FAT entry\n"); - return gotsize; - } - actsize=bytesperclust; - endclust=curclust; - } while (1); -} - - -#ifdef CONFIG_SUPPORT_VFAT -/* - * Extract the file name information from 'slotptr' into 'l_name', - * starting at l_name[*idx]. - * Return 1 if terminator (zero byte) is found, 0 otherwise. - */ -static int -slot2str(dir_slot *slotptr, char *l_name, int *idx) -{ - int j; - - for (j = 0; j <= 8; j += 2) { - l_name[*idx] = slotptr->name0_4[j]; - if (l_name[*idx] == 0x00) return 1; - (*idx)++; - } - for (j = 0; j <= 10; j += 2) { - l_name[*idx] = slotptr->name5_10[j]; - if (l_name[*idx] == 0x00) return 1; - (*idx)++; - } - for (j = 0; j <= 2; j += 2) { - l_name[*idx] = slotptr->name11_12[j]; - if (l_name[*idx] == 0x00) return 1; - (*idx)++; - } - - return 0; -} - - -/* - * Extract the full long filename starting at 'retdent' (which is really - * a slot) into 'l_name'. If successful also copy the real directory entry - * into 'retdent' - * Return 0 on success, -1 otherwise. - */ -__u8 get_vfatname_block[MAX_CLUSTSIZE]; -static int -get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, - dir_entry *retdent, char *l_name) -{ - dir_entry *realdent; - dir_slot *slotptr = (dir_slot*) retdent; - __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; - __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; - int idx = 0; - - while ((__u8*)slotptr < nextclust) { - if (counter == 0) break; - if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) - return -1; - slotptr++; - counter--; - } - - if ((__u8*)slotptr >= nextclust) { - dir_slot *slotptr2; - - slotptr--; - curclust = get_fatent(mydata, curclust); - if (curclust <= 0x0001 || curclust >= 0xfff0) { - FAT_DPRINT("curclust: 0x%x\n", curclust); - FAT_ERROR("Invalid FAT entry\n"); - return -1; - } - if (get_cluster(mydata, curclust, get_vfatname_block, - mydata->clust_size * SECTOR_SIZE) != 0) { - FAT_DPRINT("Error: reading directory block\n"); - return -1; - } - slotptr2 = (dir_slot*) get_vfatname_block; - while (slotptr2->id > 0x01) { - slotptr2++; - } - /* Save the real directory entry */ - realdent = (dir_entry*)slotptr2 + 1; - while ((__u8*)slotptr2 >= get_vfatname_block) { - slot2str(slotptr2, l_name, &idx); - slotptr2--; - } - } else { - /* Save the real directory entry */ - realdent = (dir_entry*)slotptr; - } - - do { - slotptr--; - if (slot2str(slotptr, l_name, &idx)) break; - } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); - - l_name[idx] = '\0'; - if (*l_name == DELETED_FLAG) *l_name = '\0'; - else if (*l_name == aRING) *l_name = ''; - downcase(l_name); - - /* Return the real directory entry */ - memcpy(retdent, realdent, sizeof(dir_entry)); - - return 0; -} - - -/* Calculate short name checksum */ -static __u8 -mkcksum(const char *str) -{ - int i; - __u8 ret = 0; - - for (i = 0; i < 11; i++) { - ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i]; - } - - return ret; -} -#endif - - -/* - * Get the directory entry associated with 'filename' from the directory - * starting at 'startsect' - */ -__u8 get_dentfromdir_block[MAX_CLUSTSIZE]; -static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, - char *filename, dir_entry * retdent, - int dols) -{ - __u16 prevcksum = 0xffff; - __u32 curclust = START (retdent); - int files = 0, dirs = 0; - - FAT_DPRINT ("get_dentfromdir: %s\n", filename); - while (1) { - dir_entry *dentptr; - int i; - - if (get_cluster (mydata, curclust, get_dentfromdir_block, - mydata->clust_size * SECTOR_SIZE) != 0) { - FAT_DPRINT ("Error: reading directory block\n"); - return NULL; - } - dentptr = (dir_entry *) get_dentfromdir_block; - for (i = 0; i < DIRENTSPERCLUST; i++) { - char s_name[14], l_name[256]; - - l_name[0] = '\0'; - if (dentptr->name[0] == DELETED_FLAG) { - dentptr++; - continue; - } - if ((dentptr->attr & ATTR_VOLUME)) { -#ifdef CONFIG_SUPPORT_VFAT - if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - prevcksum = ((dir_slot *) dentptr) - ->alias_checksum; - get_vfatname (mydata, curclust, get_dentfromdir_block, - dentptr, l_name); - if (dols) { - int isdir = (dentptr->attr & ATTR_DIR); - char dirc; - int doit = 0; - - if (isdir) { - dirs++; - dirc = '/'; - doit = 1; - } else { - dirc = ' '; - if (l_name[0] != 0) { - files++; - doit = 1; - } - } - if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", - (long) FAT2CPU32 (dentptr->size), - l_name, dirc); - } else { - printf (" %s%c\n", l_name, dirc); - } - } - dentptr++; - continue; - } - FAT_DPRINT ("vfatname: |%s|\n", l_name); - } else -#endif - { - /* Volume label or VFAT entry */ - dentptr++; - continue; - } - } - if (dentptr->name[0] == 0) { - if (dols) { - printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); - } - FAT_DPRINT ("Dentname == NULL - %d\n", i); - return NULL; - } -#ifdef CONFIG_SUPPORT_VFAT - if (dols && mkcksum (dentptr->name) == prevcksum) { - dentptr++; - continue; - } -#endif - get_name (dentptr, s_name); - if (dols) { - int isdir = (dentptr->attr & ATTR_DIR); - char dirc; - int doit = 0; - - if (isdir) { - dirs++; - dirc = '/'; - doit = 1; - } else { - dirc = ' '; - if (s_name[0] != 0) { - files++; - doit = 1; - } - } - if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", - (long) FAT2CPU32 (dentptr->size), s_name, - dirc); - } else { - printf (" %s%c\n", s_name, dirc); - } - } - dentptr++; - continue; - } - if (strcmp (filename, s_name) && strcmp (filename, l_name)) { - FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); - dentptr++; - continue; - } - memcpy (retdent, dentptr, sizeof (dir_entry)); - - FAT_DPRINT ("DentName: %s", s_name); - FAT_DPRINT (", start: 0x%x", START (dentptr)); - FAT_DPRINT (", size: 0x%x %s\n", - FAT2CPU32 (dentptr->size), - (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); - - return retdent; - } - curclust = get_fatent (mydata, curclust); - if (curclust <= 0x0001 || curclust >= 0xfff0) { - FAT_DPRINT ("curclust: 0x%x\n", curclust); - FAT_ERROR ("Invalid FAT entry\n"); - return NULL; - } - } - - return NULL; -} - - -/* - * Read boot sector and volume info from a FAT filesystem - */ -static int -read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) -{ - __u8 block[FS_BLOCK_SIZE]; - volume_info *vistart; - - if (disk_read(0, 1, block) < 0) { - FAT_DPRINT("Error: reading block\n"); - return -1; - } - - memcpy(bs, block, sizeof(boot_sector)); - bs->reserved = FAT2CPU16(bs->reserved); - bs->fat_length = FAT2CPU16(bs->fat_length); - bs->secs_track = FAT2CPU16(bs->secs_track); - bs->heads = FAT2CPU16(bs->heads); -#if 0 /* UNUSED */ - bs->hidden = FAT2CPU32(bs->hidden); -#endif - bs->total_sect = FAT2CPU32(bs->total_sect); - - /* FAT32 entries */ - if (bs->fat_length == 0) { - /* Assume FAT32 */ - bs->fat32_length = FAT2CPU32(bs->fat32_length); - bs->flags = FAT2CPU16(bs->flags); - bs->root_cluster = FAT2CPU32(bs->root_cluster); - bs->info_sector = FAT2CPU16(bs->info_sector); - bs->backup_boot = FAT2CPU16(bs->backup_boot); - vistart = (volume_info*) (block + sizeof(boot_sector)); - *fatsize = 32; - } else { - vistart = (volume_info*) &(bs->fat32_length); - *fatsize = 0; - } - memcpy(volinfo, vistart, sizeof(volume_info)); - - /* Terminate fs_type string. Writing past the end of vistart - is ok - it's just the buffer. */ - vistart->fs_type[8] = '\0'; - - if (*fatsize == 32) { - if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) { - return 0; - } - } else { - if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) { - *fatsize = 12; - return 0; - } - if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) { - *fatsize = 16; - return 0; - } - } - - FAT_DPRINT("Error: broken fs_type sign\n"); - return -1; -} - - -__u8 do_fat_read_block[MAX_CLUSTSIZE]; /* Block buffer */ -long -do_fat_read (const char *filename, void *buffer, unsigned long maxsize, - int dols) -{ -#if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ - static -#endif - char fnamecopy[2048]; - boot_sector bs; - volume_info volinfo; - fsdata datablock; - fsdata *mydata = &datablock; - dir_entry *dentptr; - __u16 prevcksum = 0xffff; - char *subname = ""; - int rootdir_size, cursect; - int idx, isdir = 0; - int files = 0, dirs = 0; - long ret = 0; - int firsttime; - - if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { - FAT_DPRINT ("Error: reading boot sector\n"); - return -1; - } - if (mydata->fatsize == 32) { - mydata->fatlength = bs.fat32_length; - } else { - mydata->fatlength = bs.fat_length; - } - mydata->fat_sect = bs.reserved; - cursect = mydata->rootdir_sect - = mydata->fat_sect + mydata->fatlength * bs.fats; - mydata->clust_size = bs.cluster_size; - if (mydata->fatsize == 32) { - rootdir_size = mydata->clust_size; - mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ - - (mydata->clust_size * 2); - } else { - rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0]) - * sizeof (dir_entry)) / SECTOR_SIZE; - mydata->data_begin = mydata->rootdir_sect + rootdir_size - - (mydata->clust_size * 2); - } - mydata->fatbufnum = -1; - - FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, - mydata->fatlength); - FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" - "Data begins at: %d\n", - mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, - rootdir_size, mydata->data_begin); - FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); - - /* "cwd" is always the root... */ - while (ISDIRDELIM (*filename)) - filename++; - /* Make a copy of the filename and convert it to lowercase */ - strcpy (fnamecopy, filename); - downcase (fnamecopy); - if (*fnamecopy == '\0') { - if (!dols) - return -1; - dols = LS_ROOT; - } else if ((idx = dirdelim (fnamecopy)) >= 0) { - isdir = 1; - fnamecopy[idx] = '\0'; - subname = fnamecopy + idx + 1; - /* Handle multiple delimiters */ - while (ISDIRDELIM (*subname)) - subname++; - } else if (dols) { - isdir = 1; - } - - while (1) { - int i; - - if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) { - FAT_DPRINT ("Error: reading rootdir block\n"); - return -1; - } - dentptr = (dir_entry *) do_fat_read_block; - for (i = 0; i < DIRENTSPERBLOCK; i++) { - char s_name[14], l_name[256]; - - l_name[0] = '\0'; - if ((dentptr->attr & ATTR_VOLUME)) { -#ifdef CONFIG_SUPPORT_VFAT - if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - prevcksum = ((dir_slot *) dentptr)->alias_checksum; - get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); - if (dols == LS_ROOT) { - int isdir = (dentptr->attr & ATTR_DIR); - char dirc; - int doit = 0; - - if (isdir) { - dirs++; - dirc = '/'; - doit = 1; - } else { - dirc = ' '; - if (l_name[0] != 0) { - files++; - doit = 1; - } - } - if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", - (long) FAT2CPU32 (dentptr->size), - l_name, dirc); - } else { - printf (" %s%c\n", l_name, dirc); - } - } - dentptr++; - continue; - } - FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); - } else -#endif - { - /* Volume label or VFAT entry */ - dentptr++; - continue; - } - } else if (dentptr->name[0] == 0) { - FAT_DPRINT ("RootDentname == NULL - %d\n", i); - if (dols == LS_ROOT) { - printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); - return 0; - } - return -1; - } -#ifdef CONFIG_SUPPORT_VFAT - else if (dols == LS_ROOT - && mkcksum (dentptr->name) == prevcksum) { - dentptr++; - continue; - } -#endif - get_name (dentptr, s_name); - if (dols == LS_ROOT) { - int isdir = (dentptr->attr & ATTR_DIR); - char dirc; - int doit = 0; - - if (isdir) { - dirc = '/'; - if (s_name[0] != 0) { - dirs++; - doit = 1; - } - } else { - dirc = ' '; - if (s_name[0] != 0) { - files++; - doit = 1; - } - } - if (doit) { - if (dirc == ' ') { - printf (" %8ld %s%c\n", - (long) FAT2CPU32 (dentptr->size), s_name, - dirc); - } else { - printf (" %s%c\n", s_name, dirc); - } - } - dentptr++; - continue; - } - if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { - FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); - dentptr++; - continue; - } - if (isdir && !(dentptr->attr & ATTR_DIR)) - return -1; - - FAT_DPRINT ("RootName: %s", s_name); - FAT_DPRINT (", start: 0x%x", START (dentptr)); - FAT_DPRINT (", size: 0x%x %s\n", - FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); - - goto rootdir_done; /* We got a match */ - } - cursect++; - } - rootdir_done: - - firsttime = 1; - while (isdir) { - int startsect = mydata->data_begin - + START (dentptr) * mydata->clust_size; - dir_entry dent; - char *nextname = NULL; - - dent = *dentptr; - dentptr = &dent; - - idx = dirdelim (subname); - if (idx >= 0) { - subname[idx] = '\0'; - nextname = subname + idx + 1; - /* Handle multiple delimiters */ - while (ISDIRDELIM (*nextname)) - nextname++; - if (dols && *nextname == '\0') - firsttime = 0; - } else { - if (dols && firsttime) { - firsttime = 0; - } else { - isdir = 0; - } - } - - if (get_dentfromdir (mydata, startsect, subname, dentptr, - isdir ? 0 : dols) == NULL) { - if (dols && !isdir) - return 0; - return -1; - } - - if (idx >= 0) { - if (!(dentptr->attr & ATTR_DIR)) - return -1; - subname = nextname; - } - } - ret = get_contents (mydata, dentptr, buffer, maxsize); - FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); - - return ret; -} - - -int -file_fat_detectfs(void) -{ - boot_sector bs; - volume_info volinfo; - int fatsize; - char vol_label[12]; - - if(cur_dev==NULL) { - printf("No current device\n"); - return 1; - } -#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ - (CONFIG_COMMANDS & CFG_CMD_USB) || (CONFIG_COMMANDS & CFG_CMD_MMC) - printf("Interface: "); - switch(cur_dev->if_type) { - case IF_TYPE_IDE : printf("IDE"); break; - case IF_TYPE_SCSI : printf("SCSI"); break; - case IF_TYPE_ATAPI : printf("ATAPI"); break; - case IF_TYPE_USB : printf("USB"); break; - case IF_TYPE_DOC : printf("DOC"); break; - case IF_TYPE_MMC : printf("MMC"); break; - default : printf("Unknown"); - } - printf("\n Device %d: ",cur_dev->dev); - dev_print(cur_dev); -#endif - if(read_bootsectandvi(&bs, &volinfo, &fatsize)) { - printf("\nNo valid FAT fs found\n"); - return 1; - } - memcpy (vol_label, volinfo.volume_label, 11); - vol_label[11] = '\0'; - volinfo.fs_type[5]='\0'; - printf("Partition %d: Filesystem: %s \"%s\"\n" - ,cur_part,volinfo.fs_type,vol_label); - return 0; -} - - -int -file_fat_ls(const char *dir) -{ - return do_fat_read(dir, NULL, 0, LS_YES); -} - - -long -file_fat_read(const char *filename, void *buffer, unsigned long maxsize) -{ - printf("reading %s\n",filename); - return do_fat_read(filename, buffer, maxsize, LS_NO); -} - -#endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */ +/* + * fat.c + * + * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg + * + * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 + * 2003-03-10 - kharris@nexus-tech.net - ported to uboot + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_FAT) + +/* + * Convert a string to lowercase. + */ +static void +downcase(char *str) +{ + while (*str != '\0') { + TOLOWER(*str); + str++; + } +} + +static block_dev_desc_t *cur_dev = NULL; +static unsigned long part_offset = 0; +static int cur_part = 1; + +#define DOS_PART_TBL_OFFSET 0x1be +#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_FS_TYPE_OFFSET 0x36 + +int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) +{ + startblock += part_offset; + if (cur_dev == NULL) + return -1; + if (cur_dev->block_read) { + return cur_dev->block_read (cur_dev->dev + , startblock, getsize, (unsigned long *)bufptr); + } + return -1; +} + + +int +fat_register_device(block_dev_desc_t *dev_desc, int part_no) +{ + unsigned char buffer[SECTOR_SIZE]; + disk_partition_t info; + + if (!dev_desc->block_read) + return -1; + cur_dev = dev_desc; + /* check if we have a MBR (on floppies we have only a PBR) */ + if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) { + printf ("** Can't read from device %d **\n", dev_desc->dev); + return -1; + } + if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || + buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { + /* no signature found */ + return -1; + } +#if (defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) ) + /* First we assume, there is a MBR */ + if (!get_partition_info (dev_desc, part_no, &info)) { + part_offset = info.start; + cur_part = part_no; + } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { + /* ok, we assume we are on a PBR only */ + cur_part = 1; + part_offset = 0; + } else { + printf ("** Partition %d not valid on device %d **\n", + part_no, dev_desc->dev); + return -1; + } + +#else + if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { + /* ok, we assume we are on a PBR only */ + cur_part = 1; + part_offset = 0; + info.start = part_offset; + } else { + /* FIXME we need to determine the start block of the + * partition where the DOS FS resides. This can be done + * by using the get_partition_info routine. For this + * purpose the libpart must be included. + */ + part_offset = 32; + cur_part = 1; + } +#endif + return 0; +} + + +/* + * Get the first occurence of a directory delimiter ('/' or '\') in a string. + * Return index into string if found, -1 otherwise. + */ +static int +dirdelim(char *str) +{ + char *start = str; + + while (*str != '\0') { + if (ISDIRDELIM(*str)) return str - start; + str++; + } + return -1; +} + + +/* + * Match volume_info fs_type strings. + * Return 0 on match, -1 otherwise. + */ +static int +compare_sign(char *str1, char *str2) +{ + char *end = str1+SIGNLEN; + + while (str1 != end) { + if (*str1 != *str2) { + return -1; + } + str1++; + str2++; + } + + return 0; +} + + +/* + * Extract zero terminated short name from a directory entry. + */ +static void get_name (dir_entry *dirent, char *s_name) +{ + char *ptr; + + memcpy (s_name, dirent->name, 8); + s_name[8] = '\0'; + ptr = s_name; + while (*ptr && *ptr != ' ') + ptr++; + if (dirent->ext[0] && dirent->ext[0] != ' ') { + *ptr = '.'; + ptr++; + memcpy (ptr, dirent->ext, 3); + ptr[3] = '\0'; + while (*ptr && *ptr != ' ') + ptr++; + } + *ptr = '\0'; + if (*s_name == DELETED_FLAG) + *s_name = '\0'; + else if (*s_name == aRING) + *s_name = ''; + downcase (s_name); +} + +/* + * Get the entry at index 'entry' in a FAT (12/16/32) table. + * On failure 0x00 is returned. + */ +static __u32 +get_fatent(fsdata *mydata, __u32 entry) +{ + __u32 bufnum; + __u32 offset; + __u32 ret = 0x00; + + switch (mydata->fatsize) { + case 32: + bufnum = entry / FAT32BUFSIZE; + offset = entry - bufnum * FAT32BUFSIZE; + break; + case 16: + bufnum = entry / FAT16BUFSIZE; + offset = entry - bufnum * FAT16BUFSIZE; + break; + case 12: + bufnum = entry / FAT12BUFSIZE; + offset = entry - bufnum * FAT12BUFSIZE; + break; + + default: + /* Unsupported FAT size */ + return ret; + } + + /* Read a new block of FAT entries into the cache. */ + if (bufnum != mydata->fatbufnum) { + int getsize = FATBUFSIZE/FS_BLOCK_SIZE; + __u8 *bufptr = mydata->fatbuf; + __u32 fatlength = mydata->fatlength; + __u32 startblock = bufnum * FATBUFBLOCKS; + + fatlength *= SECTOR_SIZE; /* We want it in bytes now */ + startblock += mydata->fat_sect; /* Offset from start of disk */ + + if (getsize > fatlength) getsize = fatlength; + if (disk_read(startblock, getsize, bufptr) < 0) { + FAT_DPRINT("Error reading FAT blocks\n"); + return ret; + } + mydata->fatbufnum = bufnum; + } + + /* Get the actual entry from the table */ + switch (mydata->fatsize) { + case 32: + ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]); + break; + case 16: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]); + break; + case 12: { + __u32 off16 = (offset*3)/4; + __u16 val1, val2; + + switch (offset & 0x3) { + case 0: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + ret &= 0xfff; + break; + case 1: + val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + val1 &= 0xf000; + val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); + val2 &= 0x00ff; + ret = (val2 << 4) | (val1 >> 12); + break; + case 2: + val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + val1 &= 0xff00; + val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); + val2 &= 0x000f; + ret = (val2 << 8) | (val1 >> 8); + break; + case 3: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);; + ret = (ret & 0xfff0) >> 4; + break; + default: + break; + } + } + break; + } + FAT_DPRINT("ret: %d, offset: %d\n", ret, offset); + + return ret; +} + + +/* + * Read at most 'size' bytes from the specified cluster into 'buffer'. + * Return 0 on success, -1 otherwise. + */ +static int +get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) +{ + int idx = 0; + __u32 startsect; + + if (clustnum > 0) { + startsect = mydata->data_begin + clustnum*mydata->clust_size; + } else { + startsect = mydata->rootdir_sect; + } + + FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); + if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) { + FAT_DPRINT("Error reading data\n"); + return -1; + } + if(size % FS_BLOCK_SIZE) { + __u8 tmpbuf[FS_BLOCK_SIZE]; + idx= size/FS_BLOCK_SIZE; + if (disk_read(startsect + idx, 1, tmpbuf) < 0) { + FAT_DPRINT("Error reading data\n"); + return -1; + } + buffer += idx*FS_BLOCK_SIZE; + + memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE); + return 0; + } + + return 0; +} + + +/* + * Read at most 'maxsize' bytes from the file associated with 'dentptr' + * into 'buffer'. + * Return the number of bytes read or -1 on fatal errors. + */ +static long +get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, + unsigned long maxsize) +{ + unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; + unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE; + __u32 curclust = START(dentptr); + __u32 endclust, newclust; + unsigned long actsize; + + FAT_DPRINT("Filesize: %ld bytes\n", filesize); + + if (maxsize > 0 && filesize > maxsize) filesize = maxsize; + + FAT_DPRINT("Reading: %ld bytes\n", filesize); + + actsize=bytesperclust; + endclust=curclust; + do { + /* search for consecutive clusters */ + while(actsize < filesize) { + newclust = get_fatent(mydata, endclust); + if((newclust -1)!=endclust) + goto getit; + if (CHECK_CLUST(newclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%08x fatsize=%d\n", newclust, mydata->fatsize); + FAT_ERROR("Invalid FAT entry\n"); + return gotsize; + } + endclust=newclust; + actsize+= bytesperclust; + } + /* actsize >= file size */ + actsize -= bytesperclust; + /* get remaining clusters */ + if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + /* get remaining bytes */ + gotsize += (int)actsize; + filesize -= actsize; + buffer += actsize; + actsize= filesize; + if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + gotsize+=actsize; + return gotsize; +getit: + if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + gotsize += (int)actsize; + filesize -= actsize; + buffer += actsize; + curclust = get_fatent(mydata, endclust); + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%08x fatsize=%d\n", curclust, mydata->fatsize); + FAT_ERROR("Invalid FAT entry\n"); + return gotsize; + } + actsize=bytesperclust; + endclust=curclust; + } while (1); +} + + +#ifdef CONFIG_SUPPORT_VFAT +/* + * Extract the file name information from 'slotptr' into 'l_name', + * starting at l_name[*idx]. + * Return 1 if terminator (zero byte) is found, 0 otherwise. + */ +static int +slot2str(dir_slot *slotptr, char *l_name, int *idx) +{ + int j; + + for (j = 0; j <= 8; j += 2) { + l_name[*idx] = slotptr->name0_4[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + for (j = 0; j <= 10; j += 2) { + l_name[*idx] = slotptr->name5_10[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + for (j = 0; j <= 2; j += 2) { + l_name[*idx] = slotptr->name11_12[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + + return 0; +} + + +/* + * Extract the full long filename starting at 'retdent' (which is really + * a slot) into 'l_name'. If successful also copy the real directory entry + * into 'retdent' + * Return 0 on success, -1 otherwise. + */ +__u8 get_vfatname_block[MAX_CLUSTSIZE]; +static int +get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, + dir_entry *retdent, char *l_name) +{ + dir_entry *realdent; + dir_slot *slotptr = (dir_slot*) retdent; + __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; + __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; + int idx = 0; + + while ((__u8*)slotptr < nextclust) { + if (counter == 0) break; + if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) + return -1; + slotptr++; + counter--; + } + + if ((__u8*)slotptr >= nextclust) { + dir_slot *slotptr2; + + slotptr--; + curclust = get_fatent(mydata, curclust); + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%08x fatsize=%d\n", curclust, mydata->fatsize); + FAT_ERROR("Invalid FAT entry\n"); + return -1; + } + if (get_cluster(mydata, curclust, get_vfatname_block, + mydata->clust_size * SECTOR_SIZE) != 0) { + FAT_DPRINT("Error: reading directory block\n"); + return -1; + } + slotptr2 = (dir_slot*) get_vfatname_block; + while (slotptr2->id > 0x01) { + slotptr2++; + } + /* Save the real directory entry */ + realdent = (dir_entry*)slotptr2 + 1; + while ((__u8*)slotptr2 >= get_vfatname_block) { + slot2str(slotptr2, l_name, &idx); + slotptr2--; + } + } else { + /* Save the real directory entry */ + realdent = (dir_entry*)slotptr; + } + + do { + slotptr--; + if (slot2str(slotptr, l_name, &idx)) break; + } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); + + l_name[idx] = '\0'; + if (*l_name == DELETED_FLAG) *l_name = '\0'; + else if (*l_name == aRING) *l_name = ''; + downcase(l_name); + + /* Return the real directory entry */ + memcpy(retdent, realdent, sizeof(dir_entry)); + + return 0; +} + + +/* Calculate short name checksum */ +static __u8 +mkcksum(const char *str) +{ + int i; + __u8 ret = 0; + + for (i = 0; i < 11; i++) { + ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i]; + } + + return ret; +} +#endif + + +/* + * Get the directory entry associated with 'filename' from the directory + * starting at 'startsect' + */ +__u8 get_dentfromdir_block[MAX_CLUSTSIZE]; +static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, + char *filename, dir_entry * retdent, + int dols) +{ + __u16 prevcksum = 0xffff; + __u32 curclust = START (retdent); + int files = 0, dirs = 0; + + FAT_DPRINT ("get_dentfromdir: %s\n", filename); + while (1) { + dir_entry *dentptr; + int i; + + if (get_cluster (mydata, curclust, get_dentfromdir_block, + mydata->clust_size * SECTOR_SIZE) != 0) { + FAT_DPRINT ("Error: reading directory block\n"); + return NULL; + } + dentptr = (dir_entry *) get_dentfromdir_block; + for (i = 0; i < DIRENTSPERCLUST; i++) { + char s_name[14], l_name[256]; + + l_name[0] = '\0'; + if (dentptr->name[0] == DELETED_FLAG) { + dentptr++; + continue; + } + if ((dentptr->attr & ATTR_VOLUME)) { +#ifdef CONFIG_SUPPORT_VFAT + if ((dentptr->attr & ATTR_VFAT) && + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + prevcksum = ((dir_slot *) dentptr) + ->alias_checksum; + get_vfatname (mydata, curclust, get_dentfromdir_block, + dentptr, l_name); + if (dols) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirs++; + dirc = '/'; + doit = 1; + } else { + dirc = ' '; + if (l_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), + l_name, dirc); + } else { + printf (" %s%c\n", l_name, dirc); + } + } + dentptr++; + continue; + } + FAT_DPRINT ("vfatname: |%s|\n", l_name); + } else +#endif + { + /* Volume label or VFAT entry */ + dentptr++; + continue; + } + } + if (dentptr->name[0] == 0) { + if (dols) { + printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); + } + FAT_DPRINT ("Dentname == NULL - %d\n", i); + return NULL; + } +#ifdef CONFIG_SUPPORT_VFAT + if (dols && mkcksum (dentptr->name) == prevcksum) { + dentptr++; + continue; + } +#endif + get_name (dentptr, s_name); + if (dols) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirs++; + dirc = '/'; + doit = 1; + } else { + dirc = ' '; + if (s_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), s_name, + dirc); + } else { + printf (" %s%c\n", s_name, dirc); + } + } + dentptr++; + continue; + } + if (strcmp (filename, s_name) && strcmp (filename, l_name)) { + FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); + dentptr++; + continue; + } + memcpy (retdent, dentptr, sizeof (dir_entry)); + + FAT_DPRINT ("DentName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", + FAT2CPU32 (dentptr->size), + (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); + + return retdent; + } + curclust = get_fatent (mydata, curclust); + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_ERROR ("curclust: 0x%08x fatsize=%d\n", curclust, mydata->fatsize); + FAT_ERROR ("Invalid FAT entry\n"); + return NULL; + } + } + + return NULL; +} + + +/* + * Read boot sector and volume info from a FAT filesystem + */ +static int +read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) +{ + __u8 block[FS_BLOCK_SIZE]; + volume_info *vistart; + + if (disk_read(0, 1, block) < 0) { + FAT_DPRINT("Error: reading block\n"); + return -1; + } + + memcpy(bs, block, sizeof(boot_sector)); + bs->reserved = FAT2CPU16(bs->reserved); + bs->fat_length = FAT2CPU16(bs->fat_length); + bs->secs_track = FAT2CPU16(bs->secs_track); + bs->heads = FAT2CPU16(bs->heads); +#if 0 /* UNUSED */ + bs->hidden = FAT2CPU32(bs->hidden); +#endif + bs->total_sect = FAT2CPU32(bs->total_sect); + + /* FAT32 entries */ + if (bs->fat_length == 0) { + /* Assume FAT32 */ + bs->fat32_length = FAT2CPU32(bs->fat32_length); + bs->flags = FAT2CPU16(bs->flags); + bs->root_cluster = FAT2CPU32(bs->root_cluster); + bs->info_sector = FAT2CPU16(bs->info_sector); + bs->backup_boot = FAT2CPU16(bs->backup_boot); + vistart = (volume_info*) (block + sizeof(boot_sector)); + *fatsize = 32; + } else { + vistart = (volume_info*) &(bs->fat32_length); + *fatsize = 0; + } + memcpy(volinfo, vistart, sizeof(volume_info)); + + /* Terminate fs_type string. Writing past the end of vistart + is ok - it's just the buffer. */ + vistart->fs_type[8] = '\0'; + + if (*fatsize == 32) { + if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) { + return 0; + } + } else { + if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) { + *fatsize = 12; + return 0; + } + if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) { + *fatsize = 16; + return 0; + } + } + + FAT_DPRINT("Error: broken fs_type sign\n"); + return -1; +} + + +__u8 do_fat_read_block[MAX_CLUSTSIZE]; /* Block buffer */ +long +do_fat_read (const char *filename, void *buffer, unsigned long maxsize, + int dols) +{ +#if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ + static +#endif + char fnamecopy[2048]; + boot_sector bs; + volume_info volinfo; + fsdata datablock; + fsdata *mydata = &datablock; + dir_entry *dentptr; + __u16 prevcksum = 0xffff; + char *subname = ""; + int rootdir_size, cursect; + int idx, isdir = 0; + int files = 0, dirs = 0; + long ret = 0; + int firsttime; + + if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { + FAT_DPRINT ("Error: reading boot sector\n"); + return -1; + } + if (mydata->fatsize == 32) { + mydata->fatlength = bs.fat32_length; + } else { + mydata->fatlength = bs.fat_length; + } + mydata->fat_sect = bs.reserved; + cursect = mydata->rootdir_sect + = mydata->fat_sect + mydata->fatlength * bs.fats; + mydata->clust_size = bs.cluster_size; + if (mydata->fatsize == 32) { + rootdir_size = mydata->clust_size; + mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ + - (mydata->clust_size * 2); + } else { + rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0]) + * sizeof (dir_entry)) / SECTOR_SIZE; + mydata->data_begin = mydata->rootdir_sect + rootdir_size + - (mydata->clust_size * 2); + } + mydata->fatbufnum = -1; + + FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, + mydata->fatlength); + FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" + "Data begins at: %d\n", + mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, + rootdir_size, mydata->data_begin); + FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); + + /* "cwd" is always the root... */ + while (ISDIRDELIM (*filename)) + filename++; + /* Make a copy of the filename and convert it to lowercase */ + strcpy (fnamecopy, filename); + downcase (fnamecopy); + if (*fnamecopy == '\0') { + if (!dols) + return -1; + dols = LS_ROOT; + } else if ((idx = dirdelim (fnamecopy)) >= 0) { + isdir = 1; + fnamecopy[idx] = '\0'; + subname = fnamecopy + idx + 1; + /* Handle multiple delimiters */ + while (ISDIRDELIM (*subname)) + subname++; + } else if (dols) { + isdir = 1; + } + + while (1) { + int i; + + if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) { + FAT_DPRINT ("Error: reading rootdir block\n"); + return -1; + } + dentptr = (dir_entry *) do_fat_read_block; + for (i = 0; i < DIRENTSPERBLOCK; i++) { + char s_name[14], l_name[256]; + + l_name[0] = '\0'; + if ((dentptr->attr & ATTR_VOLUME)) { +#ifdef CONFIG_SUPPORT_VFAT + if ((dentptr->attr & ATTR_VFAT) && + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + prevcksum = ((dir_slot *) dentptr)->alias_checksum; + get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); + if (dols == LS_ROOT) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirs++; + dirc = '/'; + doit = 1; + } else { + dirc = ' '; + if (l_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), + l_name, dirc); + } else { + printf (" %s%c\n", l_name, dirc); + } + } + dentptr++; + continue; + } + FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); + } else +#endif + { + /* Volume label or VFAT entry */ + dentptr++; + continue; + } + } else if (dentptr->name[0] == 0) { + FAT_DPRINT ("RootDentname == NULL - %d\n", i); + if (dols == LS_ROOT) { + printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); + return 0; + } + return -1; + } +#ifdef CONFIG_SUPPORT_VFAT + else if (dols == LS_ROOT + && mkcksum (dentptr->name) == prevcksum) { + dentptr++; + continue; + } +#endif + get_name (dentptr, s_name); + if (dols == LS_ROOT) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirc = '/'; + if (s_name[0] != 0) { + dirs++; + doit = 1; + } + } else { + dirc = ' '; + if (s_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), s_name, + dirc); + } else { + printf (" %s%c\n", s_name, dirc); + } + } + dentptr++; + continue; + } + if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { + FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); + dentptr++; + continue; + } + if (isdir && !(dentptr->attr & ATTR_DIR)) + return -1; + + FAT_DPRINT ("RootName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", + FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); + + goto rootdir_done; /* We got a match */ + } + cursect++; + } + rootdir_done: + + firsttime = 1; + while (isdir) { + int startsect = mydata->data_begin + + START (dentptr) * mydata->clust_size; + dir_entry dent; + char *nextname = NULL; + + dent = *dentptr; + dentptr = &dent; + + idx = dirdelim (subname); + if (idx >= 0) { + subname[idx] = '\0'; + nextname = subname + idx + 1; + /* Handle multiple delimiters */ + while (ISDIRDELIM (*nextname)) + nextname++; + if (dols && *nextname == '\0') + firsttime = 0; + } else { + if (dols && firsttime) { + firsttime = 0; + } else { + isdir = 0; + } + } + + if (get_dentfromdir (mydata, startsect, subname, dentptr, + isdir ? 0 : dols) == NULL) { + if (dols && !isdir) + return 0; + return -1; + } + + if (idx >= 0) { + if (!(dentptr->attr & ATTR_DIR)) + return -1; + subname = nextname; + } + } + ret = get_contents (mydata, dentptr, buffer, maxsize); + FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); + + return ret; +} + + +int +file_fat_detectfs(void) +{ + boot_sector bs; + volume_info volinfo; + int fatsize; + char vol_label[12]; + + if(cur_dev==NULL) { + printf("No current device\n"); + return 1; + } +#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ + (CONFIG_COMMANDS & CFG_CMD_USB) || (CONFIG_COMMANDS & CFG_CMD_MMC) + printf("Interface: "); + switch(cur_dev->if_type) { + case IF_TYPE_IDE : printf("IDE"); break; + case IF_TYPE_SCSI : printf("SCSI"); break; + case IF_TYPE_ATAPI : printf("ATAPI"); break; + case IF_TYPE_USB : printf("USB"); break; + case IF_TYPE_DOC : printf("DOC"); break; + case IF_TYPE_MMC : printf("MMC"); break; + default : printf("Unknown"); + } + printf("\n Device %d: ",cur_dev->dev); + dev_print(cur_dev); +#endif + if(read_bootsectandvi(&bs, &volinfo, &fatsize)) { + printf("\nNo valid FAT fs found\n"); + return 1; + } + memcpy (vol_label, volinfo.volume_label, 11); + vol_label[11] = '\0'; + volinfo.fs_type[5]='\0'; + printf("Partition %d: Filesystem: %s \"%s\"\n" + ,cur_part,volinfo.fs_type,vol_label); + return 0; +} + + +int +file_fat_ls(const char *dir) +{ + return do_fat_read(dir, NULL, 0, LS_YES); +} + + +long +file_fat_read(const char *filename, void *buffer, unsigned long maxsize) +{ + printf("reading %s\n",filename); + return do_fat_read(filename, buffer, maxsize, LS_NO); +} + +#endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */ diff -uNr u-boot-3.4.16.orig/include/configs/mv_kw.h u-boot-3.4.16/include/configs/mv_kw.h --- u-boot-3.4.16.orig/include/configs/mv_kw.h 2009-03-03 06:15:18.000000000 +0900 +++ u-boot-3.4.16/include/configs/mv_kw.h 2009-08-21 19:13:33.000000000 +0900 @@ -150,6 +150,8 @@ | CFG_CMD_FLASH \ | CFG_CMD_MEMORY \ | CFG_CMD_IDE \ + | CFG_CMD_IMI \ + | CFG_CMD_CACHE \ | CFG_CMD_EXT2 \ | CFG_CMD_ENV \ | CFG_CMD_BOOTD \ @@ -161,6 +163,8 @@ #endif +#define MV_MMC + #if defined(MV_NAND) || defined(MV_NAND_BOOT) #define CONFIG_CMD_BASIC1 (CONFIG_CMD_BASIC | CFG_CMD_NAND) #else @@ -383,7 +387,7 @@ /* SDIO/MMC */ /************/ -#if defined(MV_88F6183) || defined(MV_88F6183L) +#if defined(MV_88F6183) || defined(MV_88F6183L) || defined(MV88F6281) #define CONFIG_MMC #define CFG_MMC_BASE 0xF0000000 #endif diff -uNr u-boot-3.4.16.orig/include/fat.h u-boot-3.4.16/include/fat.h --- u-boot-3.4.16.orig/include/fat.h 2009-01-05 07:54:28.000000000 +0900 +++ u-boot-3.4.16/include/fat.h 2009-04-29 14:06:28.000000000 +0900 @@ -1,216 +1,218 @@ -/* - * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg - * - * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 - * 2003-03-10 - kharris@nexus-tech.net - ported to u-boot - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef _FAT_H_ -#define _FAT_H_ - -#include - -#define CONFIG_SUPPORT_VFAT - -#define SECTOR_SIZE FS_BLOCK_SIZE - -#define FS_BLOCK_SIZE 512 - -#if FS_BLOCK_SIZE != SECTOR_SIZE -#error FS_BLOCK_SIZE != SECTOR_SIZE - This code needs to be fixed! -#endif - -#define MAX_CLUSTSIZE 65536 -#define DIRENTSPERBLOCK (FS_BLOCK_SIZE/sizeof(dir_entry)) -#define DIRENTSPERCLUST ((mydata->clust_size*SECTOR_SIZE)/sizeof(dir_entry)) - -#define FATBUFBLOCKS 6 -#define FATBUFSIZE (FS_BLOCK_SIZE*FATBUFBLOCKS) -#define FAT12BUFSIZE ((FATBUFSIZE*2)/3) -#define FAT16BUFSIZE (FATBUFSIZE/2) -#define FAT32BUFSIZE (FATBUFSIZE/4) - - -/* Filesystem identifiers */ -#define FAT12_SIGN "FAT12 " -#define FAT16_SIGN "FAT16 " -#define FAT32_SIGN "FAT32 " -#define SIGNLEN 8 - -/* File attributes */ -#define ATTR_RO 1 -#define ATTR_HIDDEN 2 -#define ATTR_SYS 4 -#define ATTR_VOLUME 8 -#define ATTR_DIR 16 -#define ATTR_ARCH 32 - -#define ATTR_VFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) - -#define DELETED_FLAG ((char)0xe5) /* Marks deleted files when in name[0] */ -#define aRING 0x05 /* Used to represent '' in name[0] */ - -/* Indicates that the entry is the last long entry in a set of long - * dir entries - */ -#define LAST_LONG_ENTRY_MASK 0x40 - -/* Flags telling whether we should read a file or list a directory */ -#define LS_NO 0 -#define LS_YES 1 -#define LS_DIR 1 -#define LS_ROOT 2 - -#undef DEBUG -#ifdef DEBUG -#define FAT_DPRINT(args...) printf(args) -#else -#define FAT_DPRINT(args...) -#endif -#define FAT_ERROR(arg) printf(arg) - -#define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') - -#define FSTYPE_NONE (-1) - -#if defined(__linux__) && defined(__KERNEL__) -#define FAT2CPU16 le16_to_cpu -#define FAT2CPU32 le32_to_cpu -#else -#if __LITTLE_ENDIAN -#define FAT2CPU16(x) (x) -#define FAT2CPU32(x) (x) -#else -#define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) -#define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ - (((x) & 0x0000ff00) << 8) | \ - (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0xff000000) >> 24)) -#endif -#endif - -#define TOLOWER(c) if((c) >= 'A' && (c) <= 'Z'){(c)+=('a' - 'A');} -#define START(dent) (FAT2CPU16((dent)->start) \ - + (mydata->fatsize != 32 ? 0 : \ - (FAT2CPU16((dent)->starthi) << 16))) - - -typedef struct boot_sector { - __u8 ignored[3]; /* Bootstrap code */ - char system_id[8]; /* Name of fs */ - __u8 sector_size[2]; /* Bytes/sector */ - __u8 cluster_size; /* Sectors/cluster */ - __u16 reserved; /* Number of reserved sectors */ - __u8 fats; /* Number of FATs */ - __u8 dir_entries[2]; /* Number of root directory entries */ - __u8 sectors[2]; /* Number of sectors */ - __u8 media; /* Media code */ - __u16 fat_length; /* Sectors/FAT */ - __u16 secs_track; /* Sectors/track */ - __u16 heads; /* Number of heads */ - __u32 hidden; /* Number of hidden sectors */ - __u32 total_sect; /* Number of sectors (if sectors == 0) */ - - /* FAT32 only */ - __u32 fat32_length; /* Sectors/FAT */ - __u16 flags; /* Bit 8: fat mirroring, low 4: active fat */ - __u8 version[2]; /* Filesystem version */ - __u32 root_cluster; /* First cluster in root directory */ - __u16 info_sector; /* Filesystem info sector */ - __u16 backup_boot; /* Backup boot sector */ - __u16 reserved2[6]; /* Unused */ -} boot_sector; - -typedef struct volume_info -{ - __u8 drive_number; /* BIOS drive number */ - __u8 reserved; /* Unused */ - __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ - __u8 volume_id[4]; /* Volume ID number */ - char volume_label[11]; /* Volume label */ - char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */ - /* Boot code comes next, all but 2 bytes to fill up sector */ - /* Boot sign comes last, 2 bytes */ -} volume_info; - -typedef struct dir_entry { - char name[8],ext[3]; /* Name and extension */ - __u8 attr; /* Attribute bits */ - __u8 lcase; /* Case for base and extension */ - __u8 ctime_ms; /* Creation time, milliseconds */ - __u16 ctime; /* Creation time */ - __u16 cdate; /* Creation date */ - __u16 adate; /* Last access date */ - __u16 starthi; /* High 16 bits of cluster in FAT32 */ - __u16 time,date,start;/* Time, date and first cluster */ - __u32 size; /* File size in bytes */ -} dir_entry; - -typedef struct dir_slot { - __u8 id; /* Sequence number for slot */ - __u8 name0_4[10]; /* First 5 characters in name */ - __u8 attr; /* Attribute byte */ - __u8 reserved; /* Unused */ - __u8 alias_checksum;/* Checksum for 8.3 alias */ - __u8 name5_10[12]; /* 6 more characters in name */ - __u16 start; /* Unused */ - __u8 name11_12[4]; /* Last 2 characters in name */ -} dir_slot; - -/* Private filesystem parameters */ -typedef struct { - int fatsize; /* Size of FAT in bits */ - __u16 fatlength; /* Length of FAT in sectors */ - __u16 fat_sect; /* Starting sector of the FAT */ - __u16 rootdir_sect; /* Start sector of root directory */ - __u16 clust_size; /* Size of clusters in sectors */ - short data_begin; /* The sector of the first cluster, can be negative */ - __u8 fatbuf[FATBUFSIZE]; /* Current FAT buffer */ - int fatbufnum; /* Used by get_fatent, init to -1 */ -} fsdata; - -typedef int (file_detectfs_func)(void); -typedef int (file_ls_func)(const char *dir); -typedef long (file_read_func)(const char *filename, void *buffer, - unsigned long maxsize); - -struct filesystem { - file_detectfs_func *detect; - file_ls_func *ls; - file_read_func *read; - const char name[12]; -}; - -/* FAT tables */ -file_detectfs_func file_fat_detectfs; -file_ls_func file_fat_ls; -file_read_func file_fat_read; - -/* Currently this doesn't check if the dir exists or is valid... */ -int file_cd(const char *path); -int file_fat_detectfs(void); -int file_fat_ls(const char *dir); -long file_fat_read(const char *filename, void *buffer, unsigned long maxsize); -const char *file_getfsname(int idx); -int fat_register_device(block_dev_desc_t *dev_desc, int part_no); - -#endif /* _FAT_H_ */ +/* + * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg + * + * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 + * 2003-03-10 - kharris@nexus-tech.net - ported to u-boot + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _FAT_H_ +#define _FAT_H_ + +#include + +#define CONFIG_SUPPORT_VFAT + +#define SECTOR_SIZE FS_BLOCK_SIZE + +#define FS_BLOCK_SIZE 512 + +#if FS_BLOCK_SIZE != SECTOR_SIZE +#error FS_BLOCK_SIZE != SECTOR_SIZE - This code needs to be fixed! +#endif + +#define MAX_CLUSTSIZE 65536 +#define DIRENTSPERBLOCK (FS_BLOCK_SIZE/sizeof(dir_entry)) +#define DIRENTSPERCLUST ((mydata->clust_size*SECTOR_SIZE)/sizeof(dir_entry)) + +#define FATBUFBLOCKS 6 +#define FATBUFSIZE (FS_BLOCK_SIZE*FATBUFBLOCKS) +#define FAT12BUFSIZE ((FATBUFSIZE*2)/3) +#define FAT16BUFSIZE (FATBUFSIZE/2) +#define FAT32BUFSIZE (FATBUFSIZE/4) + + +/* Filesystem identifiers */ +#define FAT12_SIGN "FAT12 " +#define FAT16_SIGN "FAT16 " +#define FAT32_SIGN "FAT32 " +#define SIGNLEN 8 + +/* File attributes */ +#define ATTR_RO 1 +#define ATTR_HIDDEN 2 +#define ATTR_SYS 4 +#define ATTR_VOLUME 8 +#define ATTR_DIR 16 +#define ATTR_ARCH 32 + +#define ATTR_VFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) + +#define DELETED_FLAG ((char)0xe5) /* Marks deleted files when in name[0] */ +#define aRING 0x05 /* Used to represent '' in name[0] */ + +/* Indicates that the entry is the last long entry in a set of long + * dir entries + */ +#define LAST_LONG_ENTRY_MASK 0x40 + +/* Flags telling whether we should read a file or list a directory */ +#define LS_NO 0 +#define LS_YES 1 +#define LS_DIR 1 +#define LS_ROOT 2 + +#undef DEBUG +#ifdef DEBUG +#define FAT_DPRINT(args...) printf(args) +#else +#define FAT_DPRINT(args...) +#endif +#define FAT_ERROR(arg...) printf(arg) + +#define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') + +#define FSTYPE_NONE (-1) + +#if defined(__linux__) && defined(__KERNEL__) +#define FAT2CPU16 le16_to_cpu +#define FAT2CPU32 le32_to_cpu +#else +#if __LITTLE_ENDIAN +#define FAT2CPU16(x) (x) +#define FAT2CPU32(x) (x) +#else +#define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) +#define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) +#endif +#endif + +#define TOLOWER(c) if((c) >= 'A' && (c) <= 'Z'){(c)+=('a' - 'A');} +#define START(dent) (FAT2CPU16((dent)->start) \ + + (mydata->fatsize != 32 ? 0 : \ + (FAT2CPU16((dent)->starthi) << 16))) + +#define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ + (x) >= ((fatsize) != 32 ? 0xfff0 : 0xffffff0)) + +typedef struct boot_sector { + __u8 ignored[3]; /* Bootstrap code */ + char system_id[8]; /* Name of fs */ + __u8 sector_size[2]; /* Bytes/sector */ + __u8 cluster_size; /* Sectors/cluster */ + __u16 reserved; /* Number of reserved sectors */ + __u8 fats; /* Number of FATs */ + __u8 dir_entries[2]; /* Number of root directory entries */ + __u8 sectors[2]; /* Number of sectors */ + __u8 media; /* Media code */ + __u16 fat_length; /* Sectors/FAT */ + __u16 secs_track; /* Sectors/track */ + __u16 heads; /* Number of heads */ + __u32 hidden; /* Number of hidden sectors */ + __u32 total_sect; /* Number of sectors (if sectors == 0) */ + + /* FAT32 only */ + __u32 fat32_length; /* Sectors/FAT */ + __u16 flags; /* Bit 8: fat mirroring, low 4: active fat */ + __u8 version[2]; /* Filesystem version */ + __u32 root_cluster; /* First cluster in root directory */ + __u16 info_sector; /* Filesystem info sector */ + __u16 backup_boot; /* Backup boot sector */ + __u16 reserved2[6]; /* Unused */ +} boot_sector; + +typedef struct volume_info +{ + __u8 drive_number; /* BIOS drive number */ + __u8 reserved; /* Unused */ + __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ + __u8 volume_id[4]; /* Volume ID number */ + char volume_label[11]; /* Volume label */ + char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */ + /* Boot code comes next, all but 2 bytes to fill up sector */ + /* Boot sign comes last, 2 bytes */ +} volume_info; + +typedef struct dir_entry { + char name[8],ext[3]; /* Name and extension */ + __u8 attr; /* Attribute bits */ + __u8 lcase; /* Case for base and extension */ + __u8 ctime_ms; /* Creation time, milliseconds */ + __u16 ctime; /* Creation time */ + __u16 cdate; /* Creation date */ + __u16 adate; /* Last access date */ + __u16 starthi; /* High 16 bits of cluster in FAT32 */ + __u16 time,date,start;/* Time, date and first cluster */ + __u32 size; /* File size in bytes */ +} dir_entry; + +typedef struct dir_slot { + __u8 id; /* Sequence number for slot */ + __u8 name0_4[10]; /* First 5 characters in name */ + __u8 attr; /* Attribute byte */ + __u8 reserved; /* Unused */ + __u8 alias_checksum;/* Checksum for 8.3 alias */ + __u8 name5_10[12]; /* 6 more characters in name */ + __u16 start; /* Unused */ + __u8 name11_12[4]; /* Last 2 characters in name */ +} dir_slot; + +/* Private filesystem parameters */ +typedef struct { + __u8 fatbuf[FATBUFSIZE]; /* Current FAT buffer */ + int fatsize; /* Size of FAT in bits */ + __u16 fatlength; /* Length of FAT in sectors */ + __u16 fat_sect; /* Starting sector of the FAT */ + __u16 rootdir_sect; /* Start sector of root directory */ + __u16 clust_size; /* Size of clusters in sectors */ + short data_begin; /* The sector of the first cluster, can be negative */ + int fatbufnum; /* Used by get_fatent, init to -1 */ +} fsdata; + +typedef int (file_detectfs_func)(void); +typedef int (file_ls_func)(const char *dir); +typedef long (file_read_func)(const char *filename, void *buffer, + unsigned long maxsize); + +struct filesystem { + file_detectfs_func *detect; + file_ls_func *ls; + file_read_func *read; + const char name[12]; +}; + +/* FAT tables */ +file_detectfs_func file_fat_detectfs; +file_ls_func file_fat_ls; +file_read_func file_fat_read; + +/* Currently this doesn't check if the dir exists or is valid... */ +int file_cd(const char *path); +int file_fat_detectfs(void); +int file_fat_ls(const char *dir); +long file_fat_read(const char *filename, void *buffer, unsigned long maxsize); +const char *file_getfsname(int idx); +int fat_register_device(block_dev_desc_t *dev_desc, int part_no); + +#endif /* _FAT_H_ */ diff -uNr u-boot-3.4.16.orig/Makefile u-boot-3.4.16/Makefile --- u-boot-3.4.16.orig/Makefile 2009-01-21 09:44:34.000000000 +0900 +++ u-boot-3.4.16/Makefile 2009-08-21 19:13:51.000000000 +0900 @@ -1532,6 +1532,7 @@ echo "MV_IMAGE_FLAGS = -DMV_SEC_256K" >> include/config.mk; \ echo "MV_IMAGE_FLAGS += -DMV_BOOTSIZE_16M" >> include/config.mk; \ echo "MV_IMAGE_FLAGS += -DMV_LARGE_PAGE" >> include/config.mk; \ + echo “MV_IMAGE_FLAGS += -DMV_MMC” >> include/config.mk; \ echo "MV_FLAGS += -DMV_BOOTROM" >> include/config.mk; \ echo "MV_DDR_FREQ = 400db" >> include/config.mk; \ cp board/mv_feroceon/config_kw/u-boot-sec256k.lds board/mv_feroceon/config_kw/u-boot.lds; \