diff options
Diffstat (limited to 'target/linux/generic-2.6/files')
| -rw-r--r-- | target/linux/generic-2.6/files/drivers/mtd/myloader.c | 178 | 
1 files changed, 178 insertions, 0 deletions
| diff --git a/target/linux/generic-2.6/files/drivers/mtd/myloader.c b/target/linux/generic-2.6/files/drivers/mtd/myloader.c new file mode 100644 index 000000000..60ebe2205 --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/mtd/myloader.c @@ -0,0 +1,178 @@ +/* + *  Parse MyLoader-style flash partition tables and produce a Linux partition + *  array to match. + * + *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> + * + *  This file was based on drivers/mtd/redboot.c + *  Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com> + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/byteorder/generic.h> +#include <linux/myloader.h> + +#define BLOCK_LEN_MIN		0x10000 +#define PART_NAME_LEN		32 + +struct part_data { +	struct mylo_partition_table	tab; +	char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; +}; + +int myloader_parse_partitions(struct mtd_info *master, +			struct mtd_partition **pparts, +			unsigned long origin) +{ +	struct part_data *buf; +	struct mylo_partition_table *tab; +	struct mylo_partition *part; +	struct mtd_partition *mtd_parts; +	struct mtd_partition *mtd_part; +	int num_parts; +	int ret, i; +	size_t retlen; +	char *names; +	unsigned long offset; +	unsigned long blocklen; + +	buf = vmalloc(sizeof(*buf)); +	if (!buf) { +		return -ENOMEM; +		goto out; +	} +	tab = &buf->tab; + +	blocklen = master->erasesize; +	if (blocklen < BLOCK_LEN_MIN) +		blocklen = BLOCK_LEN_MIN; + +	offset = blocklen; + +	/* Find the partition table */ +	for (i = 0; i < 4; i++, offset += blocklen) { +		printk(KERN_DEBUG "%s: searching for MyLoader partition table" +				" at offset 0x%lx\n", master->name, offset); + +		ret = master->read(master, offset, sizeof(*buf), &retlen, +					(void *)buf); +		if (ret) +			goto out_free_buf; + +		if (retlen != sizeof(*buf)) { +			ret = -EIO; +			goto out_free_buf; +		} + +		/* Check for Partition Table magic number */ +		if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) +			break; + +	} + +	if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { +		printk(KERN_DEBUG "%s: no MyLoader partition table found\n", +			master->name); +		ret = 0; +		goto out_free_buf; +	} + +	/* The MyLoader and the Partition Table is always present */ +	num_parts = 2; + +	/* Detect number of used partitions */ +	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { +		part = &tab->partitions[i]; + +		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) +			continue; + +		num_parts++; +	} + +	mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + +				num_parts * PART_NAME_LEN), GFP_KERNEL); + +	if (!mtd_parts) { +		ret = -ENOMEM; +		goto out_free_buf; +	} + +	mtd_part = mtd_parts; +	names = (char *)&mtd_parts[num_parts]; + +	strncpy(names, "myloader", PART_NAME_LEN); +	mtd_part->name = names; +	mtd_part->offset = 0; +	mtd_part->size = offset; +	mtd_part->mask_flags = MTD_WRITEABLE; +	mtd_part++; +	names += PART_NAME_LEN; + +	strncpy(names, "partition_table", PART_NAME_LEN); +	mtd_part->name = names; +	mtd_part->offset = offset; +	mtd_part->size = blocklen; +	mtd_part->mask_flags = MTD_WRITEABLE; +	mtd_part++; +	names += PART_NAME_LEN; + +	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { +		part = &tab->partitions[i]; + +		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) +			continue; + +		if (buf->names[i][0]) +			strncpy(names, buf->names[i], PART_NAME_LEN); +		else +			snprintf(names, PART_NAME_LEN, "partition%d", i); + +		mtd_part->offset = le32_to_cpu(part->addr); +		mtd_part->size = le32_to_cpu(part->size); +		mtd_part->name = names; +		mtd_part++; +		names += PART_NAME_LEN; +	} + +	*pparts = mtd_parts; +	ret = num_parts; + + out_free_buf: +	vfree(buf); + out: +	return ret; +} + +static struct mtd_part_parser myloader_mtd_parser = { +	.owner		= THIS_MODULE, +	.parse_fn	= myloader_parse_partitions, +	.name		= "MyLoader", +}; + +static int __init myloader_mtd_parser_init(void) +{ +	return register_mtd_parser(&myloader_mtd_parser); +} + +static void __exit myloader_mtd_parser_exit(void) +{ +	deregister_mtd_parser(&myloader_mtd_parser); +} + +module_init(myloader_mtd_parser_init); +module_exit(myloader_mtd_parser_exit); + +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); +MODULE_LICENSE("GPL v2"); | 
