aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdpart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdpart.c')
-rw-r--r--drivers/mtd/mtdpart.c99
1 files changed, 50 insertions, 49 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index b92e6bfffaf2..99395911d26f 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -5,11 +5,11 @@
5 * 5 *
6 * This code is GPL 6 * This code is GPL
7 * 7 *
8 * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ 8 * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $
9 * 9 *
10 * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> 10 * 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
11 * added support for read_oob, write_oob 11 * added support for read_oob, write_oob
12 */ 12 */
13 13
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/types.h> 15#include <linux/types.h>
@@ -41,13 +41,13 @@ struct mtd_part {
41 */ 41 */
42#define PART(x) ((struct mtd_part *)(x)) 42#define PART(x) ((struct mtd_part *)(x))
43 43
44 44
45/* 45/*
46 * MTD methods which simply translate the effective address and pass through 46 * MTD methods which simply translate the effective address and pass through
47 * to the _real_ device. 47 * to the _real_ device.
48 */ 48 */
49 49
50static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 50static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
51 size_t *retlen, u_char *buf) 51 size_t *retlen, u_char *buf)
52{ 52{
53 struct mtd_part *part = PART(mtd); 53 struct mtd_part *part = PART(mtd);
@@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
55 len = 0; 55 len = 0;
56 else if (from + len > mtd->size) 56 else if (from + len > mtd->size)
57 len = mtd->size - from; 57 len = mtd->size - from;
58 if (part->master->read_ecc == NULL) 58 if (part->master->read_ecc == NULL)
59 return part->master->read (part->master, from + part->offset, 59 return part->master->read (part->master, from + part->offset,
60 len, retlen, buf); 60 len, retlen, buf);
61 else 61 else
62 return part->master->read_ecc (part->master, from + part->offset, 62 return part->master->read_ecc (part->master, from + part->offset,
63 len, retlen, buf, NULL, &mtd->oobinfo); 63 len, retlen, buf, NULL, &mtd->oobinfo);
64} 64}
65 65
66static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 66static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
67 size_t *retlen, u_char **buf) 67 size_t *retlen, u_char **buf)
68{ 68{
69 struct mtd_part *part = PART(mtd); 69 struct mtd_part *part = PART(mtd);
@@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
71 len = 0; 71 len = 0;
72 else if (from + len > mtd->size) 72 else if (from + len > mtd->size)
73 len = mtd->size - from; 73 len = mtd->size - from;
74 return part->master->point (part->master, from + part->offset, 74 return part->master->point (part->master, from + part->offset,
75 len, retlen, buf); 75 len, retlen, buf);
76} 76}
77static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) 77static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
@@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
82} 82}
83 83
84 84
85static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 85static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
86 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) 86 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
87{ 87{
88 struct mtd_part *part = PART(mtd); 88 struct mtd_part *part = PART(mtd);
@@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
92 len = 0; 92 len = 0;
93 else if (from + len > mtd->size) 93 else if (from + len > mtd->size)
94 len = mtd->size - from; 94 len = mtd->size - from;
95 return part->master->read_ecc (part->master, from + part->offset, 95 return part->master->read_ecc (part->master, from + part->offset,
96 len, retlen, buf, eccbuf, oobsel); 96 len, retlen, buf, eccbuf, oobsel);
97} 97}
98 98
99static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 99static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
100 size_t *retlen, u_char *buf) 100 size_t *retlen, u_char *buf)
101{ 101{
102 struct mtd_part *part = PART(mtd); 102 struct mtd_part *part = PART(mtd);
@@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
104 len = 0; 104 len = 0;
105 else if (from + len > mtd->size) 105 else if (from + len > mtd->size)
106 len = mtd->size - from; 106 len = mtd->size - from;
107 return part->master->read_oob (part->master, from + part->offset, 107 return part->master->read_oob (part->master, from + part->offset,
108 len, retlen, buf); 108 len, retlen, buf);
109} 109}
110 110
111static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 111static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
112 size_t *retlen, u_char *buf) 112 size_t *retlen, u_char *buf)
113{ 113{
114 struct mtd_part *part = PART(mtd); 114 struct mtd_part *part = PART(mtd);
115 return part->master->read_user_prot_reg (part->master, from, 115 return part->master->read_user_prot_reg (part->master, from,
116 len, retlen, buf); 116 len, retlen, buf);
117} 117}
118 118
@@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd,
123 return part->master->get_user_prot_info (part->master, buf, len); 123 return part->master->get_user_prot_info (part->master, buf, len);
124} 124}
125 125
126static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 126static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
127 size_t *retlen, u_char *buf) 127 size_t *retlen, u_char *buf)
128{ 128{
129 struct mtd_part *part = PART(mtd); 129 struct mtd_part *part = PART(mtd);
130 return part->master->read_fact_prot_reg (part->master, from, 130 return part->master->read_fact_prot_reg (part->master, from,
131 len, retlen, buf); 131 len, retlen, buf);
132} 132}
133 133
@@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
148 len = 0; 148 len = 0;
149 else if (to + len > mtd->size) 149 else if (to + len > mtd->size)
150 len = mtd->size - to; 150 len = mtd->size - to;
151 if (part->master->write_ecc == NULL) 151 if (part->master->write_ecc == NULL)
152 return part->master->write (part->master, to + part->offset, 152 return part->master->write (part->master, to + part->offset,
153 len, retlen, buf); 153 len, retlen, buf);
154 else 154 else
155 return part->master->write_ecc (part->master, to + part->offset, 155 return part->master->write_ecc (part->master, to + part->offset,
156 len, retlen, buf, NULL, &mtd->oobinfo); 156 len, retlen, buf, NULL, &mtd->oobinfo);
157 157
158} 158}
159 159
160static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, 160static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
@@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
170 len = 0; 170 len = 0;
171 else if (to + len > mtd->size) 171 else if (to + len > mtd->size)
172 len = mtd->size - to; 172 len = mtd->size - to;
173 return part->master->write_ecc (part->master, to + part->offset, 173 return part->master->write_ecc (part->master, to + part->offset,
174 len, retlen, buf, eccbuf, oobsel); 174 len, retlen, buf, eccbuf, oobsel);
175} 175}
176 176
@@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
184 len = 0; 184 len = 0;
185 else if (to + len > mtd->size) 185 else if (to + len > mtd->size)
186 len = mtd->size - to; 186 len = mtd->size - to;
187 return part->master->write_oob (part->master, to + part->offset, 187 return part->master->write_oob (part->master, to + part->offset,
188 len, retlen, buf); 188 len, retlen, buf);
189} 189}
190 190
191static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 191static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
192 size_t *retlen, u_char *buf) 192 size_t *retlen, u_char *buf)
193{ 193{
194 struct mtd_part *part = PART(mtd); 194 struct mtd_part *part = PART(mtd);
195 return part->master->write_user_prot_reg (part->master, from, 195 return part->master->write_user_prot_reg (part->master, from,
196 len, retlen, buf); 196 len, retlen, buf);
197} 197}
198 198
199static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 199static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
200{ 200{
201 struct mtd_part *part = PART(mtd); 201 struct mtd_part *part = PART(mtd);
202 return part->master->lock_user_prot_reg (part->master, from, len); 202 return part->master->lock_user_prot_reg (part->master, from, len);
@@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
208 struct mtd_part *part = PART(mtd); 208 struct mtd_part *part = PART(mtd);
209 if (!(mtd->flags & MTD_WRITEABLE)) 209 if (!(mtd->flags & MTD_WRITEABLE))
210 return -EROFS; 210 return -EROFS;
211 if (part->master->writev_ecc == NULL) 211 if (part->master->writev_ecc == NULL)
212 return part->master->writev (part->master, vecs, count, 212 return part->master->writev (part->master, vecs, count,
213 to + part->offset, retlen); 213 to + part->offset, retlen);
214 else 214 else
@@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd, struct kvec *vecs,
221 unsigned long count, loff_t from, size_t *retlen) 221 unsigned long count, loff_t from, size_t *retlen)
222{ 222{
223 struct mtd_part *part = PART(mtd); 223 struct mtd_part *part = PART(mtd);
224 if (part->master->readv_ecc == NULL) 224 if (part->master->readv_ecc == NULL)
225 return part->master->readv (part->master, vecs, count, 225 return part->master->readv (part->master, vecs, count,
226 from + part->offset, retlen); 226 from + part->offset, retlen);
227 else 227 else
228 return part->master->readv_ecc (part->master, vecs, count, 228 return part->master->readv_ecc (part->master, vecs, count,
229 from + part->offset, retlen, 229 from + part->offset, retlen,
230 NULL, &mtd->oobinfo); 230 NULL, &mtd->oobinfo);
231} 231}
232 232
@@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
252 if (oobsel == NULL) 252 if (oobsel == NULL)
253 oobsel = &mtd->oobinfo; 253 oobsel = &mtd->oobinfo;
254 return part->master->readv_ecc (part->master, vecs, count, 254 return part->master->readv_ecc (part->master, vecs, count,
255 from + part->offset, retlen, 255 from + part->offset, retlen,
256 eccbuf, oobsel); 256 eccbuf, oobsel);
257} 257}
258 258
@@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
286static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) 286static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
287{ 287{
288 struct mtd_part *part = PART(mtd); 288 struct mtd_part *part = PART(mtd);
289 if ((len + ofs) > mtd->size) 289 if ((len + ofs) > mtd->size)
290 return -EINVAL; 290 return -EINVAL;
291 return part->master->lock(part->master, ofs + part->offset, len); 291 return part->master->lock(part->master, ofs + part->offset, len);
292} 292}
@@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
294static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) 294static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
295{ 295{
296 struct mtd_part *part = PART(mtd); 296 struct mtd_part *part = PART(mtd);
297 if ((len + ofs) > mtd->size) 297 if ((len + ofs) > mtd->size)
298 return -EINVAL; 298 return -EINVAL;
299 return part->master->unlock(part->master, ofs + part->offset, len); 299 return part->master->unlock(part->master, ofs + part->offset, len);
300} 300}
@@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
337 return part->master->block_markbad(part->master, ofs); 337 return part->master->block_markbad(part->master, ofs);
338} 338}
339 339
340/* 340/*
341 * This function unregisters and destroy all slave MTD objects which are 341 * This function unregisters and destroy all slave MTD objects which are
342 * attached to the given master MTD object. 342 * attached to the given master MTD object.
343 */ 343 */
344 344
@@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master)
371 * (Q: should we register the master MTD object as well?) 371 * (Q: should we register the master MTD object as well?)
372 */ 372 */
373 373
374int add_mtd_partitions(struct mtd_info *master, 374int add_mtd_partitions(struct mtd_info *master,
375 const struct mtd_partition *parts, 375 const struct mtd_partition *parts,
376 int nbparts) 376 int nbparts)
377{ 377{
@@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master,
414 slave->mtd.point = part_point; 414 slave->mtd.point = part_point;
415 slave->mtd.unpoint = part_unpoint; 415 slave->mtd.unpoint = part_unpoint;
416 } 416 }
417 417
418 if (master->read_ecc) 418 if (master->read_ecc)
419 slave->mtd.read_ecc = part_read_ecc; 419 slave->mtd.read_ecc = part_read_ecc;
420 if (master->write_ecc) 420 if (master->write_ecc)
@@ -465,9 +465,10 @@ int add_mtd_partitions(struct mtd_info *master,
465 if (slave->offset == MTDPART_OFS_APPEND) 465 if (slave->offset == MTDPART_OFS_APPEND)
466 slave->offset = cur_offset; 466 slave->offset = cur_offset;
467 if (slave->offset == MTDPART_OFS_NXTBLK) { 467 if (slave->offset == MTDPART_OFS_NXTBLK) {
468 u_int32_t emask = master->erasesize-1; 468 slave->offset = cur_offset;
469 slave->offset = (cur_offset + emask) & ~emask; 469 if ((cur_offset % master->erasesize) != 0) {
470 if (slave->offset != cur_offset) { 470 /* Round up to next erasesize */
471 slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
471 printk(KERN_NOTICE "Moving partition %d: " 472 printk(KERN_NOTICE "Moving partition %d: "
472 "0x%08x -> 0x%08x\n", i, 473 "0x%08x -> 0x%08x\n", i,
473 cur_offset, slave->offset); 474 cur_offset, slave->offset);
@@ -476,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master,
476 if (slave->mtd.size == MTDPART_SIZ_FULL) 477 if (slave->mtd.size == MTDPART_SIZ_FULL)
477 slave->mtd.size = master->size - slave->offset; 478 slave->mtd.size = master->size - slave->offset;
478 cur_offset = slave->offset + slave->mtd.size; 479 cur_offset = slave->offset + slave->mtd.size;
479 480
480 printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 481 printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
481 slave->offset + slave->mtd.size, slave->mtd.name); 482 slave->offset + slave->mtd.size, slave->mtd.name);
482 483
483 /* let's do some sanity checks */ 484 /* let's do some sanity checks */
@@ -497,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master,
497 /* Deal with variable erase size stuff */ 498 /* Deal with variable erase size stuff */
498 int i; 499 int i;
499 struct mtd_erase_region_info *regions = master->eraseregions; 500 struct mtd_erase_region_info *regions = master->eraseregions;
500 501
501 /* Find the first erase regions which is part of this partition. */ 502 /* Find the first erase regions which is part of this partition. */
502 for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) 503 for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
503 ; 504 ;
@@ -512,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master,
512 slave->mtd.erasesize = master->erasesize; 513 slave->mtd.erasesize = master->erasesize;
513 } 514 }
514 515
515 if ((slave->mtd.flags & MTD_WRITEABLE) && 516 if ((slave->mtd.flags & MTD_WRITEABLE) &&
516 (slave->offset % slave->mtd.erasesize)) { 517 (slave->offset % slave->mtd.erasesize)) {
517 /* Doesn't start on a boundary of major erase size */ 518 /* Doesn't start on a boundary of major erase size */
518 /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ 519 /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
@@ -520,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master,
520 printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", 521 printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
521 parts[i].name); 522 parts[i].name);
522 } 523 }
523 if ((slave->mtd.flags & MTD_WRITEABLE) && 524 if ((slave->mtd.flags & MTD_WRITEABLE) &&
524 (slave->mtd.size % slave->mtd.erasesize)) { 525 (slave->mtd.size % slave->mtd.erasesize)) {
525 slave->mtd.flags &= ~MTD_WRITEABLE; 526 slave->mtd.flags &= ~MTD_WRITEABLE;
526 printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", 527 printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
527 parts[i].name); 528 parts[i].name);
528 } 529 }
529 530
530 /* copy oobinfo from master */ 531 /* copy oobinfo from master */
531 memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); 532 memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
532 533
533 if(parts[i].mtdp) 534 if(parts[i].mtdp)
@@ -588,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p)
588 return 0; 589 return 0;
589} 590}
590 591
591int parse_mtd_partitions(struct mtd_info *master, const char **types, 592int parse_mtd_partitions(struct mtd_info *master, const char **types,
592 struct mtd_partition **pparts, unsigned long origin) 593 struct mtd_partition **pparts, unsigned long origin)
593{ 594{
594 struct mtd_part_parser *parser; 595 struct mtd_part_parser *parser;
595 int ret = 0; 596 int ret = 0;
596 597
597 for ( ; ret <= 0 && *types; types++) { 598 for ( ; ret <= 0 && *types; types++) {
598 parser = get_partition_parser(*types); 599 parser = get_partition_parser(*types);
599#ifdef CONFIG_KMOD 600#ifdef CONFIG_KMOD
@@ -607,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
607 } 608 }
608 ret = (*parser->parse_fn)(master, pparts, origin); 609 ret = (*parser->parse_fn)(master, pparts, origin);
609 if (ret > 0) { 610 if (ret > 0) {
610 printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", 611 printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
611 ret, parser->name, master->name); 612 ret, parser->name, master->name);
612 } 613 }
613 put_partition_parser(parser); 614 put_partition_parser(parser);