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 modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #include <linux/list.h>
18 #include <linux/kmod.h>
19 #include <linux/root_dev.h>
21 #include <linux/mtd/mtd.h>
22 #include <linux/mtd/partitions.h>
24 #include <linux/byteorder/generic.h>
26 #define PFX "trxsplit: "
28 #define TRX_MAGIC 0x30524448 /* "HDR0" */
30 #define TRX_MAX_LEN 0x3A0000
31 #define TRX_NO_HEADER 0x1 /* do not write TRX header */
32 #define TRX_GZ_FILES 0x2 /* contains individual gzip files */
33 #define TRX_MAX_OFFSET 3
34 #define TRX_MIN_KERNEL_SIZE 256*1024
37 u32 magic
; /* "HDR0" */
38 u32 len
; /* Length of file including header */
39 u32 crc32
; /* 32-bit CRC from flag_version to end of file */
40 u32 flag_version
; /* 0:15 flags, 16:31 version */
41 u32 offsets
[TRX_MAX_OFFSET
]; /* Offsets of partitions */
44 #define TRX_ALIGN 0x1000
46 static int trx_nr_parts
;
47 static unsigned long trx_offset
;
48 static struct mtd_info
*trx_mtd
;
49 static struct mtd_partition trx_parts
[TRX_MAX_OFFSET
];
50 static struct trx_header trx_hdr
;
52 static int trxsplit_refresh_partitions(struct mtd_info
*mtd
);
54 static int trxsplit_checktrx(struct mtd_info
*mtd
, unsigned long offset
)
59 err
= mtd
->read(mtd
, offset
, sizeof(trx_hdr
), &retlen
,
62 printk(KERN_ALERT PFX
"unable to read from '%s'\n", mtd
->name
);
66 if (retlen
!= sizeof(trx_hdr
)) {
67 printk(KERN_ALERT PFX
"reading failed on '%s'\n", mtd
->name
);
71 trx_hdr
.magic
= le32_to_cpu(trx_hdr
.magic
);
72 trx_hdr
.len
= le32_to_cpu(trx_hdr
.len
);
73 trx_hdr
.crc32
= le32_to_cpu(trx_hdr
.crc32
);
74 trx_hdr
.flag_version
= le32_to_cpu(trx_hdr
.flag_version
);
75 trx_hdr
.offsets
[0] = le32_to_cpu(trx_hdr
.offsets
[0]);
76 trx_hdr
.offsets
[1] = le32_to_cpu(trx_hdr
.offsets
[1]);
77 trx_hdr
.offsets
[2] = le32_to_cpu(trx_hdr
.offsets
[2]);
80 if (trx_hdr
.magic
!= TRX_MAGIC
)
83 if (trx_hdr
.len
> mtd
->size
- offset
)
86 /* TODO: add crc32 checking too? */
94 static void trxsplit_findtrx(struct mtd_info
*mtd
)
99 printk(KERN_INFO PFX
"searching TRX header in '%s'\n", mtd
->name
);
102 for (offset
= 0; offset
< mtd
->size
; offset
+= TRX_ALIGN
) {
103 err
= trxsplit_checktrx(mtd
, offset
);
111 printk(KERN_INFO PFX
"TRX header found at 0x%lX\n", offset
);
117 static void trxsplit_create_partitions(struct mtd_info
*mtd
)
119 struct mtd_partition
*part
= trx_parts
;
123 for (i
= 0; i
< TRX_MAX_OFFSET
; i
++) {
124 part
= &trx_parts
[i
];
125 if (trx_hdr
.offsets
[i
] == 0)
127 part
->offset
= trx_offset
+ trx_hdr
.offsets
[i
];
131 for (i
= 0; i
< trx_nr_parts
-1; i
++)
132 trx_parts
[i
].size
= trx_parts
[i
+1].offset
- trx_parts
[i
].offset
;
134 trx_parts
[i
].size
= mtd
->size
- trx_parts
[i
].offset
;
137 part
= &trx_parts
[i
];
138 if (part
->size
< TRX_MIN_KERNEL_SIZE
) {
139 part
->name
= "loader";
143 part
= &trx_parts
[i
];
144 part
->name
= "kernel";
147 part
= &trx_parts
[i
];
148 part
->name
= "rootfs";
150 err
= add_mtd_partitions(mtd
, trx_parts
, trx_nr_parts
);
152 printk(KERN_ALERT PFX
"adding TRX partitions failed\n");
156 mtd
->refresh_device
= trxsplit_refresh_partitions
;
159 static int trxsplit_refresh_partitions(struct mtd_info
*mtd
)
161 printk(KERN_INFO PFX
"refreshing TRX partitions in '%s' (%d,%d)\n",
162 mtd
->name
, MTD_BLOCK_MAJOR
, mtd
->index
);
164 /* remove old partitions */
165 del_mtd_partitions(mtd
);
167 trxsplit_findtrx(mtd
);
171 trxsplit_create_partitions(trx_mtd
);
178 static void __init
trxsplit_add_mtd(struct mtd_info
*mtd
)
180 if (mtd
->type
!= MTD_NORFLASH
) {
181 printk(KERN_INFO PFX
"'%s' is not a NOR flash, skipped\n",
187 trxsplit_findtrx(mtd
);
190 static void __init
trxsplit_remove_mtd(struct mtd_info
*mtd
)
195 static struct mtd_notifier trxsplit_notifier __initdata
= {
196 .add
= trxsplit_add_mtd
,
197 .remove
= trxsplit_remove_mtd
,
200 static void __init
trxsplit_scan(void)
202 register_mtd_user(&trxsplit_notifier
);
203 unregister_mtd_user(&trxsplit_notifier
);
206 static int __init
trxsplit_init(void)
211 printk(KERN_INFO PFX
"creating TRX partitions in '%s' "
212 "(%d,%d)\n", trx_mtd
->name
, MTD_BLOCK_MAJOR
,
214 trxsplit_create_partitions(trx_mtd
);
220 late_initcall(trxsplit_init
);