4 * Copyright (C) 2007 OpenWrt.org
5 * Copyright (C) Gabor Juhos <juhosg at openwrt.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <linux/list.h>
28 #include <linux/kmod.h>
29 #include <linux/root_dev.h>
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/partitions.h>
34 #include <linux/byteorder/generic.h>
36 #define PFX "trxsplit: "
38 #define TRX_MAGIC 0x30524448 /* "HDR0" */
40 #define TRX_MAX_LEN 0x3A0000
41 #define TRX_NO_HEADER 1 /* Do not write TRX header */
42 #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
43 #define TRX_MAX_OFFSET 3
44 #define TRX_MIN_KERNEL_SIZE 256*1024
47 u32 magic
; /* "HDR0" */
48 u32 len
; /* Length of file including header */
49 u32 crc32
; /* 32-bit CRC from flag_version to end of file */
50 u32 flag_version
; /* 0:15 flags, 16:31 version */
51 u32 offsets
[TRX_MAX_OFFSET
]; /* Offsets of partitions from start of header */
54 #define BLOCK_LEN_MIN 0x10000
56 static struct mtd_info
*trx_mtd
= NULL
;
57 static unsigned long trx_offset
= 0;
58 static int trx_nr_parts
= 0;
59 static struct mtd_partition trx_parts
[TRX_MAX_OFFSET
];
60 static struct trx_header trx_hdr
;
62 static int __init
trxsplit_checktrx(struct mtd_info
*mtd
, unsigned long offset
)
67 err
= mtd
->read(mtd
, offset
, sizeof(trx_hdr
), &retlen
, (void *)&trx_hdr
);
69 printk(KERN_ALERT PFX
"unable to read from '%s'\n", mtd
->name
);
73 if (retlen
!= sizeof(trx_hdr
)) {
74 printk(KERN_ALERT PFX
"reading failed on '%s'\n", mtd
->name
);
78 trx_hdr
.magic
= le32_to_cpu(trx_hdr
.magic
);
79 trx_hdr
.len
= le32_to_cpu(trx_hdr
.len
);
80 trx_hdr
.crc32
= le32_to_cpu(trx_hdr
.crc32
);
81 trx_hdr
.flag_version
= le32_to_cpu(trx_hdr
.flag_version
);
82 trx_hdr
.offsets
[0] = le32_to_cpu(trx_hdr
.offsets
[0]);
83 trx_hdr
.offsets
[1] = le32_to_cpu(trx_hdr
.offsets
[1]);
84 trx_hdr
.offsets
[2] = le32_to_cpu(trx_hdr
.offsets
[2]);
87 if (trx_hdr
.magic
!= TRX_MAGIC
)
90 if (trx_hdr
.len
> mtd
->size
- offset
)
93 /* TODO: add crc32 checking too? */
101 static int __init
trxsplit_create_partitions(void)
103 struct mtd_partition
*part
= trx_parts
;
110 printk(KERN_INFO PFX
"creating TRX partitions in '%s' (%d,%d)\n",
111 trx_mtd
->name
, MTD_BLOCK_MAJOR
, trx_mtd
->index
);
113 for (i
=0; i
<TRX_MAX_OFFSET
;i
++) {
114 part
= &trx_parts
[i
];
115 if (trx_hdr
.offsets
[i
] == 0)
117 part
->offset
= trx_offset
+ trx_hdr
.offsets
[i
];
121 for (i
=0; i
<trx_nr_parts
-1; i
++) {
122 trx_parts
[i
].size
= trx_parts
[i
+1].offset
- trx_parts
[i
].offset
;
124 trx_parts
[i
].size
= trx_mtd
->size
- trx_parts
[i
].offset
;
127 part
= &trx_parts
[i
];
128 if (part
->size
< TRX_MIN_KERNEL_SIZE
) {
129 part
->name
= "loader";
133 part
= &trx_parts
[i
];
134 part
->name
= "kernel";
137 part
= &trx_parts
[i
];
138 part
->name
= "rootfs";
140 ret
= add_mtd_partitions(trx_mtd
, trx_parts
, trx_nr_parts
);
142 printk(KERN_ALERT PFX
"creating TRX partitions failed\n");
149 static void __init
trxsplit_add_mtd(struct mtd_info
*mtd
)
151 unsigned long offset
;
152 unsigned long blocklen
;
158 blocklen
= mtd
->erasesize
;
159 if (blocklen
< BLOCK_LEN_MIN
)
160 blocklen
= BLOCK_LEN_MIN
;
162 printk(KERN_INFO PFX
"searching TRX header in '%s'\n", mtd
->name
);
165 for (offset
=0; offset
< mtd
->size
; offset
+=blocklen
) {
166 err
= trxsplit_checktrx(mtd
, offset
);
172 printk(KERN_ALERT PFX
"no TRX header found\n");
176 printk(KERN_INFO PFX
"TRX header found at 0x%lX\n", offset
);
182 static void __init
trxsplit_remove_mtd(struct mtd_info
*mtd
)
187 static struct mtd_notifier trxsplit_notifier __initdata
= {
188 .add
= trxsplit_add_mtd
,
189 .remove
= trxsplit_remove_mtd
,
192 static void __init
trxsplit_find_trx(void)
194 register_mtd_user(&trxsplit_notifier
);
195 unregister_mtd_user(&trxsplit_notifier
);
198 static int __init
trxsplit_init(void)
204 ret
= trxsplit_create_partitions();
208 late_initcall(trxsplit_init
);