281cd2c351d2de8598e950b1848779b5a751e10c
[oweals/openwrt.git] / target / linux / ath79 / patches-5.4 / 405-mtd-tp-link-partition-parser.patch
1 --- a/drivers/mtd/parsers/Kconfig
2 +++ b/drivers/mtd/parsers/Kconfig
3 @@ -184,3 +184,9 @@ config MTD_MYLOADER_PARTS
4  
5           You will still need the parsing functions to be called by the driver
6           for your particular device. It won't happen automatically.
7 +
8 +config MTD_TPLINK_PARTS
9 +       tristate "TP-Link AR7XXX/AR9XXX partitioning support"
10 +       depends on ATH79
11 +       ---help---
12 +         TBD.
13 --- a/drivers/mtd/parsers/Makefile
14 +++ b/drivers/mtd/parsers/Makefile
15 @@ -11,3 +11,4 @@ obj-$(CONFIG_MTD_PARSER_TRX)          += parser_
16  obj-$(CONFIG_MTD_SHARPSL_PARTS)                += sharpslpart.o
17  obj-$(CONFIG_MTD_REDBOOT_PARTS)                += redboot.o
18  obj-$(CONFIG_MTD_MYLOADER_PARTS)               += myloader.o
19 +obj-$(CONFIG_MTD_TPLINK_PARTS)         += tplinkpart.o
20 --- /dev/null
21 +++ b/drivers/mtd/parsers/tplinkpart.c
22 @@ -0,0 +1,222 @@
23 +/*
24 + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
25 + *
26 + * This program is free software; you can redistribute it and/or modify it
27 + * under the terms of the GNU General Public License version 2 as published
28 + * by the Free Software Foundation.
29 + */
30 +
31 +#include <linux/kernel.h>
32 +#include <linux/module.h>
33 +#include <linux/slab.h>
34 +#include <linux/vmalloc.h>
35 +#include <linux/magic.h>
36 +
37 +#include <linux/mtd/mtd.h>
38 +#include <linux/mtd/partitions.h>
39 +#include <linux/version.h>
40 +
41 +#define TPLINK_NUM_PARTS       5
42 +#define TPLINK_HEADER_V1       0x01000000
43 +#define TPLINK_HEADER_V2       0x02000000
44 +#define MD5SUM_LEN             16
45 +
46 +#define TPLINK_ART_LEN         0x10000
47 +#define TPLINK_KERNEL_OFFS     0x20000
48 +#define TPLINK_64K_KERNEL_OFFS 0x10000
49 +
50 +struct tplink_fw_header {
51 +       uint32_t        version;        /* header version */
52 +       char            vendor_name[24];
53 +       char            fw_version[36];
54 +       uint32_t        hw_id;          /* hardware id */
55 +       uint32_t        hw_rev;         /* hardware revision */
56 +       uint32_t        unk1;
57 +       uint8_t         md5sum1[MD5SUM_LEN];
58 +       uint32_t        unk2;
59 +       uint8_t         md5sum2[MD5SUM_LEN];
60 +       uint32_t        unk3;
61 +       uint32_t        kernel_la;      /* kernel load address */
62 +       uint32_t        kernel_ep;      /* kernel entry point */
63 +       uint32_t        fw_length;      /* total length of the firmware */
64 +       uint32_t        kernel_ofs;     /* kernel data offset */
65 +       uint32_t        kernel_len;     /* kernel data length */
66 +       uint32_t        rootfs_ofs;     /* rootfs data offset */
67 +       uint32_t        rootfs_len;     /* rootfs data length */
68 +       uint32_t        boot_ofs;       /* bootloader data offset */
69 +       uint32_t        boot_len;       /* bootloader data length */
70 +       uint8_t         pad[360];
71 +} __attribute__ ((packed));
72 +
73 +static struct tplink_fw_header *
74 +tplink_read_header(struct mtd_info *mtd, size_t offset)
75 +{
76 +       struct tplink_fw_header *header;
77 +       size_t header_len;
78 +       size_t retlen;
79 +       int ret;
80 +       u32 t;
81 +
82 +       header = vmalloc(sizeof(*header));
83 +       if (!header)
84 +               goto err;
85 +
86 +       header_len = sizeof(struct tplink_fw_header);
87 +       ret = mtd_read(mtd, offset, header_len, &retlen,
88 +                      (unsigned char *) header);
89 +       if (ret)
90 +               goto err_free_header;
91 +
92 +       if (retlen != header_len)
93 +               goto err_free_header;
94 +
95 +       /* sanity checks */
96 +       t = be32_to_cpu(header->version);
97 +       if ((t != TPLINK_HEADER_V1) && (t != TPLINK_HEADER_V2))
98 +               goto err_free_header;
99 +
100 +       t = be32_to_cpu(header->kernel_ofs);
101 +       if (t != header_len)
102 +               goto err_free_header;
103 +
104 +       return header;
105 +
106 +err_free_header:
107 +       vfree(header);
108 +err:
109 +       return NULL;
110 +}
111 +
112 +static int tplink_check_rootfs_magic(struct mtd_info *mtd, size_t offset)
113 +{
114 +       u32 magic;
115 +       size_t retlen;
116 +       int ret;
117 +
118 +       ret = mtd_read(mtd, offset, sizeof(magic), &retlen,
119 +                      (unsigned char *) &magic);
120 +       if (ret)
121 +               return ret;
122 +
123 +       if (retlen != sizeof(magic))
124 +               return -EIO;
125 +
126 +       if (le32_to_cpu(magic) != SQUASHFS_MAGIC &&
127 +           magic != 0x19852003)
128 +               return -EINVAL;
129 +
130 +       return 0;
131 +}
132 +
133 +static int tplink_parse_partitions_offset(struct mtd_info *master,
134 +                                  const struct mtd_partition **pparts,
135 +                                  struct mtd_part_parser_data *data,
136 +                                  size_t offset)
137 +{
138 +       struct mtd_partition *parts;
139 +       struct tplink_fw_header *header;
140 +       int nr_parts;
141 +       size_t art_offset;
142 +       size_t rootfs_offset;
143 +       size_t squashfs_offset;
144 +       int ret;
145 +
146 +       nr_parts = TPLINK_NUM_PARTS;
147 +       parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL);
148 +       if (!parts) {
149 +               ret = -ENOMEM;
150 +               goto err;
151 +       }
152 +
153 +       header = tplink_read_header(master, offset);
154 +       if (!header) {
155 +               pr_notice("%s: no TP-Link header found\n", master->name);
156 +               ret = -ENODEV;
157 +               goto err_free_parts;
158 +       }
159 +
160 +       squashfs_offset = offset + sizeof(struct tplink_fw_header) +
161 +                         be32_to_cpu(header->kernel_len);
162 +
163 +       ret = tplink_check_rootfs_magic(master, squashfs_offset);
164 +       if (ret == 0)
165 +               rootfs_offset = squashfs_offset;
166 +       else
167 +               rootfs_offset = offset + be32_to_cpu(header->rootfs_ofs);
168 +
169 +       art_offset = master->size - TPLINK_ART_LEN;
170 +
171 +       parts[0].name = "u-boot";
172 +       parts[0].offset = 0;
173 +       parts[0].size = offset;
174 +       parts[0].mask_flags = MTD_WRITEABLE;
175 +
176 +       parts[1].name = "kernel";
177 +       parts[1].offset = offset;
178 +       parts[1].size = rootfs_offset - offset;
179 +
180 +       parts[2].name = "rootfs";
181 +       parts[2].offset = rootfs_offset;
182 +       parts[2].size = art_offset - rootfs_offset;
183 +
184 +       parts[3].name = "art";
185 +       parts[3].offset = art_offset;
186 +       parts[3].size = TPLINK_ART_LEN;
187 +       parts[3].mask_flags = MTD_WRITEABLE;
188 +
189 +       parts[4].name = "firmware";
190 +       parts[4].offset = offset;
191 +       parts[4].size = art_offset - offset;
192 +
193 +       vfree(header);
194 +
195 +       *pparts = parts;
196 +       return nr_parts;
197 +
198 +err_free_parts:
199 +       kfree(parts);
200 +err:
201 +       *pparts = NULL;
202 +       return ret;
203 +}
204 +
205 +static int tplink_parse_partitions(struct mtd_info *master,
206 +                                  const struct mtd_partition **pparts,
207 +                                  struct mtd_part_parser_data *data)
208 +{
209 +       return tplink_parse_partitions_offset(master, pparts, data,
210 +                                             TPLINK_KERNEL_OFFS);
211 +}
212 +
213 +static int tplink_parse_64k_partitions(struct mtd_info *master,
214 +                                  const struct mtd_partition **pparts,
215 +                                  struct mtd_part_parser_data *data)
216 +{
217 +       return tplink_parse_partitions_offset(master, pparts, data,
218 +                                             TPLINK_64K_KERNEL_OFFS);
219 +}
220 +
221 +static struct mtd_part_parser tplink_parser = {
222 +       .owner          = THIS_MODULE,
223 +       .parse_fn       = tplink_parse_partitions,
224 +       .name           = "tp-link",
225 +};
226 +
227 +static struct mtd_part_parser tplink_64k_parser = {
228 +       .owner          = THIS_MODULE,
229 +       .parse_fn       = tplink_parse_64k_partitions,
230 +       .name           = "tp-link-64k",
231 +};
232 +
233 +static int __init tplink_parser_init(void)
234 +{
235 +       register_mtd_parser(&tplink_parser);
236 +       register_mtd_parser(&tplink_64k_parser);
237 +
238 +       return 0;
239 +}
240 +
241 +module_init(tplink_parser_init);
242 +
243 +MODULE_LICENSE("GPL v2");
244 +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");