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/slab.h>
18#include <linux/init.h>
19#include <linux/vmalloc.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/partitions.h>
22#include <linux/byteorder/generic.h>
23#include <linux/myloader.h>
24
25#define BLOCK_LEN_MIN 0x10000
26#define PART_NAME_LEN 32
27
28struct part_data {
29    struct mylo_partition_table tab;
30    char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
31};
32
33int myloader_parse_partitions(struct mtd_info *master,
34            struct mtd_partition **pparts,
35            unsigned long origin)
36{
37    struct part_data *buf;
38    struct mylo_partition_table *tab;
39    struct mylo_partition *part;
40    struct mtd_partition *mtd_parts;
41    struct mtd_partition *mtd_part;
42    int num_parts;
43    int ret, i;
44    size_t retlen;
45    char *names;
46    unsigned long offset;
47    unsigned long blocklen;
48
49    buf = vmalloc(sizeof(*buf));
50    if (!buf) {
51        return -ENOMEM;
52        goto out;
53    }
54    tab = &buf->tab;
55
56    blocklen = master->erasesize;
57    if (blocklen < BLOCK_LEN_MIN)
58        blocklen = BLOCK_LEN_MIN;
59
60    offset = blocklen;
61
62    /* Find the partition table */
63    for (i = 0; i < 4; i++, offset += blocklen) {
64        printk(KERN_DEBUG "%s: searching for MyLoader partition table"
65                " at offset 0x%lx\n", master->name, offset);
66
67        ret = master->read(master, offset, sizeof(*buf), &retlen,
68                    (void *)buf);
69        if (ret)
70            goto out_free_buf;
71
72        if (retlen != sizeof(*buf)) {
73            ret = -EIO;
74            goto out_free_buf;
75        }
76
77        /* Check for Partition Table magic number */
78        if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
79            break;
80
81    }
82
83    if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
84        printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
85            master->name);
86        ret = 0;
87        goto out_free_buf;
88    }
89
90    /* The MyLoader and the Partition Table is always present */
91    num_parts = 2;
92
93    /* Detect number of used partitions */
94    for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
95        part = &tab->partitions[i];
96
97        if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
98            continue;
99
100        num_parts++;
101    }
102
103    mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
104                num_parts * PART_NAME_LEN), GFP_KERNEL);
105
106    if (!mtd_parts) {
107        ret = -ENOMEM;
108        goto out_free_buf;
109    }
110
111    mtd_part = mtd_parts;
112    names = (char *)&mtd_parts[num_parts];
113
114    strncpy(names, "myloader", PART_NAME_LEN);
115    mtd_part->name = names;
116    mtd_part->offset = 0;
117    mtd_part->size = offset;
118    mtd_part->mask_flags = MTD_WRITEABLE;
119    mtd_part++;
120    names += PART_NAME_LEN;
121
122    strncpy(names, "partition_table", PART_NAME_LEN);
123    mtd_part->name = names;
124    mtd_part->offset = offset;
125    mtd_part->size = blocklen;
126    mtd_part->mask_flags = MTD_WRITEABLE;
127    mtd_part++;
128    names += PART_NAME_LEN;
129
130    for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
131        part = &tab->partitions[i];
132
133        if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
134            continue;
135
136        if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
137            strncpy(names, buf->names[i], PART_NAME_LEN);
138        else
139            snprintf(names, PART_NAME_LEN, "partition%d", i);
140
141        mtd_part->offset = le32_to_cpu(part->addr);
142        mtd_part->size = le32_to_cpu(part->size);
143        mtd_part->name = names;
144        mtd_part++;
145        names += PART_NAME_LEN;
146    }
147
148    *pparts = mtd_parts;
149    ret = num_parts;
150
151 out_free_buf:
152    vfree(buf);
153 out:
154    return ret;
155}
156
157static struct mtd_part_parser myloader_mtd_parser = {
158    .owner = THIS_MODULE,
159    .parse_fn = myloader_parse_partitions,
160    .name = "MyLoader",
161};
162
163static int __init myloader_mtd_parser_init(void)
164{
165    return register_mtd_parser(&myloader_mtd_parser);
166}
167
168static void __exit myloader_mtd_parser_exit(void)
169{
170    deregister_mtd_parser(&myloader_mtd_parser);
171}
172
173module_init(myloader_mtd_parser_init);
174module_exit(myloader_mtd_parser_exit);
175
176MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
177MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
178MODULE_LICENSE("GPL v2");
179

Archive Download this file



interactive