Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / mtd / redboot.c
index 0212a7d..c077d2e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $
+ * $Id: redboot.c,v 1.19 2005/12/01 10:03:51 dwmw2 Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -30,13 +30,16 @@ struct fis_list {
        struct fis_list *next;
 };
 
+static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
+module_param(directory, int, 0);
+
 static inline int redboot_checksum(struct fis_image_desc *img)
 {
        /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
        return 1;
 }
 
-static int parse_redboot_partitions(struct mtd_info *master, 
+static int parse_redboot_partitions(struct mtd_info *master,
                              struct mtd_partition **pparts,
                              unsigned long fis_origin)
 {
@@ -50,6 +53,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
        char *nullname;
        int namelen = 0;
        int nulllen = 0;
+       int numslots;
+       unsigned long offset;
 #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
        static char nullstring[] = "unallocated";
 #endif
@@ -59,8 +64,15 @@ static int parse_redboot_partitions(struct mtd_info *master,
        if (!buf)
                return -ENOMEM;
 
-       /* Read the start of the last erase block */
-       ret = master->read(master, master->size - master->erasesize,
+       if ( directory < 0 )
+               offset = master->size + directory*master->erasesize;
+       else
+               offset = directory*master->erasesize;
+
+       printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+              master->name, offset);
+
+       ret = master->read(master, offset,
                           master->erasesize, &retlen, (void *)buf);
 
        if (ret)
@@ -71,12 +83,36 @@ static int parse_redboot_partitions(struct mtd_info *master,
                goto out;
        }
 
-       /* RedBoot image could appear in any of the first three slots */
-       for (i = 0; i < 3; i++) {
-               if (!memcmp(buf[i].name, "RedBoot", 8))
+       numslots = (master->erasesize / sizeof(struct fis_image_desc));
+       for (i = 0; i < numslots; i++) {
+               if (!memcmp(buf[i].name, "FIS directory", 14)) {
+                       /* This is apparently the FIS directory entry for the
+                        * FIS directory itself.  The FIS directory size is
+                        * one erase block; if the buf[i].size field is
+                        * swab32(erasesize) then we know we are looking at
+                        * a byte swapped FIS directory - swap all the entries!
+                        * (NOTE: this is 'size' not 'data_length'; size is
+                        * the full size of the entry.)
+                        */
+                       if (swab32(buf[i].size) == master->erasesize) {
+                               int j;
+                               for (j = 0; j < numslots && buf[j].name[0] != 0xff; ++j) {
+                                       /* The unsigned long fields were written with the
+                                        * wrong byte sex, name and pad have no byte sex.
+                                        */
+                                       swab32s(&buf[j].flash_base);
+                                       swab32s(&buf[j].mem_base);
+                                       swab32s(&buf[j].size);
+                                       swab32s(&buf[j].entry_point);
+                                       swab32s(&buf[j].data_length);
+                                       swab32s(&buf[j].desc_cksum);
+                                       swab32s(&buf[j].file_cksum);
+                               }
+                       }
                        break;
+               }
        }
-       if (i == 3) {
+       if (i == numslots) {
                /* Didn't find it */
                printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
                       master->name);
@@ -84,11 +120,11 @@ static int parse_redboot_partitions(struct mtd_info *master,
                goto out;
        }
 
-       for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
+       for (i = 0; i < numslots; i++) {
                struct fis_list *new_fl, **prev;
 
                if (buf[i].name[0] == 0xff)
-                       break;
+                       continue;
                if (!redboot_checksum(&buf[i]))
                        break;