linux/drivers/mtd/ar7part.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2007 Eugene Konev <ejka@openwrt.org>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 *
  18 * TI AR7 flash partition table.
  19 * Based on ar7 map by Felix Fietkau <nbd@openwrt.org>
  20 *
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/slab.h>
  25
  26#include <linux/mtd/mtd.h>
  27#include <linux/mtd/partitions.h>
  28#include <linux/bootmem.h>
  29#include <linux/module.h>
  30
  31#include <uapi/linux/magic.h>
  32
  33#define AR7_PARTS       4
  34#define ROOT_OFFSET     0xe0000
  35
  36#define LOADER_MAGIC1   le32_to_cpu(0xfeedfa42)
  37#define LOADER_MAGIC2   le32_to_cpu(0xfeed1281)
  38
  39struct ar7_bin_rec {
  40        unsigned int checksum;
  41        unsigned int length;
  42        unsigned int address;
  43};
  44
  45static int create_mtd_partitions(struct mtd_info *master,
  46                                 const struct mtd_partition **pparts,
  47                                 struct mtd_part_parser_data *data)
  48{
  49        struct ar7_bin_rec header;
  50        unsigned int offset;
  51        size_t len;
  52        unsigned int pre_size = master->erasesize, post_size = 0;
  53        unsigned int root_offset = ROOT_OFFSET;
  54
  55        int retries = 10;
  56        struct mtd_partition *ar7_parts;
  57
  58        ar7_parts = kzalloc(sizeof(*ar7_parts) * AR7_PARTS, GFP_KERNEL);
  59        if (!ar7_parts)
  60                return -ENOMEM;
  61        ar7_parts[0].name = "loader";
  62        ar7_parts[0].offset = 0;
  63        ar7_parts[0].size = master->erasesize;
  64        ar7_parts[0].mask_flags = MTD_WRITEABLE;
  65
  66        ar7_parts[1].name = "config";
  67        ar7_parts[1].offset = 0;
  68        ar7_parts[1].size = master->erasesize;
  69        ar7_parts[1].mask_flags = 0;
  70
  71        do { /* Try 10 blocks starting from master->erasesize */
  72                offset = pre_size;
  73                mtd_read(master, offset, sizeof(header), &len,
  74                         (uint8_t *)&header);
  75                if (!strncmp((char *)&header, "TIENV0.8", 8))
  76                        ar7_parts[1].offset = pre_size;
  77                if (header.checksum == LOADER_MAGIC1)
  78                        break;
  79                if (header.checksum == LOADER_MAGIC2)
  80                        break;
  81                pre_size += master->erasesize;
  82        } while (retries--);
  83
  84        pre_size = offset;
  85
  86        if (!ar7_parts[1].offset) {
  87                ar7_parts[1].offset = master->size - master->erasesize;
  88                post_size = master->erasesize;
  89        }
  90
  91        switch (header.checksum) {
  92        case LOADER_MAGIC1:
  93                while (header.length) {
  94                        offset += sizeof(header) + header.length;
  95                        mtd_read(master, offset, sizeof(header), &len,
  96                                 (uint8_t *)&header);
  97                }
  98                root_offset = offset + sizeof(header) + 4;
  99                break;
 100        case LOADER_MAGIC2:
 101                while (header.length) {
 102                        offset += sizeof(header) + header.length;
 103                        mtd_read(master, offset, sizeof(header), &len,
 104                                 (uint8_t *)&header);
 105                }
 106                root_offset = offset + sizeof(header) + 4 + 0xff;
 107                root_offset &= ~(uint32_t)0xff;
 108                break;
 109        default:
 110                printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum);
 111                break;
 112        }
 113
 114        mtd_read(master, root_offset, sizeof(header), &len, (u8 *)&header);
 115        if (header.checksum != SQUASHFS_MAGIC) {
 116                root_offset += master->erasesize - 1;
 117                root_offset &= ~(master->erasesize - 1);
 118        }
 119
 120        ar7_parts[2].name = "linux";
 121        ar7_parts[2].offset = pre_size;
 122        ar7_parts[2].size = master->size - pre_size - post_size;
 123        ar7_parts[2].mask_flags = 0;
 124
 125        ar7_parts[3].name = "rootfs";
 126        ar7_parts[3].offset = root_offset;
 127        ar7_parts[3].size = master->size - root_offset - post_size;
 128        ar7_parts[3].mask_flags = 0;
 129
 130        *pparts = ar7_parts;
 131        return AR7_PARTS;
 132}
 133
 134static struct mtd_part_parser ar7_parser = {
 135        .parse_fn = create_mtd_partitions,
 136        .name = "ar7part",
 137};
 138module_mtd_part_parser(ar7_parser);
 139
 140MODULE_LICENSE("GPL");
 141MODULE_AUTHOR(  "Felix Fietkau <nbd@openwrt.org>, "
 142                "Eugene Konev <ejka@openwrt.org>");
 143MODULE_DESCRIPTION("MTD partitioning for TI AR7");
 144