]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mtd/mtdconcat.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / mtd / mtdconcat.c
index 3dbb1b38db666cf4294047ec8cac5f8610c19525..792b547786b8fdf6c4122f28240b1458c0d80f66 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/types.h>
+#include <linux/backing-dev.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/concat.h>
@@ -683,6 +684,40 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return err;
 }
 
+/*
+ * try to support NOMMU mmaps on concatenated devices
+ * - we don't support subdev spanning as we can't guarantee it'll work
+ */
+static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
+                                             unsigned long len,
+                                             unsigned long offset,
+                                             unsigned long flags)
+{
+       struct mtd_concat *concat = CONCAT(mtd);
+       int i;
+
+       for (i = 0; i < concat->num_subdev; i++) {
+               struct mtd_info *subdev = concat->subdev[i];
+
+               if (offset >= subdev->size) {
+                       offset -= subdev->size;
+                       continue;
+               }
+
+               /* we've found the subdev over which the mapping will reside */
+               if (offset + len > subdev->size)
+                       return (unsigned long) -EINVAL;
+
+               if (subdev->get_unmapped_area)
+                       return subdev->get_unmapped_area(subdev, len, offset,
+                                                        flags);
+
+               break;
+       }
+
+       return (unsigned long) -ENOSYS;
+}
+
 /*
  * This function constructs a virtual MTD device by concatenating
  * num_devs MTD devices. A pointer to the new device object is
@@ -740,6 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
 
        concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
 
+       concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
+
        concat->subdev[0] = subdev[0];
 
        for (i = 1; i < num_devs; i++) {
@@ -766,6 +803,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],      /* subdevices to c
                                concat->mtd.flags |=
                                    subdev[i]->flags & MTD_WRITEABLE;
                }
+
+               /* only permit direct mapping if the BDIs are all the same
+                * - copy-mapping is still permitted
+                */
+               if (concat->mtd.backing_dev_info !=
+                   subdev[i]->backing_dev_info)
+                       concat->mtd.backing_dev_info =
+                               &default_backing_dev_info;
+
                concat->mtd.size += subdev[i]->size;
                concat->mtd.ecc_stats.badblocks +=
                        subdev[i]->ecc_stats.badblocks;
@@ -796,6 +842,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        concat->mtd.unlock = concat_unlock;
        concat->mtd.suspend = concat_suspend;
        concat->mtd.resume = concat_resume;
+       concat->mtd.get_unmapped_area = concat_get_unmapped_area;
 
        /*
         * Combine the erase block size info of the subdevices: