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>
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.
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>
23 #define WRGG_NR_PARTS 2
24 #define WRGG_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */
25 #define WRGG03_MAGIC 0x20080321
26 #define WRG_MAGIC 0x20040220
28 struct wrgg03_header
{
41 } __attribute__ ((packed
));
51 } __attribute__ ((packed
));
54 static int mtdsplit_parse_wrgg(struct mtd_info
*master
,
55 const struct mtd_partition
**pparts
,
56 struct mtd_part_parser_data
*data
)
58 struct wrgg03_header hdr
;
59 size_t hdr_len
, retlen
, kernel_ent_size
;
61 struct mtd_partition
*parts
;
62 enum mtdsplit_part_type type
;
65 hdr_len
= sizeof(hdr
);
66 err
= mtd_read(master
, 0, hdr_len
, &retlen
, (void *) &hdr
);
70 if (retlen
!= hdr_len
)
74 if (le32_to_cpu(hdr
.magic1
) == WRGG03_MAGIC
) {
75 kernel_ent_size
= hdr_len
+ be32_to_cpu(hdr
.size
);
77 * If this becomes silly big it's probably because the
78 * WRGG image is little-endian.
80 if (kernel_ent_size
> master
->size
)
81 kernel_ent_size
= hdr_len
+ le32_to_cpu(hdr
.size
);
83 /* Now what ?! It's neither */
84 if (kernel_ent_size
> master
->size
)
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
);
93 if (kernel_ent_size
> master
->size
)
97 * The size in the header covers the rootfs as well.
98 * Start the search from an arbitrary offset.
100 err
= mtd_find_rootfs_from(master
, WRGG_MIN_ROOTFS_OFFS
,
101 master
->size
, &rootfs_offset
, &type
);
105 parts
= kzalloc(WRGG_NR_PARTS
* sizeof(*parts
), GFP_KERNEL
);
109 parts
[0].name
= KERNEL_PART_NAME
;
111 parts
[0].size
= rootfs_offset
;
113 parts
[1].name
= ROOTFS_PART_NAME
;
114 parts
[1].offset
= rootfs_offset
;
115 parts
[1].size
= master
->size
- rootfs_offset
;
118 return WRGG_NR_PARTS
;
121 static const struct of_device_id mtdsplit_wrgg_of_match_table
[] = {
122 { .compatible
= "wrg" },
125 MODULE_DEVICE_TABLE(of
, mtdsplit_wrgg_of_match_table
);
127 static struct mtd_part_parser mtdsplit_wrgg_parser
= {
128 .owner
= THIS_MODULE
,
130 .of_match_table
= mtdsplit_wrgg_of_match_table
,
131 .parse_fn
= mtdsplit_parse_wrgg
,
132 .type
= MTD_PARSER_TYPE_FIRMWARE
,
135 static int __init
mtdsplit_wrgg_init(void)
137 register_mtd_parser(&mtdsplit_wrgg_parser
);
142 subsys_initcall(mtdsplit_wrgg_init
);