#include #include #include #include #include struct mtd_part { struct mtd_info mtd; struct mtd_info *master; uint64_t offset; struct list_head list; }; #define PART(x) ((struct mtd_part *)(x)) static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); struct mtd_ecc_stats stats; int res; stats = part->master->ecc_stats; if (from >= mtd->size) len = 0; else if (from + len > mtd->size) len = mtd->size - from; res = part->master->read(part->master, from + part->offset, len, retlen, buf); return res; } static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (to >= mtd->size) len = 0; else if (to + len > mtd->size) len = mtd->size - to; return part->master->write(part->master, to + part->offset, len, retlen, buf); } static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mtd_part *part = PART(mtd); int ret; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (instr->addr >= mtd->size) return -EINVAL; instr->addr += part->offset; ret = part->master->erase(part->master, instr); if (ret) { if (instr->fail_addr != 0xffffffff) instr->fail_addr -= part->offset; instr->addr -= part->offset; } return ret; } static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); if (ofs >= mtd->size) return -EINVAL; ofs += part->offset; return part->master->block_isbad(part->master, ofs); } static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); int res; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (ofs >= mtd->size) return -EINVAL; ofs += part->offset; res = part->master->block_markbad(part->master, ofs); if (!res) mtd->ecc_stats.badblocks++; return res; } struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, unsigned long flags, const char *name) { struct mtd_part *slave; struct mtd_info *slave_mtd; int start = 0, end = 0, i; slave = xzalloc(sizeof(*slave)); slave_mtd = &slave->mtd; memcpy(slave_mtd, mtd, sizeof(*slave)); /* * find the number of eraseregions the partition includes. * Do not bother to create the mtd_erase_region_infos as * ubi is only interested in its number. UBI does not * yet support multiple erase regions. */ for (i = mtd->numeraseregions - 1; i >= 0; i--) { struct mtd_erase_region_info *region = &mtd->eraseregions[i]; if (offset >= region->offset && offset < region->offset + region->erasesize * region->numblocks) start = i; if (offset + size >= region->offset && offset + size <= region->offset + region->erasesize * region->numblocks) end = i; } slave_mtd->numeraseregions = end - start; slave_mtd->read = mtd_part_read; slave_mtd->write = mtd_part_write; slave_mtd->erase = mtd_part_erase; slave_mtd->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; slave_mtd->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; slave_mtd->size = size; slave_mtd->name = strdup(name); slave->offset = offset; slave->master = mtd; return slave_mtd; } void mtd_del_partition(struct mtd_info *mtd) { struct mtd_part *part = PART(mtd); free(mtd->name); free(part); }