kernel: update mtdsplit for linux 4.9
[openwrt/staging/dedeckeh.git] / target / linux / generic / files / drivers / mtd / mtdsplit / mtdsplit_eva.c
1 /*
2 * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
3 * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation.
8 *
9 */
10
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <linux/mtd/mtd.h>
16 #include <linux/mtd/partitions.h>
17 #include <linux/byteorder/generic.h>
18
19 #include "mtdsplit.h"
20
21 #define EVA_NR_PARTS 2
22 #define EVA_MAGIC 0xfeed1281
23 #define EVA_FOOTER_SIZE 0x18
24 #define EVA_DUMMY_SQUASHFS_SIZE 0x100
25
26 struct eva_image_header {
27 uint32_t magic;
28 uint32_t size;
29 };
30
31 static int mtdsplit_parse_eva(struct mtd_info *master,
32 const struct mtd_partition **pparts,
33 struct mtd_part_parser_data *data)
34 {
35 struct mtd_partition *parts;
36 struct eva_image_header hdr;
37 size_t retlen;
38 unsigned long kernel_size, rootfs_offset;
39 int err;
40
41 err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr);
42 if (err)
43 return err;
44
45 if (retlen != sizeof(hdr))
46 return -EIO;
47
48 if (le32_to_cpu(hdr.magic) != EVA_MAGIC)
49 return -EINVAL;
50
51 kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE;
52
53 /* rootfs starts at the next 0x10000 boundary: */
54 rootfs_offset = round_up(kernel_size, 0x10000);
55
56 /* skip the dummy EVA squashfs partition (with wrong endianness): */
57 rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE;
58
59 if (rootfs_offset >= master->size)
60 return -EINVAL;
61
62 err = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
63 if (err)
64 return err;
65
66 parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
67 if (!parts)
68 return -ENOMEM;
69
70 parts[0].name = KERNEL_PART_NAME;
71 parts[0].offset = 0;
72 parts[0].size = kernel_size;
73
74 parts[1].name = ROOTFS_PART_NAME;
75 parts[1].offset = rootfs_offset;
76 parts[1].size = master->size - rootfs_offset;
77
78 *pparts = parts;
79 return EVA_NR_PARTS;
80 }
81
82 static struct mtd_part_parser mtdsplit_eva_parser = {
83 .owner = THIS_MODULE,
84 .name = "eva-fw",
85 .parse_fn = mtdsplit_parse_eva,
86 .type = MTD_PARSER_TYPE_FIRMWARE,
87 };
88
89 static int __init mtdsplit_eva_init(void)
90 {
91 register_mtd_parser(&mtdsplit_eva_parser);
92
93 return 0;
94 }
95
96 subsys_initcall(mtdsplit_eva_init);