kernel: move mtdsplit files to drivers/mtd/mtdsplit/ to simplify maintenance, unify...
[openwrt.git] / target / linux / generic / files / drivers / mtd / mtdsplit / mtdsplit_lzma.c
1 /*
2  *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
3  *
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.
7  *
8  */
9
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
17 #include <asm/unaligned.h>
18
19 #include "mtdsplit.h"
20
21 #define LZMA_NR_PARTS           2
22 #define LZMA_PROPERTIES_SIZE    5
23
24 struct lzma_header {
25         u8 props[LZMA_PROPERTIES_SIZE];
26         u8 size_low[4];
27         u8 size_high[4];
28 };
29
30 static int mtdsplit_parse_lzma(struct mtd_info *master,
31                                struct mtd_partition **pparts,
32                                struct mtd_part_parser_data *data)
33 {
34         struct lzma_header hdr;
35         size_t hdr_len, retlen;
36         size_t rootfs_offset;
37         u32 t;
38         struct mtd_partition *parts;
39         int err;
40
41         hdr_len = sizeof(hdr);
42         err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
43         if (err)
44                 return err;
45
46         if (retlen != hdr_len)
47                 return -EIO;
48
49         /* verify LZMA properties */
50         if (hdr.props[0] >= (9 * 5 * 5))
51                 return -EINVAL;
52
53         t = get_unaligned_le32(&hdr.props[1]);
54         if (!is_power_of_2(t))
55                 return -EINVAL;
56
57         t = get_unaligned_le32(&hdr.size_high);
58         if (t)
59                 return -EINVAL;
60
61         err = mtd_find_rootfs_from(master, master->erasesize,
62                                    master->size, &rootfs_offset);
63         if (err)
64                 return err;
65
66         parts = kzalloc(LZMA_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 = rootfs_offset;
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 LZMA_NR_PARTS;
80 }
81
82 static struct mtd_part_parser mtdsplit_lzma_parser = {
83         .owner = THIS_MODULE,
84         .name = "lzma-fw",
85         .parse_fn = mtdsplit_parse_lzma,
86         .type = MTD_PARSER_TYPE_FIRMWARE,
87 };
88
89 static int __init mtdsplit_lzma_init(void)
90 {
91         register_mtd_parser(&mtdsplit_lzma_parser);
92
93         return 0;
94 }
95
96 subsys_initcall(mtdsplit_lzma_init);