*
* This code is GPL
*
- * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $
*/
-#include <linux/module.h>
-#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/concat.h>
*/
#define CONCAT(x) ((struct mtd_concat *)(x))
-/*
+/*
* MTD methods which look up the relevant subdevice, translate the
* effective address and pass through to the subdevice.
*/
struct mtd_concat *concat = CONCAT(mtd);
struct mtd_info *subdev;
int i, err;
- u_int32_t length;
+ u_int32_t length, offset = 0;
struct erase_info *erase;
if (!(mtd->flags & MTD_WRITEABLE))
return -EINVAL;
}
+ instr->fail_addr = 0xffffffff;
+
/* make a local copy of instr to avoid modifying the caller's struct */
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
*/
for (i = 0; i < concat->num_subdev; i++) {
subdev = concat->subdev[i];
- if (subdev->size <= erase->addr)
+ if (subdev->size <= erase->addr) {
erase->addr -= subdev->size;
- else
+ offset += subdev->size;
+ } else {
break;
+ }
}
/* must never happen since size limit has been verified above */
- if (i >= concat->num_subdev)
- BUG();
+ BUG_ON(i >= concat->num_subdev);
/* now do the erase: */
err = 0;
if ((err = concat_dev_erase(subdev, erase))) {
/* sanity check: should never happen since
* block alignment has been checked above */
- if (err == -EINVAL)
- BUG();
+ BUG_ON(err == -EINVAL);
+ if (erase->fail_addr != 0xffffffff)
+ instr->fail_addr = erase->fail_addr + offset;
break;
}
/*
* current subdevice, i.e. at offset zero.
*/
erase->addr = 0;
+ offset += subdev->size;
}
+ instr->state = erase->state;
kfree(erase);
if (err)
return err;
- instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
return 0;
return &concat->mtd;
}
-/*
+/*
* This function destroys an MTD object obtained from concat_mtd_devs()
*/