Blame view
drivers/mtd/cmdlinepart.c
9.06 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
97894cda5 [MTD] core: Clean... |
2 |
* $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 7 8 |
* * Read flash partition table from command line * * Copyright 2002 SYSGO Real-Time Solutions GmbH * * The format for the command line is as follows: |
97894cda5 [MTD] core: Clean... |
9 |
* |
1da177e4c Linux-2.6.12-rc2 |
10 11 |
* mtdparts=<mtddef>[;<mtddef] * <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
e619a75ff [MTD] Unlocking a... |
12 |
* <partdef> := <size>[@offset][<name>][ro][lk] |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 |
* <mtd-id> := unique name used in mapping driver/device (mtd->name) * <size> := standard linux memsize OR "-" to denote all remaining space * <name> := '(' NAME ')' |
97894cda5 [MTD] core: Clean... |
16 |
* |
1da177e4c Linux-2.6.12-rc2 |
17 |
* Examples: |
97894cda5 [MTD] core: Clean... |
18 |
* |
1da177e4c Linux-2.6.12-rc2 |
19 20 |
* 1 NOR Flash, with 1 single writable partition: * edb7312-nor:- |
97894cda5 [MTD] core: Clean... |
21 |
* |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
* 1 NOR Flash with 2 partitions, 1 NAND with one * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/bootmem.h> /* error message prefix */ #define ERRP "mtd: " /* debug macro */ #if 0 #define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) #else #define dbg(x) #endif /* special size referring to all the remaining space in a partition */ |
b175d03dd [PATCH] mtd cmdli... |
45 46 |
#define SIZE_REMAINING UINT_MAX #define OFFSET_CONTINUOUS UINT_MAX |
1da177e4c Linux-2.6.12-rc2 |
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
struct cmdline_mtd_partition { struct cmdline_mtd_partition *next; char *mtd_id; int num_parts; struct mtd_partition *parts; }; /* mtdpart_setup() parses into here */ static struct cmdline_mtd_partition *partitions; /* the command line passed to mtdpart_setupd() */ static char *cmdline; static int cmdline_parsed = 0; /* * Parse one partition definition for an MTD. Since there can be many |
97894cda5 [MTD] core: Clean... |
64 |
* comma separated partition definitions, this function calls itself |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 68 69 |
* recursively until no more partition definitions are found. Nice side * effect: the memory to keep the mtd_partition structs and the names * is allocated upon the last definition being found. At that point the * syntax has been verified ok. */ |
97894cda5 [MTD] core: Clean... |
70 |
static struct mtd_partition * newpart(char *s, |
1da177e4c Linux-2.6.12-rc2 |
71 72 |
char **retptr, int *num_parts, |
97894cda5 [MTD] core: Clean... |
73 74 |
int this_part, unsigned char **extra_mem_ptr, |
1da177e4c Linux-2.6.12-rc2 |
75 76 77 78 |
int extra_mem_size) { struct mtd_partition *parts; unsigned long size; |
b175d03dd [PATCH] mtd cmdli... |
79 |
unsigned long offset = OFFSET_CONTINUOUS; |
1da177e4c Linux-2.6.12-rc2 |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
char *name; int name_len; unsigned char *extra_mem; char delim; unsigned int mask_flags; /* fetch the partition size */ if (*s == '-') { /* assign all remaining space to this partition */ size = SIZE_REMAINING; s++; } else { size = memparse(s, &s); if (size < PAGE_SIZE) { printk(KERN_ERR ERRP "partition size too small (%lx) ", size); return NULL; } } /* fetch partition name and flags */ mask_flags = 0; /* this is going to be a regular partition */ delim = 0; /* check for offset */ |
97894cda5 [MTD] core: Clean... |
107 |
if (*s == '@') |
1da177e4c Linux-2.6.12-rc2 |
108 109 110 111 112 113 114 115 116 |
{ s++; offset = memparse(s, &s); } /* now look for name */ if (*s == '(') { delim = ')'; } |
97894cda5 [MTD] core: Clean... |
117 |
|
1da177e4c Linux-2.6.12-rc2 |
118 119 120 121 122 |
if (delim) { char *p; name = ++s; |
ed262c4f5 [MTD] cmdlinepart... |
123 124 |
p = strchr(name, delim); if (!p) |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 128 129 130 131 132 133 134 135 136 137 |
{ printk(KERN_ERR ERRP "no closing %c found in partition name ", delim); return NULL; } name_len = p - name; s = p + 1; } else { name = NULL; name_len = 13; /* Partition_000 */ } |
97894cda5 [MTD] core: Clean... |
138 |
|
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 |
/* record name length for memory allocation later */ extra_mem_size += name_len + 1; /* test for options */ |
97894cda5 [MTD] core: Clean... |
143 |
if (strncmp(s, "ro", 2) == 0) |
1da177e4c Linux-2.6.12-rc2 |
144 145 146 147 |
{ mask_flags |= MTD_WRITEABLE; s += 2; } |
e619a75ff [MTD] Unlocking a... |
148 149 150 151 152 153 |
/* if lk is found do NOT unlock the MTD partition*/ if (strncmp(s, "lk", 2) == 0) { mask_flags |= MTD_POWERUP_LOCK; s += 2; } |
1da177e4c Linux-2.6.12-rc2 |
154 155 156 157 158 159 160 161 162 163 |
/* test if more partitions are following */ if (*s == ',') { if (size == SIZE_REMAINING) { printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition "); return NULL; } /* more partitions follow, parse them */ |
ed262c4f5 [MTD] cmdlinepart... |
164 165 166 167 |
parts = newpart(s + 1, &s, num_parts, this_part + 1, &extra_mem, extra_mem_size); if (!parts) return NULL; |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 171 172 173 174 175 |
} else { /* this is the last partition: allocate space for all */ int alloc_size; *num_parts = this_part + 1; alloc_size = *num_parts * sizeof(struct mtd_partition) + extra_mem_size; |
95b93a0cd [MTD] replace kma... |
176 |
parts = kzalloc(alloc_size, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
177 178 179 180 181 182 |
if (!parts) { printk(KERN_ERR ERRP "out of memory "); return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
extra_mem = (unsigned char *)(parts + *num_parts); } /* enter this partition (offset will be calculated later if it is zero at this point) */ parts[this_part].size = size; parts[this_part].offset = offset; parts[this_part].mask_flags = mask_flags; if (name) { strlcpy(extra_mem, name, name_len + 1); } else { sprintf(extra_mem, "Partition_%03d", this_part); } parts[this_part].name = extra_mem; extra_mem += name_len + 1; dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x ", |
97894cda5 [MTD] core: Clean... |
202 |
this_part, |
1da177e4c Linux-2.6.12-rc2 |
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
parts[this_part].name, parts[this_part].offset, parts[this_part].size, parts[this_part].mask_flags)); /* return (updated) pointer to extra_mem memory */ if (extra_mem_ptr) *extra_mem_ptr = extra_mem; /* return (updated) pointer command line string */ *retptr = s; /* return partition table */ return parts; } |
97894cda5 [MTD] core: Clean... |
218 219 |
/* * Parse the command line. |
1da177e4c Linux-2.6.12-rc2 |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
*/ static int mtdpart_setup_real(char *s) { cmdline_parsed = 1; for( ; s != NULL; ) { struct cmdline_mtd_partition *this_mtd; struct mtd_partition *parts; int mtd_id_len; int num_parts; char *p, *mtd_id; mtd_id = s; /* fetch <mtd-id> */ if (!(p = strchr(s, ':'))) { printk(KERN_ERR ERRP "no mtd-id "); return 0; } mtd_id_len = p - mtd_id; dbg(("parsing <%s> ", p+1)); |
97894cda5 [MTD] core: Clean... |
245 |
/* |
1da177e4c Linux-2.6.12-rc2 |
246 247 248 249 250 251 252 253 |
* parse one mtd. have it reserve memory for the * struct cmdline_mtd_partition and the mtd-id string. */ parts = newpart(p + 1, /* cmdline */ &s, /* out: updated cmdline ptr */ &num_parts, /* out: number of parts */ 0, /* first partition */ (unsigned char**)&this_mtd, /* out: extra mem */ |
97894cda5 [MTD] core: Clean... |
254 |
mtd_id_len + 1 + sizeof(*this_mtd) + |
be76c5fb4 [MTD] Fix command... |
255 |
sizeof(void*)-1 /*alignment*/); |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 260 261 262 263 264 265 266 |
if(!parts) { /* * An error occurred. We're either: * a) out of memory, or * b) in the middle of the partition spec * Either way, this mtd is hosed and we're * unlikely to succeed in parsing any more */ return 0; } |
be76c5fb4 [MTD] Fix command... |
267 |
/* align this_mtd */ |
97894cda5 [MTD] core: Clean... |
268 |
this_mtd = (struct cmdline_mtd_partition *) |
be76c5fb4 [MTD] Fix command... |
269 |
ALIGN((unsigned long)this_mtd, sizeof(void*)); |
97894cda5 [MTD] core: Clean... |
270 |
/* enter results */ |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 274 275 276 |
this_mtd->parts = parts; this_mtd->num_parts = num_parts; this_mtd->mtd_id = (char*)(this_mtd + 1); strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); /* link into chain */ |
97894cda5 [MTD] core: Clean... |
277 |
this_mtd->next = partitions; |
1da177e4c Linux-2.6.12-rc2 |
278 |
partitions = this_mtd; |
97894cda5 [MTD] core: Clean... |
279 280 |
dbg(("mtdid=<%s> num_parts=<%d> ", |
1da177e4c Linux-2.6.12-rc2 |
281 |
this_mtd->mtd_id, this_mtd->num_parts)); |
97894cda5 [MTD] core: Clean... |
282 |
|
1da177e4c Linux-2.6.12-rc2 |
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
/* EOS - we're done */ if (*s == 0) break; /* does another spec follow? */ if (*s != ';') { printk(KERN_ERR ERRP "bad character after partition (%c) ", *s); return 0; } s++; } return 1; } /* * Main function to be called from the MTD mapping driver/device to * obtain the partitioning information. At this point the command line * arguments will actually be parsed and turned to struct mtd_partition * information. It returns partitions for the requested mtd device, or * the first one in the chain if a NULL mtd_id is passed in. */ |
97894cda5 [MTD] core: Clean... |
307 |
static int parse_cmdline_partitions(struct mtd_info *master, |
1da177e4c Linux-2.6.12-rc2 |
308 309 310 311 312 313 314 |
struct mtd_partition **pparts, unsigned long origin) { unsigned long offset; int i; struct cmdline_mtd_partition *part; char *mtd_id = master->name; |
1da177e4c Linux-2.6.12-rc2 |
315 316 317 318 319 320 321 322 323 324 |
/* parse command line */ if (!cmdline_parsed) mtdpart_setup_real(cmdline); for(part = partitions; part; part = part->next) { if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) { for(i = 0, offset = 0; i < part->num_parts; i++) { |
b175d03dd [PATCH] mtd cmdli... |
325 |
if (part->parts[i].offset == OFFSET_CONTINUOUS) |
1da177e4c Linux-2.6.12-rc2 |
326 327 328 329 330 331 332 |
part->parts[i].offset = offset; else offset = part->parts[i].offset; if (part->parts[i].size == SIZE_REMAINING) part->parts[i].size = master->size - offset; if (offset + part->parts[i].size > master->size) { |
97894cda5 [MTD] core: Clean... |
333 |
printk(KERN_WARNING ERRP |
1da177e4c Linux-2.6.12-rc2 |
334 335 336 337 338 339 340 341 342 343 344 345 |
"%s: partitioning exceeds flash size, truncating ", part->mtd_id); part->parts[i].size = master->size - offset; part->num_parts = i; } offset += part->parts[i].size; } *pparts = part->parts; return part->num_parts; } } |
b0d06afb6 [MTD] cmdlinepart... |
346 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
347 |
} |
97894cda5 [MTD] core: Clean... |
348 349 |
/* * This is the handler for our kernel parameter, called from |
1da177e4c Linux-2.6.12-rc2 |
350 351 352 353 354 |
* main.c::checksetup(). Note that we can not yet kmalloc() anything, * so we only save the commandline for later processing. * * This function needs to be visible for bootloaders. */ |
ddacff1f2 [MTD] make driver... |
355 |
static int mtdpart_setup(char *s) |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
{ cmdline = s; return 1; } __setup("mtdparts=", mtdpart_setup); static struct mtd_part_parser cmdline_parser = { .owner = THIS_MODULE, .parse_fn = parse_cmdline_partitions, .name = "cmdlinepart", }; static int __init cmdline_parser_init(void) { return register_mtd_parser(&cmdline_parser); } module_init(cmdline_parser_init); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); MODULE_DESCRIPTION("Command line configuration of MTD partitions"); |