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