2 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/vmalloc.h>
14 #include <linux/magic.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/partitions.h>
19 #define TLT_NUM_PARTS 7
20 #define TLT_HEADER_V1 0x01000000
23 #define TLT_UBOOT_LEN 0x20000
24 #define TLT_CONFIG_LEN 0x10000
25 #define TLT_ART_LEN 0x10000
26 #define EVENTLOG_LEN 0x90000
28 struct tlt_fw_header
{
29 uint32_t version
; /* header version */
32 uint32_t hw_id
; /* hardware id */
33 uint32_t hw_rev
; /* hardware revision */
35 uint8_t md5sum1
[MD5SUM_LEN
];
37 uint8_t md5sum2
[MD5SUM_LEN
];
39 uint32_t kernel_la
; /* kernel load address */
40 uint32_t kernel_ep
; /* kernel entry point */
41 uint32_t fw_length
; /* total length of the firmware */
42 uint32_t kernel_ofs
; /* kernel data offset */
43 uint32_t kernel_len
; /* kernel data length */
44 uint32_t rootfs_ofs
; /* rootfs data offset */
45 uint32_t rootfs_len
; /* rootfs data length */
46 uint32_t boot_ofs
; /* bootloader data offset */
47 uint32_t boot_len
; /* bootloader data length */
49 } __attribute__ ((packed
));
51 static struct tlt_fw_header
*
52 tlt_read_header(struct mtd_info
*mtd
, size_t offset
)
54 struct tlt_fw_header
*header
;
60 header
= vmalloc(sizeof(*header
));
64 header_len
= sizeof(struct tlt_fw_header
);
65 ret
= mtd_read(mtd
, offset
, header_len
, &retlen
,
66 (unsigned char *) header
);
70 if (retlen
!= header_len
)
74 t
= be32_to_cpu(header
->version
);
75 if (t
!= TLT_HEADER_V1
)
78 t
= be32_to_cpu(header
->kernel_ofs
);
90 static int tlt_check_rootfs_magic(struct mtd_info
*mtd
, size_t offset
)
96 ret
= mtd_read(mtd
, offset
, sizeof(magic
), &retlen
,
97 (unsigned char *) &magic
);
101 if (retlen
!= sizeof(magic
))
104 if (le32_to_cpu(magic
) != SQUASHFS_MAGIC
&&
111 static int tlt_parse_partitions(struct mtd_info
*master
,
112 struct mtd_partition
**pparts
,
113 struct mtd_part_parser_data
*data
)
115 struct mtd_partition
*parts
;
116 struct tlt_fw_header
*header
;
118 size_t kernel_offset
;
119 size_t rootfs_offset
;
120 size_t squashfs_offset
;
123 nr_parts
= TLT_NUM_PARTS
;
124 parts
= kzalloc(nr_parts
* sizeof(struct mtd_partition
), GFP_KERNEL
);
130 kernel_offset
= TLT_UBOOT_LEN
+ TLT_CONFIG_LEN
+ TLT_ART_LEN
;
132 header
= tlt_read_header(master
, kernel_offset
);
134 pr_notice("%s: no TP-Link header found\n", master
->name
);
139 squashfs_offset
= kernel_offset
+ sizeof(struct tlt_fw_header
) +
140 be32_to_cpu(header
->kernel_len
);
142 ret
= tlt_check_rootfs_magic(master
, squashfs_offset
);
144 rootfs_offset
= squashfs_offset
;
146 rootfs_offset
= kernel_offset
+ be32_to_cpu(header
->rootfs_ofs
);
150 parts
[0].name
= "u-boot";
152 parts
[0].size
= TLT_UBOOT_LEN
;
153 parts
[0].mask_flags
= MTD_WRITEABLE
;
155 parts
[1].name
= "config";
156 parts
[1].offset
= TLT_UBOOT_LEN
;
157 parts
[1].size
= TLT_CONFIG_LEN
;
159 parts
[2].name
= "art";
160 parts
[2].offset
= TLT_UBOOT_LEN
+ TLT_CONFIG_LEN
;
161 parts
[2].size
= TLT_ART_LEN
;
162 parts
[2].mask_flags
= MTD_WRITEABLE
;
164 parts
[3].name
= "kernel";
165 parts
[3].offset
= kernel_offset
;
166 parts
[3].size
= rootfs_offset
- kernel_offset
;
168 parts
[4].name
= "rootfs";
169 parts
[4].offset
= rootfs_offset
;
170 parts
[4].size
= master
->size
- rootfs_offset
- EVENTLOG_LEN
;
172 parts
[5].name
= "firmware";
173 parts
[5].offset
= kernel_offset
;
174 parts
[5].size
= master
->size
- kernel_offset
- EVENTLOG_LEN
;
176 parts
[6].name
= "event-log";
177 parts
[6].offset
= master
->size
- EVENTLOG_LEN
;
178 parts
[6].size
= EVENTLOG_LEN
;
190 static struct mtd_part_parser tlt_parser
= {
191 .owner
= THIS_MODULE
,
192 .parse_fn
= tlt_parse_partitions
,
196 static int __init
tlt_parser_init(void)
198 register_mtd_parser(&tlt_parser
);
203 module_init(tlt_parser_init
);
205 MODULE_LICENSE("GPL v2");
206 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");