1 #include <linux/kernel.h>
2 #include <linux/slab.h>
3 #include <linux/bootmem.h>
7 /* rkpart_setup() parses into here */
8 static struct cmdline_rk_partition *partitions;
9 /* the command line passed to mtdpart_setupd() */
11 static int cmdline_parsed;
14 * Parse one partition definition for an rkpart. Since there can be many
15 * comma separated partition definitions, this function calls itself
16 * recursively until no more partition definitions are found. Nice side
17 * effect: the memory to keep the rk_partition structs and the names
18 * is allocated upon the last definition being found. At that point the
19 * syntax has been verified ok.
21 static struct rk_partition *newpart(char *s,
25 unsigned char **extra_mem_ptr,
28 struct rk_partition *parts;
30 sector_t from = OFFSET_CONTINUOUS;
33 unsigned char *extra_mem;
36 /* fetch the partition size */
38 { /* assign all remaining space to this partition */
39 size = SIZE_REMAINING;
44 size = memparse(s, &s);
45 /* No sense support partition less than 8B */
46 if (size < ((PAGE_SIZE) >> 9))
48 printk(KERN_ERR ERRP "partition size too small (%llx)\n", (u64)size);
53 /* fetch partition name */
59 from = memparse(s, &s);
61 /* now look for name */
72 p = strchr(name, delim);
75 printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
84 name_len = 13; /* Partition_000 */
87 /* record name length for memory allocation later */
88 extra_mem_size += name_len + 1;
90 /* test if more partitions are following */
93 if (size == SIZE_REMAINING)
95 printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
98 /* more partitions follow, parse them */
99 parts = newpart(s + 1, &s, num_parts, this_part + 1,
100 &extra_mem, extra_mem_size);
105 { /* this is the last partition: allocate space for all */
108 *num_parts = this_part + 1;
109 alloc_size = *num_parts * sizeof(struct rk_partition) +
111 parts = kzalloc(alloc_size, GFP_KERNEL);
114 printk(KERN_ERR ERRP "out of memory\n");
117 extra_mem = (unsigned char *)(parts + *num_parts);
119 /* enter this partition (from will be calculated later if it is zero at this point) */
120 parts[this_part].size = size;
121 parts[this_part].from = from;
124 strlcpy(extra_mem, name, name_len + 1);
128 sprintf(extra_mem, "Partition_%03d", this_part);
130 parts[this_part].name = extra_mem;
131 extra_mem += name_len + 1;
133 dbg(("partition %d: name <%s>, from %llx, size %llx\n",
135 parts[this_part].name,
136 parts[this_part].from,
137 parts[this_part].size));
139 /* return (updated) pointer to extra_mem memory */
141 *extra_mem_ptr = extra_mem;
143 /* return (updated) pointer command line string */
146 /* return partition table */
151 * Parse the command line.
153 static int rkpart_setup_real(char *s)
159 struct cmdline_rk_partition *this_rk;
160 struct rk_partition *parts;
167 if (!(p = strchr(s, ':')))
169 dbg(( "no rk-id\n"));
172 rk_id_len = p - rk_id;
174 dbg(("parsing <%s>\n", p + 1));
177 * parse one mtd. have it reserve memory for the
178 * struct cmdline_mtd_partition and the mtd-id string.
180 parts = newpart(p + 1, /* cmdline */
181 &s, /* out: updated cmdline ptr */
182 &num_parts, /* out: number of parts */
183 0, /* first partition */
184 (unsigned char**)&this_rk, /* out: extra mem */
185 rk_id_len + 1 + sizeof(*this_rk) +
186 sizeof(void*)-1 /*alignment*/);
190 * An error occurred. We're either:
191 * a) out of memory, or
192 * b) in the middle of the partition spec
193 * Either way, this mtd is hosed and we're
194 * unlikely to succeed in parsing any more
200 this_rk = (struct cmdline_rk_partition *)
201 ALIGN((unsigned long)this_rk, sizeof(void*));
203 this_rk->parts = parts;
204 this_rk->num_parts = num_parts;
205 this_rk->rk_id = (char*)(this_rk + 1);
206 strlcpy(this_rk->rk_id, rk_id, rk_id_len + 1);
208 /* link into chain */
209 this_rk->next = partitions;
210 partitions = this_rk;
212 dbg(("rkid=<%s> num_parts=<%d>\n",
213 this_rk->mtd_id, this_rk->num_parts));
215 /* EOS - we're done */
224 * Main function to be called from the MTD mapping driver/device to
225 * obtain the partitioning information. At this point the command line
226 * arguments will actually be parsed and turned to struct mtd_partition
227 * information. It returns partitions for the requested mtd device, or
228 * the first one in the chain if a NULL mtd_id is passed in.
230 static int parse_cmdline_partitions(sector_t n,
231 struct rk_partition **pparts,
232 unsigned long origin)
236 struct cmdline_rk_partition *part;
237 /* Fixme: parameter should be coherence with part table id */
238 const char *rk_id = "rk29xxnand";
240 /* parse command line */
242 rkpart_setup_real(cmdline);
244 for(part = partitions; part; part = part->next)
246 if ((!rk_id) || (!strcmp(part->rk_id, rk_id)))
248 for(i = 0, from = 0; i < part->num_parts; i++)
250 if (part->parts[i].from == OFFSET_CONTINUOUS)
251 part->parts[i].from = from;
253 from = part->parts[i].from;
254 if (part->parts[i].size == SIZE_REMAINING)
255 part->parts[i].size = n - from - FROM_OFFSET;
256 if (from + part->parts[i].size > n)
258 printk(KERN_WARNING ERRP
259 "%s: partitioning exceeds flash size, truncating\n",
261 part->parts[i].size = n - from;
264 from += part->parts[i].size;
266 *pparts = kmemdup(part->parts,
267 sizeof(*part->parts) * part->num_parts,
271 return part->num_parts;
277 static void rkpart_bootmode_fixup(void)
279 const char mode[] = " androidboot.mode=emmc";
280 const char charger[] = " androidboot.charger.emmc=1";
281 char *new_command_line;
282 size_t saved_command_line_len = strlen(saved_command_line);
284 if (strstr(saved_command_line, "androidboot.mode=charger")) {
285 new_command_line = kzalloc(saved_command_line_len + strlen(charger) + 1, GFP_KERNEL);
286 sprintf(new_command_line, "%s%s", saved_command_line, charger);
288 new_command_line = kzalloc(saved_command_line_len + strlen(mode) + 1, GFP_KERNEL);
289 sprintf(new_command_line, "%s%s", saved_command_line, mode);
291 saved_command_line = new_command_line;
294 int rkpart_partition(struct parsed_partitions *state)
296 int num_parts = 0, i;
297 sector_t n = get_capacity(state->bdev->bd_disk);
298 struct rk_partition *parts = NULL;
303 /* ONLY be used by eMMC-disk */
304 if (1 != state->bdev->bd_disk->emmc_disk)
307 /* Fixme: parameter should be coherence with part table */
308 cmdline = strstr(saved_command_line, "mtdparts=");
314 num_parts = parse_cmdline_partitions(n, &parts, 0);
318 for (i = 0; i < num_parts; i++) {
319 put_partition( state,
321 parts[i].from + FROM_OFFSET,
323 strcpy(state->parts[i+1].info.volname, parts[i].name);
324 printk(KERN_INFO "%10s: 0x%09llx -- 0x%09llx (%llu MB)\n",
326 (u64)parts[i].from * 512,
327 (u64)(parts[i].from + parts[i].size) * 512,
328 (u64)parts[i].size / 2048);
331 rkpart_bootmode_fixup();