mtdpart.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Simple MTD partitioning layer
  3.  *
  4.  * (C) 2000 Nicolas Pitre <nico@cam.org>
  5.  *
  6.  * This code is GPL
  7.  *
  8.  * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $
  9.  *
  10.  *  02-21-2002 Thomas Gleixner <gleixner@autronix.de>
  11.  * added support for read_oob, write_oob
  12.  */
  13. #include <linux/module.h>
  14. #include <linux/types.h>
  15. #include <linux/kernel.h>
  16. #include <linux/slab.h>
  17. #include <linux/list.h>
  18. #include <linux/mtd/mtd.h>
  19. #include <linux/mtd/partitions.h>
  20. /* Our partition linked list */
  21. static LIST_HEAD(mtd_partitions);
  22. /* Our partition node structure */
  23. struct mtd_part {
  24. struct mtd_info mtd;
  25. struct mtd_info *master;
  26. u_int32_t offset;
  27. int index;
  28. struct list_head list;
  29. int registered;
  30. };
  31. /*
  32.  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
  33.  * the pointer to that structure with this macro.
  34.  */
  35. #define PART(x)  ((struct mtd_part *)(x))
  36. /* 
  37.  * MTD methods which simply translate the effective address and pass through
  38.  * to the _real_ device.
  39.  */
  40. static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
  41. size_t *retlen, u_char *buf)
  42. {
  43. struct mtd_part *part = PART(mtd);
  44. if (from >= mtd->size)
  45. len = 0;
  46. else if (from + len > mtd->size)
  47. len = mtd->size - from;
  48. return part->master->read (part->master, from + part->offset, 
  49. len, retlen, buf);
  50. }
  51. static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
  52. size_t *retlen, u_char *buf)
  53. {
  54. struct mtd_part *part = PART(mtd);
  55. if (from >= mtd->size)
  56. len = 0;
  57. else if (from + len > mtd->size)
  58. len = mtd->size - from;
  59. return part->master->read_oob (part->master, from + part->offset, 
  60. len, retlen, buf);
  61. }
  62. static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
  63. size_t *retlen, const u_char *buf)
  64. {
  65. struct mtd_part *part = PART(mtd);
  66. if (!(mtd->flags & MTD_WRITEABLE))
  67. return -EROFS;
  68. if (to >= mtd->size)
  69. len = 0;
  70. else if (to + len > mtd->size)
  71. len = mtd->size - to;
  72. return part->master->write (part->master, to + part->offset, 
  73. len, retlen, buf);
  74. }
  75. static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
  76. size_t *retlen, const u_char *buf)
  77. {
  78. struct mtd_part *part = PART(mtd);
  79. if (!(mtd->flags & MTD_WRITEABLE))
  80. return -EROFS;
  81. if (to >= mtd->size)
  82. len = 0;
  83. else if (to + len > mtd->size)
  84. len = mtd->size - to;
  85. return part->master->write_oob (part->master, to + part->offset, 
  86. len, retlen, buf);
  87. }
  88. static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
  89.  unsigned long count, loff_t to, size_t *retlen)
  90. {
  91. struct mtd_part *part = PART(mtd);
  92. if (!(mtd->flags & MTD_WRITEABLE))
  93. return -EROFS;
  94. return part->master->writev (part->master, vecs, count,
  95. to + part->offset, retlen);
  96. }
  97. static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
  98.  unsigned long count, loff_t from, size_t *retlen)
  99. {
  100. struct mtd_part *part = PART(mtd);
  101. return part->master->readv (part->master, vecs, count,
  102. from + part->offset, retlen);
  103. }
  104. static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
  105. {
  106. struct mtd_part *part = PART(mtd);
  107. if (!(mtd->flags & MTD_WRITEABLE))
  108. return -EROFS;
  109. if (instr->addr >= mtd->size)
  110. return -EINVAL;
  111. instr->addr += part->offset;
  112. return part->master->erase(part->master, instr);
  113. }
  114. static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
  115. {
  116. struct mtd_part *part = PART(mtd);
  117. if ((len + ofs) > mtd->size) 
  118. return -EINVAL;
  119. return part->master->lock(part->master, ofs + part->offset, len);
  120. }
  121. static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
  122. {
  123. struct mtd_part *part = PART(mtd);
  124. if ((len + ofs) > mtd->size) 
  125. return -EINVAL;
  126. return part->master->unlock(part->master, ofs + part->offset, len);
  127. }
  128. static void part_sync(struct mtd_info *mtd)
  129. {
  130. struct mtd_part *part = PART(mtd);
  131. part->master->sync(part->master);
  132. }
  133. static int part_suspend(struct mtd_info *mtd)
  134. {
  135. struct mtd_part *part = PART(mtd);
  136. return part->master->suspend(part->master);
  137. }
  138. static void part_resume(struct mtd_info *mtd)
  139. {
  140. struct mtd_part *part = PART(mtd);
  141. part->master->resume(part->master);
  142. }
  143. /* 
  144.  * This function unregisters and destroy all slave MTD objects which are 
  145.  * attached to the given master MTD object.
  146.  */
  147. int del_mtd_partitions(struct mtd_info *master)
  148. {
  149. struct list_head *node;
  150. struct mtd_part *slave;
  151. for (node = mtd_partitions.next;
  152.      node != &mtd_partitions;
  153.      node = node->next) {
  154. slave = list_entry(node, struct mtd_part, list);
  155. if (slave->master == master) {
  156. struct list_head *prev = node->prev;
  157. __list_del(prev, node->next);
  158. if(slave->registered)
  159. del_mtd_device(&slave->mtd);
  160. kfree(slave);
  161. node = prev;
  162. }
  163. }
  164. return 0;
  165. }
  166. /*
  167.  * This function, given a master MTD object and a partition table, creates
  168.  * and registers slave MTD objects which are bound to the master according to
  169.  * the partition definitions.
  170.  * (Q: should we register the master MTD object as well?)
  171.  */
  172. int add_mtd_partitions(struct mtd_info *master, 
  173.        struct mtd_partition *parts,
  174.        int nbparts)
  175. {
  176. struct mtd_part *slave;
  177. u_int32_t cur_offset = 0;
  178. int i;
  179. printk (KERN_NOTICE "Creating %d MTD partitions on "%s":n", nbparts, master->name);
  180. for (i = 0; i < nbparts; i++) {
  181. /* allocate the partition structure */
  182. slave = kmalloc (sizeof(*slave), GFP_KERNEL);
  183. if (!slave) {
  184. printk ("memory allocation error while creating partitions for "%s"n",
  185. master->name);
  186. del_mtd_partitions(master);
  187. return -ENOMEM;
  188. }
  189. memset(slave, 0, sizeof(*slave));
  190. list_add(&slave->list, &mtd_partitions);
  191. /* set up the MTD object for this partition */
  192. slave->mtd.type = master->type;
  193. slave->mtd.flags = master->flags & ~parts[i].mask_flags;
  194. slave->mtd.size = parts[i].size;
  195. slave->mtd.oobblock = master->oobblock;
  196. slave->mtd.oobsize = master->oobsize;
  197. slave->mtd.ecctype = master->ecctype;
  198. slave->mtd.eccsize = master->eccsize;
  199. slave->mtd.read_user_prot_reg = master->read_user_prot_reg;
  200. slave->mtd.read_fact_prot_reg = master->read_fact_prot_reg;
  201. slave->mtd.write_user_prot_reg = master->write_user_prot_reg;
  202. slave->mtd.name = parts[i].name;
  203. slave->mtd.bank_size = master->bank_size;
  204. slave->mtd.module = master->module;
  205. slave->mtd.read = part_read;
  206. slave->mtd.write = part_write;
  207. if (master->read_oob)
  208. slave->mtd.read_oob = part_read_oob;
  209. if (master->write_oob)
  210. slave->mtd.write_oob = part_write_oob;
  211. if (master->sync)
  212. slave->mtd.sync = part_sync;
  213. if (!i && master->suspend && master->resume) {
  214. slave->mtd.suspend = part_suspend;
  215. slave->mtd.resume = part_resume;
  216. }
  217. if (master->writev)
  218. slave->mtd.writev = part_writev;
  219. if (master->readv)
  220. slave->mtd.readv = part_readv;
  221. if (master->lock)
  222. slave->mtd.lock = part_lock;
  223. if (master->unlock)
  224. slave->mtd.unlock = part_unlock;
  225. slave->mtd.erase = part_erase;
  226. slave->master = master;
  227. slave->offset = parts[i].offset;
  228. slave->index = i;
  229. if (slave->offset == MTDPART_OFS_APPEND)
  230. slave->offset = cur_offset;
  231. if (slave->offset == MTDPART_OFS_NXTBLK) {
  232. u_int32_t emask = master->erasesize-1;
  233. slave->offset = (cur_offset + emask) & ~emask;
  234. if (slave->offset != cur_offset) {
  235. printk(KERN_NOTICE "Moving partition %d: "
  236.        "0x%08x -> 0x%08xn", i,
  237.        cur_offset, slave->offset);
  238. }
  239. }
  240. if (slave->mtd.size == MTDPART_SIZ_FULL)
  241. slave->mtd.size = master->size - slave->offset;
  242. cur_offset = slave->offset + slave->mtd.size;
  243. printk (KERN_NOTICE "0x%08x-0x%08x : "%s"n", slave->offset, 
  244. slave->offset + slave->mtd.size, slave->mtd.name);
  245. /* let's do some sanity checks */
  246. if (slave->offset >= master->size) {
  247. /* let's register it anyway to preserve ordering */
  248. slave->offset = 0;
  249. slave->mtd.size = 0;
  250. printk ("mtd: partition "%s" is out of reach -- disabledn",
  251. parts[i].name);
  252. }
  253. if (slave->offset + slave->mtd.size > master->size) {
  254. slave->mtd.size = master->size - slave->offset;
  255. printk ("mtd: partition "%s" extends beyond the end of device "%s" -- size truncated to %#xn",
  256. parts[i].name, master->name, slave->mtd.size);
  257. }
  258. if (master->numeraseregions>1) {
  259. /* Deal with variable erase size stuff */
  260. int i;
  261. struct mtd_erase_region_info *regions = master->eraseregions;
  262. /* Find the first erase regions which is part of this partition. */
  263. for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
  264. ;
  265. for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
  266. if (slave->mtd.erasesize < regions[i].erasesize) {
  267. slave->mtd.erasesize = regions[i].erasesize;
  268. }
  269. }
  270. } else {
  271. /* Single erase size */
  272. slave->mtd.erasesize = master->erasesize;
  273. }
  274. if ((slave->mtd.flags & MTD_WRITEABLE) && 
  275.     (slave->offset % slave->mtd.erasesize)) {
  276. /* Doesn't start on a boundary of major erase size */
  277. /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
  278. slave->mtd.flags &= ~MTD_WRITEABLE;
  279. printk ("mtd: partition "%s" doesn't start on an erase block boundary -- force read-onlyn",
  280. parts[i].name);
  281. }
  282. if ((slave->mtd.flags & MTD_WRITEABLE) && 
  283.     (slave->mtd.size % slave->mtd.erasesize)) {
  284. slave->mtd.flags &= ~MTD_WRITEABLE;
  285. printk ("mtd: partition "%s" doesn't end on an erase block -- force read-onlyn",
  286. parts[i].name);
  287. }
  288. if(parts[i].mtdp)
  289. { /* store the object pointer (caller may or may not register it */
  290. *parts[i].mtdp = &slave->mtd;
  291. slave->registered = 0;
  292. }
  293. else
  294. {
  295. /* register our partition */
  296. add_mtd_device(&slave->mtd);
  297. slave->registered = 1;
  298. }
  299. }
  300. return 0;
  301. }
  302. EXPORT_SYMBOL(add_mtd_partitions);
  303. EXPORT_SYMBOL(del_mtd_partitions);
  304. MODULE_LICENSE("GPL");
  305. MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
  306. MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");