0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011
0012 #include <linux/mtd/mtd.h>
0013 #include <linux/mtd/partitions.h>
0014 #include <linux/memblock.h>
0015 #include <linux/module.h>
0016
0017 #include <uapi/linux/magic.h>
0018
0019 #define AR7_PARTS 4
0020 #define ROOT_OFFSET 0xe0000
0021
0022 #define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42)
0023 #define LOADER_MAGIC2 le32_to_cpu(0xfeed1281)
0024
0025 struct ar7_bin_rec {
0026 unsigned int checksum;
0027 unsigned int length;
0028 unsigned int address;
0029 };
0030
0031 static int create_mtd_partitions(struct mtd_info *master,
0032 const struct mtd_partition **pparts,
0033 struct mtd_part_parser_data *data)
0034 {
0035 struct ar7_bin_rec header;
0036 unsigned int offset;
0037 size_t len;
0038 unsigned int pre_size = master->erasesize, post_size = 0;
0039 unsigned int root_offset = ROOT_OFFSET;
0040
0041 int retries = 10;
0042 struct mtd_partition *ar7_parts;
0043
0044 ar7_parts = kcalloc(AR7_PARTS, sizeof(*ar7_parts), GFP_KERNEL);
0045 if (!ar7_parts)
0046 return -ENOMEM;
0047 ar7_parts[0].name = "loader";
0048 ar7_parts[0].offset = 0;
0049 ar7_parts[0].size = master->erasesize;
0050 ar7_parts[0].mask_flags = MTD_WRITEABLE;
0051
0052 ar7_parts[1].name = "config";
0053 ar7_parts[1].offset = 0;
0054 ar7_parts[1].size = master->erasesize;
0055 ar7_parts[1].mask_flags = 0;
0056
0057 do {
0058 offset = pre_size;
0059 mtd_read(master, offset, sizeof(header), &len,
0060 (uint8_t *)&header);
0061 if (!strncmp((char *)&header, "TIENV0.8", 8))
0062 ar7_parts[1].offset = pre_size;
0063 if (header.checksum == LOADER_MAGIC1)
0064 break;
0065 if (header.checksum == LOADER_MAGIC2)
0066 break;
0067 pre_size += master->erasesize;
0068 } while (retries--);
0069
0070 pre_size = offset;
0071
0072 if (!ar7_parts[1].offset) {
0073 ar7_parts[1].offset = master->size - master->erasesize;
0074 post_size = master->erasesize;
0075 }
0076
0077 switch (header.checksum) {
0078 case LOADER_MAGIC1:
0079 while (header.length) {
0080 offset += sizeof(header) + header.length;
0081 mtd_read(master, offset, sizeof(header), &len,
0082 (uint8_t *)&header);
0083 }
0084 root_offset = offset + sizeof(header) + 4;
0085 break;
0086 case LOADER_MAGIC2:
0087 while (header.length) {
0088 offset += sizeof(header) + header.length;
0089 mtd_read(master, offset, sizeof(header), &len,
0090 (uint8_t *)&header);
0091 }
0092 root_offset = offset + sizeof(header) + 4 + 0xff;
0093 root_offset &= ~(uint32_t)0xff;
0094 break;
0095 default:
0096 printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum);
0097 break;
0098 }
0099
0100 mtd_read(master, root_offset, sizeof(header), &len, (u8 *)&header);
0101 if (header.checksum != SQUASHFS_MAGIC) {
0102 root_offset += master->erasesize - 1;
0103 root_offset &= ~(master->erasesize - 1);
0104 }
0105
0106 ar7_parts[2].name = "linux";
0107 ar7_parts[2].offset = pre_size;
0108 ar7_parts[2].size = master->size - pre_size - post_size;
0109 ar7_parts[2].mask_flags = 0;
0110
0111 ar7_parts[3].name = "rootfs";
0112 ar7_parts[3].offset = root_offset;
0113 ar7_parts[3].size = master->size - root_offset - post_size;
0114 ar7_parts[3].mask_flags = 0;
0115
0116 *pparts = ar7_parts;
0117 return AR7_PARTS;
0118 }
0119
0120 static struct mtd_part_parser ar7_parser = {
0121 .parse_fn = create_mtd_partitions,
0122 .name = "ar7part",
0123 };
0124 module_mtd_part_parser(ar7_parser);
0125
0126 MODULE_LICENSE("GPL");
0127 MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, "
0128 "Eugene Konev <ejka@openwrt.org>");
0129 MODULE_DESCRIPTION("MTD partitioning for TI AR7");