kernel: mtdsplit: bcm_wfi: add sercomm support
[openwrt/openwrt.git] / target / linux / generic / files / drivers / mtd / mtdsplit / mtdsplit_wrgg.c
1 /*
2 * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
3 * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
4 * Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/partitions.h>
18 #include <linux/byteorder/generic.h>
19 #include <linux/of.h>
20
21 #include "mtdsplit.h"
22
23 #define WRGG_NR_PARTS 2
24 #define WRGG_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */
25 #define WRGG03_MAGIC 0x20080321
26 #define WRG_MAGIC 0x20040220
27
28 struct wrgg03_header {
29 char signature[32];
30 uint32_t magic1;
31 uint32_t magic2;
32 char version[16];
33 char model[16];
34 uint32_t flag[2];
35 uint32_t reserve[2];
36 char buildno[16];
37 uint32_t size;
38 uint32_t offset;
39 char devname[32];
40 char digest[16];
41 } __attribute__ ((packed));
42
43 struct wrg_header {
44 char signature[32];
45 uint32_t magic1;
46 uint32_t magic2;
47 uint32_t size;
48 uint32_t offset;
49 char devname[32];
50 char digest[16];
51 } __attribute__ ((packed));
52
53
54 static int mtdsplit_parse_wrgg(struct mtd_info *master,
55 const struct mtd_partition **pparts,
56 struct mtd_part_parser_data *data)
57 {
58 struct wrgg03_header hdr;
59 size_t hdr_len, retlen, kernel_ent_size;
60 size_t rootfs_offset;
61 struct mtd_partition *parts;
62 enum mtdsplit_part_type type;
63 int err;
64
65 hdr_len = sizeof(hdr);
66 err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
67 if (err)
68 return err;
69
70 if (retlen != hdr_len)
71 return -EIO;
72
73 /* sanity checks */
74 if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) {
75 kernel_ent_size = hdr_len + be32_to_cpu(hdr.size);
76 /*
77 * If this becomes silly big it's probably because the
78 * WRGG image is little-endian.
79 */
80 if (kernel_ent_size > master->size)
81 kernel_ent_size = hdr_len + le32_to_cpu(hdr.size);
82
83 /* Now what ?! It's neither */
84 if (kernel_ent_size > master->size)
85 return -EINVAL;
86 } else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) {
87 kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu(
88 ((struct wrg_header*)&hdr)->size);
89 } else {
90 return -EINVAL;
91 }
92
93 if (kernel_ent_size > master->size)
94 return -EINVAL;
95
96 /*
97 * The size in the header covers the rootfs as well.
98 * Start the search from an arbitrary offset.
99 */
100 err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS,
101 master->size, &rootfs_offset, &type);
102 if (err)
103 return err;
104
105 parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL);
106 if (!parts)
107 return -ENOMEM;
108
109 parts[0].name = KERNEL_PART_NAME;
110 parts[0].offset = 0;
111 parts[0].size = rootfs_offset;
112
113 parts[1].name = ROOTFS_PART_NAME;
114 parts[1].offset = rootfs_offset;
115 parts[1].size = master->size - rootfs_offset;
116
117 *pparts = parts;
118 return WRGG_NR_PARTS;
119 }
120
121 static const struct of_device_id mtdsplit_wrgg_of_match_table[] = {
122 { .compatible = "wrg" },
123 {},
124 };
125 MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table);
126
127 static struct mtd_part_parser mtdsplit_wrgg_parser = {
128 .owner = THIS_MODULE,
129 .name = "wrgg-fw",
130 .of_match_table = mtdsplit_wrgg_of_match_table,
131 .parse_fn = mtdsplit_parse_wrgg,
132 .type = MTD_PARSER_TYPE_FIRMWARE,
133 };
134
135 static int __init mtdsplit_wrgg_init(void)
136 {
137 register_mtd_parser(&mtdsplit_wrgg_parser);
138
139 return 0;
140 }
141
142 subsys_initcall(mtdsplit_wrgg_init);