]> git.sur5r.net Git - u-boot/blobdiff - fs/fat/fat.c
dm: scsi: Rename CONFIG_CMD_SCSI to CONFIG_SCSI
[u-boot] / fs / fat / fat.c
index 04a51db6d4cd9e278cdf09959af2f86408864278..826bd852860aed9a078a75ad618f5d204cdef9f1 100644 (file)
  */
 
 #include <common.h>
+#include <blk.h>
 #include <config.h>
 #include <exports.h>
 #include <fat.h>
 #include <asm/byteorder.h>
 #include <part.h>
 #include <malloc.h>
+#include <memalign.h>
 #include <linux/compiler.h>
 #include <linux/ctype.h>
 
@@ -36,7 +38,7 @@ static void downcase(char *str)
        }
 }
 
-static block_dev_desc_t *cur_dev;
+static struct blk_desc *cur_dev;
 static disk_partition_t cur_part_info;
 
 #define DOS_BOOT_MAGIC_OFFSET  0x1fe
@@ -45,14 +47,20 @@ static disk_partition_t cur_part_info;
 
 static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
 {
-       if (!cur_dev || !cur_dev->block_read)
+       ulong ret;
+
+       if (!cur_dev)
                return -1;
 
-       return cur_dev->block_read(cur_dev->dev,
-                       cur_part_info.start + block, nr_blocks, buf);
+       ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf);
+
+       if (nr_blocks && ret == 0)
+               return -1;
+
+       return ret;
 }
 
-int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info)
+int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
 {
        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
 
@@ -81,7 +89,7 @@ int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info)
        return -1;
 }
 
-int fat_register_device(block_dev_desc_t *dev_desc, int part_no)
+int fat_register_device(struct blk_desc *dev_desc, int part_no)
 {
        disk_partition_t info;
 
@@ -89,10 +97,10 @@ int fat_register_device(block_dev_desc_t *dev_desc, int part_no)
        cur_dev = NULL;
 
        /* Read the partition table, if present */
-       if (get_partition_info(dev_desc, part_no, &info)) {
+       if (part_get_info(dev_desc, part_no, &info)) {
                if (part_no != 0) {
                        printf("** Partition %d not valid on device %d **\n",
-                                       part_no, dev_desc->dev);
+                                       part_no, dev_desc->devnum);
                        return -1;
                }
 
@@ -823,8 +831,11 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
        int ret = -1;
        int firsttime;
        __u32 root_cluster = 0;
+       __u32 read_blk;
        int rootdir_size = 0;
-       int j;
+       int buffer_blk_cnt;
+       int do_read;
+       __u8 *dir_ptr;
 
        if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
                debug("Error: reading boot sector\n");
@@ -892,6 +903,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
        strcpy(fnamecopy, filename);
        downcase(fnamecopy);
 
+root_reparse:
        if (*fnamecopy == '\0') {
                if (!dols)
                        goto exit;
@@ -909,24 +921,54 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
                isdir = 1;
        }
 
-       j = 0;
+       buffer_blk_cnt = 0;
+       firsttime = 1;
        while (1) {
                int i;
 
-               if (j == 0) {
-                       debug("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%zd\n",
-                               cursect, mydata->clust_size, DIRENTSPERBLOCK);
+               if (mydata->fatsize == 32 || firsttime) {
+                       dir_ptr = do_fat_read_at_block;
+                       firsttime = 0;
+               } else {
+                       /**
+                        * FAT16 sector buffer modification:
+                        * Each loop, the second buffered block is moved to
+                        * the buffer begin, and two next sectors are read
+                        * next to the previously moved one. So the sector
+                        * buffer keeps always 3 sectors for fat16.
+                        * And the current sector is the buffer second sector
+                        * beside the "firsttime" read, when it is the first one.
+                        *
+                        * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1]
+                        * n = computed root dir sector
+                        * loop |  cursect-1  | cursect    | cursect+1  |
+                        *   0  |  sector n+0 | sector n+1 | none       |
+                        *   1  |  none       | sector n+0 | sector n+1 |
+                        *   0  |  sector n+1 | sector n+2 | sector n+3 |
+                        *   1  |  sector n+3 | ...
+                       */
+                       dir_ptr = (do_fat_read_at_block + mydata->sect_size);
+                       memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size);
+               }
 
-                       if (disk_read(cursect,
-                                       (mydata->fatsize == 32) ?
-                                       (mydata->clust_size) :
-                                       PREFETCH_BLOCKS,
-                                       do_fat_read_at_block) < 0) {
+               do_read = 1;
+
+               if (mydata->fatsize == 32 && buffer_blk_cnt)
+                       do_read = 0;
+
+               if (do_read) {
+                       read_blk = (mydata->fatsize == 32) ?
+                                   mydata->clust_size : PREFETCH_BLOCKS;
+
+                       debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
+                               cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK);
+
+                       if (disk_read(cursect, read_blk, dir_ptr) < 0) {
                                debug("Error: reading rootdir block\n");
                                goto exit;
                        }
 
-                       dentptr = (dir_entry *) do_fat_read_at_block;
+                       dentptr = (dir_entry *)dir_ptr;
                }
 
                for (i = 0; i < DIRENTSPERBLOCK; i++) {
@@ -951,7 +993,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
 
                                        get_vfatname(mydata,
                                                     root_cluster,
-                                                    do_fat_read_at_block,
+                                                    dir_ptr,
                                                     dentptr, l_name);
 
                                        if (dols == LS_ROOT) {
@@ -1062,7 +1104,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
 
                        goto rootdir_done;      /* We got a match */
                }
-               debug("END LOOP: j=%d   clust_size=%d\n", j,
+               debug("END LOOP: buffer_blk_cnt=%d   clust_size=%d\n", buffer_blk_cnt,
                       mydata->clust_size);
 
                /*
@@ -1070,10 +1112,10 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
                 * root directory clusters when a cluster has been
                 * completely processed.
                 */
-               ++j;
+               ++buffer_blk_cnt;
                int rootdir_end = 0;
                if (mydata->fatsize == 32) {
-                       if (j == mydata->clust_size) {
+                       if (buffer_blk_cnt == mydata->clust_size) {
                                int nxtsect = 0;
                                int nxt_clust = 0;
 
@@ -1086,11 +1128,11 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
                                root_cluster = nxt_clust;
 
                                cursect = nxtsect;
-                               j = 0;
+                               buffer_blk_cnt = 0;
                        }
                } else {
-                       if (j == PREFETCH_BLOCKS)
-                               j = 0;
+                       if (buffer_blk_cnt == PREFETCH_BLOCKS)
+                               buffer_blk_cnt = 0;
 
                        rootdir_end = (++cursect - mydata->rootdir_sect >=
                                       rootdir_size);
@@ -1147,6 +1189,34 @@ rootdir_done:
                if (isdir && !(dentptr->attr & ATTR_DIR))
                        goto exit;
 
+               /*
+                * If we are looking for a directory, and found a directory
+                * type entry, and the entry is for the root directory (as
+                * denoted by a cluster number of 0), jump back to the start
+                * of the function, since at least on FAT12/16, the root dir
+                * lives in a hard-coded location and needs special handling
+                * to parse, rather than simply following the cluster linked
+                * list in the FAT, like other directories.
+                */
+               if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) {
+                       /*
+                        * Modify the filename to remove the prefix that gets
+                        * back to the root directory, so the initial root dir
+                        * parsing code can continue from where we are without
+                        * confusion.
+                        */
+                       strcpy(fnamecopy, nextname ?: "");
+                       /*
+                        * Set up state the same way as the function does when
+                        * first started. This is required for the root dir
+                        * parsing code operates in its expected environment.
+                        */
+                       subname = "";
+                       cursect = mydata->rootdir_sect;
+                       isdir = 0;
+                       goto root_reparse;
+               }
+
                if (idx >= 0)
                        subname = nextname;
        }
@@ -1184,7 +1254,7 @@ int file_fat_detectfs(void)
 
 #if defined(CONFIG_CMD_IDE) || \
     defined(CONFIG_CMD_SATA) || \
-    defined(CONFIG_CMD_SCSI) || \
+    defined(CONFIG_SCSI) || \
     defined(CONFIG_CMD_USB) || \
     defined(CONFIG_MMC)
        printf("Interface:  ");
@@ -1214,7 +1284,7 @@ int file_fat_detectfs(void)
                printf("Unknown");
        }
 
-       printf("\n  Device %d: ", cur_dev->dev);
+       printf("\n  Device %d: ", cur_dev->devnum);
        dev_print(cur_dev);
 #endif