📄 mtdpart.c
字号:
/* * Simple MTD partitioning layer * * (C) 2000 Nicolas Pitre <nico@cam.org> * * This code is GPL * * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> * added support for read_oob, write_oob */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/kmod.h>#include <linux/mtd/mtd.h>#include <linux/mtd/partitions.h>#include <linux/mtd/compatmac.h>/* Our partition linked list */static LIST_HEAD(mtd_partitions);/* Our partition node structure */struct mtd_part { struct mtd_info mtd; struct mtd_info *master; u_int32_t offset; int index; struct list_head list; int registered;};/* * Given a pointer to the MTD object in the mtd_part structure, we can retrieve * the pointer to that structure with this macro. */#define PART(x) ((struct mtd_part *)(x))/* * MTD methods which simply translate the effective address and pass through * to the _real_ device. */static int part_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct mtd_part *part = PART(mtd); int res; 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); if (unlikely(res)) { if (res == -EUCLEAN) mtd->ecc_stats.corrected++; if (res == -EBADMSG) mtd->ecc_stats.failed++; } return res;}static int part_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys){ struct mtd_part *part = PART(mtd); if (from >= mtd->size) len = 0; else if (from + len > mtd->size) len = mtd->size - from; return part->master->point (part->master, from + part->offset, len, retlen, virt, phys);}static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len){ struct mtd_part *part = PART(mtd); part->master->unpoint(part->master, from + part->offset, len);}static int part_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops){ struct mtd_part *part = PART(mtd); int res; if (from >= mtd->size) return -EINVAL; if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; res = part->master->read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { if (res == -EUCLEAN) mtd->ecc_stats.corrected++; if (res == -EBADMSG) mtd->ecc_stats.failed++; } return res;}static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct mtd_part *part = PART(mtd); return part->master->read_user_prot_reg(part->master, from, len, retlen, buf);}static int part_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, size_t len){ struct mtd_part *part = PART(mtd); return part->master->get_user_prot_info(part->master, buf, len);}static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct mtd_part *part = PART(mtd); return part->master->read_fact_prot_reg(part->master, from, len, retlen, buf);}static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, size_t len){ struct mtd_part *part = PART(mtd); return part->master->get_fact_prot_info(part->master, buf, len);}static int 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 part_panic_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->panic_write(part->master, to + part->offset, len, retlen, buf);}static int part_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops){ struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (to >= mtd->size) return -EINVAL; if (ops->datbuf && to + ops->len > mtd->size) return -EINVAL; return part->master->write_oob(part->master, to + part->offset, ops);}static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct mtd_part *part = PART(mtd); return part->master->write_user_prot_reg(part->master, from, len, retlen, buf);}static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len){ struct mtd_part *part = PART(mtd); return part->master->lock_user_prot_reg(part->master, from, len);}static int part_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen){ struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; return part->master->writev(part->master, vecs, count, to + part->offset, retlen);}static int 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 != MTD_FAIL_ADDR_UNKNOWN) instr->fail_addr -= part->offset; instr->addr -= part->offset; } return ret;}void mtd_erase_callback(struct erase_info *instr){ if (instr->mtd->erase == part_erase) { struct mtd_part *part = PART(instr->mtd); if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) instr->fail_addr -= part->offset; instr->addr -= part->offset; } if (instr->callback) instr->callback(instr);}EXPORT_SYMBOL_GPL(mtd_erase_callback);static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len){ struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) return -EINVAL; return part->master->lock(part->master, ofs + part->offset, len);}static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){ struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) return -EINVAL; return part->master->unlock(part->master, ofs + part->offset, len);}static void part_sync(struct mtd_info *mtd){ struct mtd_part *part = PART(mtd); part->master->sync(part->master);}static int part_suspend(struct mtd_info *mtd){ struct mtd_part *part = PART(mtd); return part->master->suspend(part->master);}static void part_resume(struct mtd_info *mtd){ struct mtd_part *part = PART(mtd); part->master->resume(part->master);}static int 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 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -