Root/target/linux/generic/files/drivers/mtd/myloader.c

1/*
2 * Parse MyLoader-style flash partition tables and produce a Linux partition
3 * array to match.
4 *
5 * Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
6 *
7 * This file was based on drivers/mtd/redboot.c
8 * Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published
12 * by the Free Software Foundation.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/version.h>
19#include <linux/slab.h>
20#include <linux/init.h>
21#include <linux/vmalloc.h>
22#include <linux/mtd/mtd.h>
23#include <linux/mtd/partitions.h>
24#include <linux/byteorder/generic.h>
25#include <linux/myloader.h>
26
27#define BLOCK_LEN_MIN 0x10000
28#define PART_NAME_LEN 32
29
30struct part_data {
31    struct mylo_partition_table tab;
32    char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
33};
34
35#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
36static int myloader_parse_partitions(struct mtd_info *master,
37                     struct mtd_partition **pparts,
38                     struct mtd_part_parser_data *data)
39#else
40static int myloader_parse_partitions(struct mtd_info *master,
41                     struct mtd_partition **pparts,
42                     unsigned long origin)
43#endif
44{
45    struct part_data *buf;
46    struct mylo_partition_table *tab;
47    struct mylo_partition *part;
48    struct mtd_partition *mtd_parts;
49    struct mtd_partition *mtd_part;
50    int num_parts;
51    int ret, i;
52    size_t retlen;
53    char *names;
54    unsigned long offset;
55    unsigned long blocklen;
56
57    buf = vmalloc(sizeof(*buf));
58    if (!buf) {
59        return -ENOMEM;
60        goto out;
61    }
62    tab = &buf->tab;
63
64    blocklen = master->erasesize;
65    if (blocklen < BLOCK_LEN_MIN)
66        blocklen = BLOCK_LEN_MIN;
67
68    offset = blocklen;
69
70    /* Find the partition table */
71    for (i = 0; i < 4; i++, offset += blocklen) {
72        printk(KERN_DEBUG "%s: searching for MyLoader partition table"
73                " at offset 0x%lx\n", master->name, offset);
74
75        ret = mtd_read(master, offset, sizeof(*buf), &retlen,
76                   (void *)buf);
77        if (ret)
78            goto out_free_buf;
79
80        if (retlen != sizeof(*buf)) {
81            ret = -EIO;
82            goto out_free_buf;
83        }
84
85        /* Check for Partition Table magic number */
86        if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
87            break;
88
89    }
90
91    if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
92        printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
93            master->name);
94        ret = 0;
95        goto out_free_buf;
96    }
97
98    /* The MyLoader and the Partition Table is always present */
99    num_parts = 2;
100
101    /* Detect number of used partitions */
102    for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
103        part = &tab->partitions[i];
104
105        if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
106            continue;
107
108        num_parts++;
109    }
110
111    mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
112                num_parts * PART_NAME_LEN), GFP_KERNEL);
113
114    if (!mtd_parts) {
115        ret = -ENOMEM;
116        goto out_free_buf;
117    }
118
119    mtd_part = mtd_parts;
120    names = (char *)&mtd_parts[num_parts];
121
122    strncpy(names, "myloader", PART_NAME_LEN);
123    mtd_part->name = names;
124    mtd_part->offset = 0;
125    mtd_part->size = offset;
126    mtd_part->mask_flags = MTD_WRITEABLE;
127    mtd_part++;
128    names += PART_NAME_LEN;
129
130    strncpy(names, "partition_table", PART_NAME_LEN);
131    mtd_part->name = names;
132    mtd_part->offset = offset;
133    mtd_part->size = blocklen;
134    mtd_part->mask_flags = MTD_WRITEABLE;
135    mtd_part++;
136    names += PART_NAME_LEN;
137
138    for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
139        part = &tab->partitions[i];
140
141        if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
142            continue;
143
144        if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
145            strncpy(names, buf->names[i], PART_NAME_LEN);
146        else
147            snprintf(names, PART_NAME_LEN, "partition%d", i);
148
149        mtd_part->offset = le32_to_cpu(part->addr);
150        mtd_part->size = le32_to_cpu(part->size);
151        mtd_part->name = names;
152        mtd_part++;
153        names += PART_NAME_LEN;
154    }
155
156    *pparts = mtd_parts;
157    ret = num_parts;
158
159 out_free_buf:
160    vfree(buf);
161 out:
162    return ret;
163}
164
165static struct mtd_part_parser myloader_mtd_parser = {
166    .owner = THIS_MODULE,
167    .parse_fn = myloader_parse_partitions,
168    .name = "MyLoader",
169};
170
171static int __init myloader_mtd_parser_init(void)
172{
173    return register_mtd_parser(&myloader_mtd_parser);
174}
175
176static void __exit myloader_mtd_parser_exit(void)
177{
178    deregister_mtd_parser(&myloader_mtd_parser);
179}
180
181module_init(myloader_mtd_parser_init);
182module_exit(myloader_mtd_parser_exit);
183
184MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
185MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
186MODULE_LICENSE("GPL v2");
187

Archive Download this file



interactive