enable start-stop-daemon by default, i want to use this to clean up a few init script...
[openwrt/staging/florian.git] / target / linux / rdc-2.6 / files / drivers / mtd / maps / rdc3210.c
1 /*******************************************************************
2 * Simple Flash mapping for RDC3210 *
3 * *
4 * 2005.03.23 *
5 * Dante Su (dante_su@gemtek.com.tw) *
6 * Copyright (C) 2005 Gemtek Corporation *
7 *******************************************************************/
8
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <asm/io.h>
13 #include <linux/mtd/mtd.h>
14 #include <linux/mtd/map.h>
15 #include <linux/mtd/partitions.h>
16 #include <linux/autoconf.h>
17 #include <linux/sched.h>
18 #include <linux/squashfs_fs.h>
19
20 static struct mtd_info *rdc3210_mtd;
21
22 struct map_info rdc3210_map =
23 {
24 .name = "RDC3210 Flash",
25 .size = CONFIG_MTD_RDC3210_SIZE,
26 .bankwidth = CONFIG_MTD_RDC3210_BUSWIDTH,
27 };
28
29 /* Dante: This is the default static mapping, however this is nothing but a hint. (Say dynamic mapping) */
30 static struct mtd_partition rdc3210_parts[] =
31 {
32 #if CONFIG_MTD_RDC3210_SIZE == 0x400000
33 { name: "linux", offset: 0, size: 0x003C0000 }, /* 3840 KB = (Kernel + ROMFS) = (768 KB + 3072 KB) */
34 { name: "romfs", offset: 0x000C0000, size: 0x00300000 }, /* 3072 KB */
35 { name: "nvram", offset: 0x003C0000, size: 0x00010000 }, /* 64 KB */
36 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
37 { name: "factory", offset: 0x003D0000, size: 0x00010000 }, /* 64 KB */
38 #endif
39 { name: "bootldr", offset: 0x003E0000, size: 0x00020000 }, /* 128 KB */
40 #elif CONFIG_MTD_RDC3210_SIZE == 0x200000
41 { name: "linux", offset: 0x00008000, size: 0x001E8000 },
42 { name: "romfs", offset: 0x000C8000, size: 0x00128000 },
43 { name: "nvram", offset: 0x00000000, size: 0x00008000 }, /* 64 KB */
44 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
45 #error Unsupported configuration!
46 #endif
47 { name: "bootldr", offset: 0x001F0000, size: 0x00010000 },
48 #else
49 #error Unsupported configuration!
50 #endif
51 };
52
53 static __u32 crctab[257] = {
54 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
55 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
56 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
57 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
58 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
59 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
60 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
61 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
62 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
63 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
64 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
65 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
66 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
67 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
68 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
69 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
70 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
71 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
72 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
73 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
74 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
75 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
76 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
77 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
78 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
79 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
80 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
81 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
82 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
83 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
84 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
85 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
86 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
87 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
88 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
89 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
90 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
91 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
92 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
93 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
94 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
95 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
96 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
97 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
98 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
99 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
100 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
101 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
102 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
103 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
104 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
105 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
106 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
107 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
108 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
109 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
110 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
111 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
112 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
113 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
114 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
115 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
116 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
117 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
118 0
119 };
120
121 static __u32 crc32(__u8 * buf, __u32 len)
122 {
123 register int i;
124 __u32 sum;
125 register __u32 s0;
126 s0 = ~0;
127 for (i = 0; i < len; i++) {
128 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
129 }
130 sum = ~s0;
131 return sum;
132 }
133
134 static void erase_callback(struct erase_info *done)
135 {
136 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
137 wake_up(wait_q);
138 }
139
140 static int erase_write (struct mtd_info *mtd, unsigned long pos,
141 int len, const char *buf)
142 {
143 struct erase_info erase;
144 DECLARE_WAITQUEUE(wait, current);
145 wait_queue_head_t wait_q;
146 size_t retlen;
147 int ret;
148
149 /*
150 * First, let's erase the flash block.
151 */
152
153 init_waitqueue_head(&wait_q);
154 erase.mtd = mtd;
155 erase.callback = erase_callback;
156 erase.addr = pos;
157 erase.len = len;
158 erase.priv = (u_long)&wait_q;
159
160 set_current_state(TASK_INTERRUPTIBLE);
161 add_wait_queue(&wait_q, &wait);
162
163 ret = mtd->erase(mtd, &erase);
164 if (ret) {
165 set_current_state(TASK_RUNNING);
166 remove_wait_queue(&wait_q, &wait);
167 printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
168 "on \"%s\" failed\n",
169 pos, len, mtd->name);
170 return ret;
171 }
172
173 schedule(); /* Wait for erase to finish. */
174 remove_wait_queue(&wait_q, &wait);
175
176 /*
177 * Next, writhe data to flash.
178 */
179
180 ret = mtd->write (mtd, pos, len, &retlen, buf);
181 if (ret)
182 return ret;
183 if (retlen != len)
184 return -EIO;
185 return 0;
186 }
187
188 static int __init init_rdc3210_map(void)
189 {
190 rdc3210_map.phys = -rdc3210_map.size;
191 printk(KERN_NOTICE "flash device: %x at %x\n", rdc3210_map.size, rdc3210_map.phys);
192
193 rdc3210_map.map_priv_1 = (unsigned long)(rdc3210_map.virt = ioremap_nocache(rdc3210_map.phys, rdc3210_map.size));
194
195 if (!rdc3210_map.map_priv_1)
196 {
197 printk("Failed to ioremap\n");
198 return -EIO;
199 }
200 rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
201 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP /* Dante: This is for fixed map */
202 if (rdc3210_mtd)
203 {
204 rdc3210_mtd->module = THIS_MODULE;
205 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
206 return 0;
207 }
208 #else /* Dante: This is for dynamic mapping */
209
210 #include "imghdr.h"
211
212 typedef struct {
213 u8 magic[4];
214 u32 kernelsz, ramdisksz;
215 u8 magic2[4];
216 u32 sz2;
217 }sc_imghdr_t;
218
219 if (rdc3210_mtd)
220 { // Dante
221 sc_imghdr_t *hdr2= (sc_imghdr_t *)(rdc3210_map.map_priv_1);
222 gt_imghdr_t *hdr = (gt_imghdr_t *)hdr2
223 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
224 , *ptmp
225 #endif
226 ;
227 int len, tmp, tmp2, tmp3, tmp4, hdr_type = 0;
228
229 if(!memcmp(hdr->magic, GTIMG_MAGIC, 4))
230 {
231 hdr_type = 1;
232 tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
233 tmp2 = rdc3210_mtd->erasesize;
234 tmp3 = ((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32;
235 tmp4 = ((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2;
236 }
237 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
238 else if (!memcmp(hdr2->magic, "CSYS", 4))
239 {
240 hdr_type = 2;
241 tmp = hdr2->ramdisksz + hdr2->kernelsz + sizeof(sc_imghdr_t);
242 tmp2 = rdc3210_mtd->erasesize;
243 tmp3 = ((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32;
244 tmp4 = ((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2;
245 }
246 #endif
247 else
248 {
249 iounmap((void *)rdc3210_map.map_priv_1);
250 rdc3210_map.map_priv_1 = 0L;
251 rdc3210_map.virt = NULL;
252 printk("Invalid MAGIC for Firmware Image!!!\n");
253 return -EIO;
254 }
255 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
256 tmp = (tmp3 == tmp4) ? tmp4 + tmp2 : tmp4;
257 if ((ptmp = (gt_imghdr_t *)vmalloc(tmp)) == NULL)
258 {
259 iounmap((void *)rdc3210_map.map_priv_1);
260 rdc3210_map.map_priv_1 = 0L;
261 rdc3210_map.virt = NULL;
262 printk("Can't allocate 0x%08x for flash-reading buffer!\n", tmp);
263 return -ENOMEM;
264 }
265 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp, &len, (__u8 *)ptmp) || len != tmp)
266 {
267 vfree(ptmp);
268 iounmap((void *)rdc3210_map.map_priv_1);
269 rdc3210_map.map_priv_1 = 0L;
270 rdc3210_map.virt = NULL;
271 printk("Can't read that much flash! Read 0x%08x of it.\n", len);
272 return -EIO;
273 }
274 #endif
275 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
276 /* 1. Adjust Redboot */
277 tmp = rdc3210_mtd->size - rdc3210_parts[4].size;
278 rdc3210_parts[4].offset = tmp - (tmp % tmp2);
279 rdc3210_parts[4].size = rdc3210_mtd->size - rdc3210_parts[4].offset;
280
281 /* 2. Adjust Factory Default */
282 tmp -= rdc3210_parts[3].size;
283 rdc3210_parts[3].offset = tmp - (tmp % tmp2);
284 rdc3210_parts[3].size = rdc3210_parts[4].offset - rdc3210_parts[3].offset;
285 #else
286 /* 1. Adjust Redboot */
287 tmp = rdc3210_mtd->size - rdc3210_parts[3].size;
288 rdc3210_parts[3].offset = tmp - (tmp % tmp2);
289 rdc3210_parts[3].size = rdc3210_mtd->size - rdc3210_parts[3].offset;
290 #endif
291 if (hdr_type == 1) {
292 /* 3. Adjust NVRAM */
293 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
294 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
295 {
296 len = 1;
297 tmp4 = tmp3;
298 tmp = hdr->imagesz;
299 rdc3210_parts[2].name = "rootfs_data";
300 rdc3210_parts[2].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
301 }
302 else
303 #else
304 tmp4 = tmp3;
305 #endif
306 {
307 len = 0;
308 tmp -= rdc3210_parts[2].size;
309 rdc3210_parts[2].offset = tmp - (tmp % tmp2);
310 }
311 rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
312 }
313 else if (hdr_type == 2)
314 {
315 len = 0;
316 tmp4 = tmp3;
317 }
318
319 /* 4. Adjust Linux (Kernel + ROMFS) */
320 rdc3210_parts[0].size = rdc3210_parts[len + hdr_type + 1].offset - rdc3210_parts[0].offset;
321
322 /* 5. Adjust ROMFS */
323 rdc3210_parts[1].offset = rdc3210_parts[0].offset + tmp4;
324 rdc3210_parts[1].size = rdc3210_parts[hdr_type + 1].offset - rdc3210_parts[1].offset;
325 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
326 if (!(hdr->reserved || len))
327 {
328 __u8 buf[1024];
329 ptmp->reserved = hdr->imagesz;
330 ptmp->imagesz = tmp4;
331 ptmp->checksum = ptmp->fastcksum = 0;
332 memcpy(buf, ptmp, 0x100);
333 memcpy(buf + 0x100, ((__u8 *)ptmp) + ((tmp4 >> 1) - ((tmp4 & 0x6) >> 1)), 0x100);
334 memcpy(buf + 0x200, ((__u8 *)ptmp) + (tmp4 - 0x200), 0x200);
335 ptmp->fastcksum = crc32(buf, sizeof(buf));
336 ptmp->checksum = crc32((__u8 *)ptmp, tmp4);
337 if (rdc3210_mtd->unlock) rdc3210_mtd->unlock(rdc3210_mtd, 0, tmp2);
338 if ((len = erase_write(rdc3210_mtd, 0, tmp2, (char *)ptmp)))
339 {
340 vfree(ptmp);
341 iounmap((void *)rdc3210_map.map_priv_1);
342 rdc3210_map.map_priv_1 = 0L;
343 rdc3210_map.virt = NULL;
344 printk("Couldn't erase! Got %d.\n", len);
345 return len;
346 }
347 if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
348 }
349 vfree(ptmp);
350 #endif
351 rdc3210_mtd->owner = THIS_MODULE;
352 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
353 return 0;
354 }
355 #endif
356 iounmap((void *)rdc3210_map.map_priv_1);
357 rdc3210_map.map_priv_1 = 0L;
358 rdc3210_map.virt = NULL;
359 return -ENXIO;
360 }
361
362 static void __exit cleanup_rdc3210_map(void)
363 {
364 if (rdc3210_mtd)
365 {
366 del_mtd_partitions(rdc3210_mtd);
367 map_destroy(rdc3210_mtd);
368 }
369
370 if (rdc3210_map.map_priv_1)
371 {
372 iounmap((void *)rdc3210_map.map_priv_1);
373 rdc3210_map.map_priv_1 = 0L;
374 rdc3210_map.virt = NULL;
375 }
376 }
377
378 module_init(init_rdc3210_map);
379 module_exit(cleanup_rdc3210_map);