/* * fs/partitions/cmdline.c * * Copyright (C) 2010 Google, Inc. * Author: Colin Cross * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ /*#define DEBUG 1*/ #include #include #include #include #include "check.h" #include "cmdline.h" static char *cmdline; static int cmdline_parsed; static struct part_device *cmdline_device; struct part { char *name; unsigned long from; unsigned long size; unsigned long sector_size; struct part *next_part; }; struct part_device { char *name; struct part *first_part; struct part_device *next_device; }; /* Passed a string like: * system:3600:10000:800 */ static struct part *parse_partition(char *s, int alloc_size, void **alloc) { char *p; struct part *this_part; pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc); if (*alloc == NULL) *alloc = kzalloc(alloc_size, GFP_KERNEL); this_part = *alloc; *alloc += sizeof(*this_part); /* Name */ p = strchr(s, ':'); if (!p) return this_part; *p = 0; this_part->name = s; /* From */ s = p+1; p = strchr(s, ':'); if (!p) return this_part; *p = 0; this_part->from = simple_strtoul(s, NULL, 16); /* Size */ s = p+1; p = strchr(s, ':'); if (!p) return this_part; *p = 0; this_part->size = simple_strtoul(s, NULL, 16); /* Sector size */ s = p+1; this_part->sector_size = simple_strtoul(s, NULL, 16); pr_debug("%s: Found %s %lu %lu %lu\n", __func__, this_part->name, this_part->from, this_part->size, this_part->sector_size); return this_part; } /* Passed a string like: * system:3600:10000:800,cache:13600:4000:800,userdata:17600:80000:800 * Could be an empty string */ static struct part *parse_partition_list(char *s, int alloc_size, void **alloc) { char *p; struct part *this_part; struct part *next_part = NULL; pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc); alloc_size += sizeof(struct part); p = strchr(s, ','); if (p) { *p = 0; next_part = parse_partition_list(p+1, alloc_size, alloc); if (!next_part) BUG(); } this_part = parse_partition(s, alloc_size, alloc); this_part->next_part = next_part; return this_part; } /* Passed a string like: * sdhci.0=system:3600:10000:800,cache:13600:4000:800,userdata:17600:80000:800 */ static struct part_device *parse_device(char *s, int alloc_size, void **alloc) { char *p; struct part *part; struct part_device *device; pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc); p = strchr(s, '='); if (!p) return NULL; *p = 0; alloc_size += sizeof(struct part_device); part = parse_partition_list(p+1, alloc_size, alloc); if (part) { device = *alloc; *alloc += sizeof(struct part_device); device->name = s; device->first_part = part; } return device; } static void parse_cmdline(void) { char *s = cmdline; void *alloc = 0; if (cmdline_parsed) return; cmdline_device = parse_device(s, 0, &alloc); cmdline_parsed = 1; } int copy_partitions_to_state(struct part_device *device, struct parsed_partitions *state, unsigned int ssz) { int i = 0; struct part *part = device->first_part; while (part) { sector_t from = part->from * (part->sector_size / ssz); sector_t size = part->size * (part->sector_size / ssz); put_named_partition(state, i+1, from, size, part->name, strlen(part->name)); i++; part = part->next_part; } return i; } int cmdline_partition(struct parsed_partitions *state) { struct block_device *bdev = state->bdev; unsigned int ssz = bdev_logical_block_size(bdev); parse_cmdline(); pr_debug("%s: %s\n", __func__, dev_name(disk_to_dev(bdev->bd_disk))); if (!cmdline_device) return 0; if (strcmp(cmdline_device->name, dev_name(disk_to_dev(bdev->bd_disk)))) return 0; /* We have a command line partition that matches this device */ copy_partitions_to_state(cmdline_device, state, ssz); return 1; } __init static int cmdline_partition_setup(char *s) { cmdline = s; return 1; } __setup("tegrapart=", cmdline_partition_setup);