2 * Copyright (C) 2013 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/module.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/mtd/mtd.h>
15 #include <linux/mtd/partitions.h>
16 #include <linux/byteorder/generic.h>
20 #define SEAMA_MAGIC 0x5EA3A417
21 #define SEAMA_NR_PARTS 2
22 #define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */
25 __be32 magic
; /* should always be SEAMA_MAGIC. */
26 __be16 reserved
; /* reserved for */
27 __be16 metasize
; /* size of the META data */
28 __be32 size
; /* size of the image */
29 u8 md5
[16]; /* digest */
32 static int mtdsplit_parse_seama(struct mtd_info
*master
,
33 struct mtd_partition
**pparts
,
34 struct mtd_part_parser_data
*data
)
36 struct seama_header hdr
;
37 size_t hdr_len
, retlen
, kernel_ent_size
;
39 struct mtd_partition
*parts
;
40 enum mtdsplit_part_type type
;
43 hdr_len
= sizeof(hdr
);
44 err
= mtd_read(master
, 0, hdr_len
, &retlen
, (void *) &hdr
);
48 if (retlen
!= hdr_len
)
52 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
)
55 kernel_ent_size
= hdr_len
+ be32_to_cpu(hdr
.size
) +
56 be16_to_cpu(hdr
.metasize
);
57 if (kernel_ent_size
> master
->size
)
60 /* Check for the rootfs right after Seama entity with a kernel. */
61 err
= mtd_check_rootfs_magic(master
, kernel_ent_size
, &type
);
63 rootfs_offset
= kernel_ent_size
;
66 * On some devices firmware entity might contain both: kernel
67 * and rootfs. We can't determine kernel size so we just have to
68 * look for rootfs magic.
69 * Start the search from an arbitrary offset.
71 err
= mtd_find_rootfs_from(master
, SEAMA_MIN_ROOTFS_OFFS
,
72 master
->size
, &rootfs_offset
, &type
);
77 parts
= kzalloc(SEAMA_NR_PARTS
* sizeof(*parts
), GFP_KERNEL
);
81 parts
[0].name
= KERNEL_PART_NAME
;
82 parts
[0].offset
= sizeof hdr
+ be16_to_cpu(hdr
.metasize
);
83 parts
[0].size
= rootfs_offset
- parts
[0].offset
;
85 if (type
== MTDSPLIT_PART_TYPE_UBI
)
86 parts
[1].name
= UBI_PART_NAME
;
88 parts
[1].name
= ROOTFS_PART_NAME
;
89 parts
[1].offset
= rootfs_offset
;
90 parts
[1].size
= master
->size
- rootfs_offset
;
93 return SEAMA_NR_PARTS
;
96 static struct mtd_part_parser mtdsplit_seama_parser
= {
99 .parse_fn
= mtdsplit_parse_seama
,
100 .type
= MTD_PARSER_TYPE_FIRMWARE
,
103 static int __init
mtdsplit_seama_init(void)
105 register_mtd_parser(&mtdsplit_seama_parser
);
110 subsys_initcall(mtdsplit_seama_init
);