2 * Copyright (C) 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/types.h>
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/list.h>
15 #include <linux/kmod.h>
16 #include <linux/root_dev.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/partitions.h>
21 #include <linux/byteorder/generic.h>
23 #define PFX "trxsplit: "
25 #define TRX_MAGIC 0x30524448 /* "HDR0" */
27 #define TRX_MAX_LEN 0x3A0000
28 #define TRX_NO_HEADER 0x1 /* do not write TRX header */
29 #define TRX_GZ_FILES 0x2 /* contains individual gzip files */
30 #define TRX_MAX_OFFSET 3
31 #define TRX_MIN_KERNEL_SIZE 256*1024
34 u32 magic
; /* "HDR0" */
35 u32 len
; /* Length of file including header */
36 u32 crc32
; /* 32-bit CRC from flag_version to end of file */
37 u32 flag_version
; /* 0:15 flags, 16:31 version */
38 u32 offsets
[TRX_MAX_OFFSET
]; /* Offsets of partitions */
41 #define TRX_ALIGN 0x1000
43 static int trx_nr_parts
;
44 static unsigned long trx_offset
;
45 static struct mtd_info
*trx_mtd
;
46 static struct mtd_partition trx_parts
[TRX_MAX_OFFSET
];
47 static struct trx_header trx_hdr
;
49 static int trxsplit_refresh_partitions(struct mtd_info
*mtd
);
51 static int trxsplit_checktrx(struct mtd_info
*mtd
, unsigned long offset
)
56 err
= mtd
->read(mtd
, offset
, sizeof(trx_hdr
), &retlen
,
59 printk(KERN_ALERT PFX
"unable to read from '%s'\n", mtd
->name
);
63 if (retlen
!= sizeof(trx_hdr
)) {
64 printk(KERN_ALERT PFX
"reading failed on '%s'\n", mtd
->name
);
68 trx_hdr
.magic
= le32_to_cpu(trx_hdr
.magic
);
69 trx_hdr
.len
= le32_to_cpu(trx_hdr
.len
);
70 trx_hdr
.crc32
= le32_to_cpu(trx_hdr
.crc32
);
71 trx_hdr
.flag_version
= le32_to_cpu(trx_hdr
.flag_version
);
72 trx_hdr
.offsets
[0] = le32_to_cpu(trx_hdr
.offsets
[0]);
73 trx_hdr
.offsets
[1] = le32_to_cpu(trx_hdr
.offsets
[1]);
74 trx_hdr
.offsets
[2] = le32_to_cpu(trx_hdr
.offsets
[2]);
77 if (trx_hdr
.magic
!= TRX_MAGIC
)
80 if (trx_hdr
.len
> mtd
->size
- offset
)
83 /* TODO: add crc32 checking too? */
91 static void trxsplit_findtrx(struct mtd_info
*mtd
)
96 printk(KERN_INFO PFX
"searching TRX header in '%s'\n", mtd
->name
);
99 for (offset
= 0; offset
< mtd
->size
; offset
+= TRX_ALIGN
) {
100 err
= trxsplit_checktrx(mtd
, offset
);
108 printk(KERN_INFO PFX
"TRX header found at 0x%lX\n", offset
);
114 static void trxsplit_create_partitions(struct mtd_info
*mtd
)
116 struct mtd_partition
*part
= trx_parts
;
120 for (i
= 0; i
< TRX_MAX_OFFSET
; i
++) {
121 part
= &trx_parts
[i
];
122 if (trx_hdr
.offsets
[i
] == 0)
124 part
->offset
= trx_offset
+ trx_hdr
.offsets
[i
];
128 for (i
= 0; i
< trx_nr_parts
-1; i
++)
129 trx_parts
[i
].size
= trx_parts
[i
+1].offset
- trx_parts
[i
].offset
;
131 trx_parts
[i
].size
= mtd
->size
- trx_parts
[i
].offset
;
134 part
= &trx_parts
[i
];
135 if (part
->size
< TRX_MIN_KERNEL_SIZE
) {
136 part
->name
= "loader";
140 part
= &trx_parts
[i
];
141 part
->name
= "kernel";
144 part
= &trx_parts
[i
];
145 part
->name
= "rootfs";
147 err
= add_mtd_partitions(mtd
, trx_parts
, trx_nr_parts
);
149 printk(KERN_ALERT PFX
"adding TRX partitions failed\n");
153 mtd
->refresh_device
= trxsplit_refresh_partitions
;
156 static int trxsplit_refresh_partitions(struct mtd_info
*mtd
)
158 printk(KERN_INFO PFX
"refreshing TRX partitions in '%s' (%d,%d)\n",
159 mtd
->name
, MTD_BLOCK_MAJOR
, mtd
->index
);
161 /* remove old partitions */
162 del_mtd_partitions(mtd
);
164 trxsplit_findtrx(mtd
);
168 trxsplit_create_partitions(trx_mtd
);
175 static void __init
trxsplit_add_mtd(struct mtd_info
*mtd
)
177 if (mtd
->type
!= MTD_NORFLASH
) {
178 printk(KERN_INFO PFX
"'%s' is not a NOR flash, skipped\n",
184 trxsplit_findtrx(mtd
);
187 static void __init
trxsplit_remove_mtd(struct mtd_info
*mtd
)
192 static struct mtd_notifier trxsplit_notifier __initdata
= {
193 .add
= trxsplit_add_mtd
,
194 .remove
= trxsplit_remove_mtd
,
197 static void __init
trxsplit_scan(void)
199 register_mtd_user(&trxsplit_notifier
);
200 unregister_mtd_user(&trxsplit_notifier
);
203 static int __init
trxsplit_init(void)
208 printk(KERN_INFO PFX
"creating TRX partitions in '%s' "
209 "(%d,%d)\n", trx_mtd
->name
, MTD_BLOCK_MAJOR
,
211 trxsplit_create_partitions(trx_mtd
);
217 late_initcall(trxsplit_init
);