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
, (void *)&trx_hdr
);
58 printk(KERN_ALERT PFX
"unable to read from '%s'\n", mtd
->name
);
62 if (retlen
!= sizeof(trx_hdr
)) {
63 printk(KERN_ALERT PFX
"reading failed on '%s'\n", mtd
->name
);
67 trx_hdr
.magic
= le32_to_cpu(trx_hdr
.magic
);
68 trx_hdr
.len
= le32_to_cpu(trx_hdr
.len
);
69 trx_hdr
.crc32
= le32_to_cpu(trx_hdr
.crc32
);
70 trx_hdr
.flag_version
= le32_to_cpu(trx_hdr
.flag_version
);
71 trx_hdr
.offsets
[0] = le32_to_cpu(trx_hdr
.offsets
[0]);
72 trx_hdr
.offsets
[1] = le32_to_cpu(trx_hdr
.offsets
[1]);
73 trx_hdr
.offsets
[2] = le32_to_cpu(trx_hdr
.offsets
[2]);
76 if (trx_hdr
.magic
!= TRX_MAGIC
)
79 if (trx_hdr
.len
> mtd
->size
- offset
)
82 /* TODO: add crc32 checking too? */
90 static void trxsplit_findtrx(struct mtd_info
*mtd
)
95 printk(KERN_INFO PFX
"searching TRX header in '%s'\n", mtd
->name
);
98 for (offset
= 0; offset
< mtd
->size
; offset
+= TRX_ALIGN
) {
99 err
= trxsplit_checktrx(mtd
, offset
);
107 printk(KERN_INFO PFX
"TRX header found at 0x%lX\n", offset
);
113 static void trxsplit_create_partitions(struct mtd_info
*mtd
)
115 struct mtd_partition
*part
= trx_parts
;
119 for (i
= 0; i
< TRX_MAX_OFFSET
; i
++) {
120 part
= &trx_parts
[i
];
121 if (trx_hdr
.offsets
[i
] == 0)
123 part
->offset
= trx_offset
+ trx_hdr
.offsets
[i
];
127 for (i
= 0; i
< trx_nr_parts
-1; i
++)
128 trx_parts
[i
].size
= trx_parts
[i
+1].offset
- trx_parts
[i
].offset
;
130 trx_parts
[i
].size
= mtd
->size
- trx_parts
[i
].offset
;
133 part
= &trx_parts
[i
];
134 if (part
->size
< TRX_MIN_KERNEL_SIZE
) {
135 part
->name
= "loader";
139 part
= &trx_parts
[i
];
140 part
->name
= "kernel";
143 part
= &trx_parts
[i
];
144 part
->name
= "rootfs";
146 err
= mtd_device_register(mtd
, trx_parts
, trx_nr_parts
);
148 printk(KERN_ALERT PFX
"adding TRX partitions failed\n");
152 mtd
->refresh_device
= trxsplit_refresh_partitions
;
155 static int trxsplit_refresh_partitions(struct mtd_info
*mtd
)
157 printk(KERN_INFO PFX
"refreshing TRX partitions in '%s' (%d,%d)\n",
158 mtd
->name
, MTD_BLOCK_MAJOR
, mtd
->index
);
160 /* remove old partitions */
161 mtd_device_unregister(mtd
);
163 trxsplit_findtrx(mtd
);
167 trxsplit_create_partitions(trx_mtd
);
174 static void __init
trxsplit_add_mtd(struct mtd_info
*mtd
)
176 if (mtd
->type
!= MTD_NORFLASH
) {
177 printk(KERN_INFO PFX
"'%s' is not a NOR flash, skipped\n",
183 trxsplit_findtrx(mtd
);
186 static void __init
trxsplit_remove_mtd(struct mtd_info
*mtd
)
191 static struct mtd_notifier trxsplit_notifier __initdata
= {
192 .add
= trxsplit_add_mtd
,
193 .remove
= trxsplit_remove_mtd
,
196 static void __init
trxsplit_scan(void)
198 register_mtd_user(&trxsplit_notifier
);
199 unregister_mtd_user(&trxsplit_notifier
);
202 static int __init
trxsplit_init(void)
207 printk(KERN_INFO PFX
"creating TRX partitions in '%s' "
208 "(%d,%d)\n", trx_mtd
->name
, MTD_BLOCK_MAJOR
,
210 trxsplit_create_partitions(trx_mtd
);
216 late_initcall(trxsplit_init
);