Merge branch 'Toastman-RT' into Toastman-RT-N
[tomato.git] / release / src / router / rc / mtd.c
blob6aa91be9a4249c2cf33d3f7ee80c509717879767
1 /*
3 Copyright 2003, CyberTAN Inc. All Rights Reserved
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
6 the contents of this file may not be disclosed to third parties,
7 copied or duplicated in any form without the prior written
8 permission of CyberTAN Inc.
10 This software should be used as a reference only, and it not
11 intended for production use!
13 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
14 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
15 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
21 Copyright 2005, Broadcom Corporation
22 All Rights Reserved.
24 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
32 Modified for Tomato Firmware
33 Portions, Copyright (C) 2006-2009 Jonathan Zarate
37 #include "rc.h"
39 #include <limits.h>
40 #include <sys/sysmacros.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <error.h>
46 #include <sys/ioctl.h>
47 #include <sys/sysinfo.h>
48 #ifdef LINUX26
49 #include <linux/compiler.h>
50 #include <mtd/mtd-user.h>
51 #else
52 #include <linux/mtd/mtd.h>
53 #endif
54 #include <stdint.h>
56 #include <trxhdr.h>
57 #include <bcmutils.h>
60 // #define DEBUG_SIMULATE
63 struct code_header {
64 char magic[4];
65 char res1[4];
66 char fwdate[3];
67 char fwvern[3];
68 char id[4];
69 char hw_ver;
70 char res2;
71 unsigned short flags;
72 unsigned char res3[10];
73 } ;
75 // -----------------------------------------------------------------------------
77 static uint32 *crc_table = NULL;
79 static void crc_done(void)
81 free(crc_table);
82 crc_table = NULL;
85 static int crc_init(void)
87 uint32 c;
88 int i, j;
90 if (crc_table == NULL) {
91 if ((crc_table = malloc(sizeof(uint32) * 256)) == NULL) return 0;
92 for (i = 255; i >= 0; --i) {
93 c = i;
94 for (j = 8; j > 0; --j) {
95 if (c & 1) c = (c >> 1) ^ 0xEDB88320L;
96 else c >>= 1;
98 crc_table[i] = c;
101 return 1;
104 static uint32 crc_calc(uint32 crc, char *buf, int len)
106 while (len-- > 0) {
107 crc = crc_table[(crc ^ *((char *)buf)) & 0xFF] ^ (crc >> 8);
108 buf++;
110 return crc;
113 // -----------------------------------------------------------------------------
115 static int mtd_open(const char *mtdname, mtd_info_t *mi)
117 char path[256];
118 int part;
119 int size;
120 int f;
122 if (mtd_getinfo(mtdname, &part, &size)) {
123 sprintf(path, MTD_DEV(%d), part);
124 if ((f = open(path, O_RDWR|O_SYNC)) >= 0) {
125 if ((mi) && ioctl(f, MEMGETINFO, mi) != 0) {
126 close(f);
127 return -1;
129 return f;
132 return -1;
135 static int _unlock_erase(const char *mtdname, int erase)
137 int mf;
138 mtd_info_t mi;
139 erase_info_t ei;
140 int r;
142 if (!wait_action_idle(5)) return 0;
143 set_action(ACT_ERASE_NVRAM);
144 if (erase) led(LED_DIAG, 1);
146 r = 0;
147 if ((mf = mtd_open(mtdname, &mi)) >= 0) {
148 r = 1;
149 #if 1
150 ei.length = mi.erasesize;
151 for (ei.start = 0; ei.start < mi.size; ei.start += mi.erasesize) {
152 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, (ei.start + ei.length) - 1);
153 fflush(stdout);
155 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
156 // perror("MEMUNLOCK");
157 // r = 0;
158 // break;
160 if (erase) {
161 if (ioctl(mf, MEMERASE, &ei) != 0) {
162 perror("MEMERASE");
163 r = 0;
164 break;
168 #else
169 ei.start = 0;
170 ei.length = mi.size;
172 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, ei.length - 1);
173 fflush(stdout);
175 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
176 perror("MEMUNLOCK");
177 r = 0;
179 else if (erase) {
180 if (ioctl(mf, MEMERASE, &ei) != 0) {
181 perror("MEMERASE");
182 r = 0;
185 #endif
187 // checkme:
188 char buf[2];
189 read(mf, &buf, sizeof(buf));
190 close(mf);
193 if (erase) led(LED_DIAG, 0);
194 set_action(ACT_IDLE);
196 if (r) printf("\"%s\" successfully %s.\n", mtdname, erase ? "erased" : "unlocked");
197 else printf("\nError %sing MTD\n", erase ? "eras" : "unlock");
199 sleep(1);
200 return r;
203 int mtd_unlock(const char *mtdname)
205 return _unlock_erase(mtdname, 0);
208 int mtd_erase(const char *mtdname)
210 return _unlock_erase(mtdname, 1);
213 int mtd_unlock_erase_main(int argc, char *argv[])
215 char c;
216 char *dev = NULL;
218 while ((c = getopt(argc, argv, "d:")) != -1) {
219 switch (c) {
220 case 'd':
221 dev = optarg;
222 break;
226 if (!dev) {
227 usage_exit(argv[0], "-d part");
230 return _unlock_erase(dev, strstr(argv[0], "erase") ? 1 : 0);
233 int mtd_write_main(int argc, char *argv[])
235 int mf = -1;
236 mtd_info_t mi;
237 erase_info_t ei;
238 uint32 sig;
239 struct trx_header trx;
240 struct code_header cth;
241 uint32 crc;
242 FILE *f;
243 char *buf = NULL;
244 const char *error;
245 uint32 total;
246 uint32 n;
247 struct sysinfo si;
248 uint32 ofs;
249 char c;
250 int web = 0;
251 char *iname = NULL;
252 char *dev = NULL;
253 int model;
255 while ((c = getopt(argc, argv, "i:d:w")) != -1) {
256 switch (c) {
257 case 'i':
258 iname = optarg;
259 break;
260 case 'd':
261 dev = optarg;
262 break;
263 case 'w':
264 web = 1;
265 break;
269 if ((iname == NULL) || (dev == NULL)) {
270 usage_exit(argv[0], "-i file -d part");
273 if (!wait_action_idle(10)) {
274 printf("System is busy\n");
275 return 1;
277 set_action(ACT_WEB_UPGRADE);
279 if ((f = fopen(iname, "r")) == NULL) {
280 error = "Error opening input file";
281 goto ERROR;
284 error = "File contains an invalid header";
286 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
287 goto ERROR;
289 switch (sig) {
290 case 0x47343557: // W54G G, GL
291 case 0x53343557: // W54S GS
292 case 0x73343557: // W54s GS v4
293 case 0x55343557: // W54U SL
294 case 0x31345257: // WR41 WRH54G
295 case 0x4E303233: // 320N WRT320N
296 case 0x4E583233: // 32XN E2000
297 case 0x4E303136: // 610N WRT610N v2
298 case 0x4E583136: // 61XN E3000
299 case 0x30303945: // E900 E900
300 case 0x30303145: // E100 E1000
301 case 0x30323145: // E120 E1200v1
302 case 0x32323145: // E122 E1200v2
303 case 0x30353145: // E150 E1500
304 case 0x30353531: // 1550 E1550
305 case 0x3031304D: // M010 M10
306 case 0x3032304D: // M020 M20
307 case 0x3036314E: // N160 WRT160N
308 case 0x42435745: // EWCB WRT300N v1
309 case 0x4E303133: // 310N WRT310N v1/v2
310 // case 0x32435745: // EWC2 WRT300N?
311 case 0x3035314E: // N150 WRT150N
312 case 0x58353245: // E25X E2500
313 case 0x30303233: // 3200 E3200
314 case 0x30303234: // 4200 E4200
315 if (safe_fread(((char *)&cth) + 4, 1, sizeof(cth) - 4, f) != (sizeof(cth) - 4)) {
316 goto ERROR;
318 if (memcmp(cth.id, "U2ND", 4) != 0) {
319 goto ERROR;
322 // trx should be next...
323 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
324 goto ERROR;
326 break;
327 case 0x5E24232A: // Netgear
328 // header length is next
329 if (safe_fread(&n, 1, sizeof(n), f) != sizeof(n)) {
330 goto ERROR;
332 // skip the header - we can't use seek() for fifo, so read the rest of the header
333 n = ntohl(n) - sizeof(sig) - sizeof(n);
334 if ((buf = malloc(n + 1)) == NULL) {
335 error = "Not enough memory";
336 goto ERROR;
338 if (safe_fread(buf, 1, n, f) != n) {
339 goto ERROR;
341 free(buf);
342 buf = NULL;
343 // trx should be next...
344 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
345 goto ERROR;
347 break;
348 case TRX_MAGIC:
349 break;
350 #ifdef CONFIG_BCMWL5
351 case TRX_MAGIC_F7D3301:
352 case TRX_MAGIC_F7D3302:
353 case TRX_MAGIC_F7D4302:
354 case TRX_MAGIC_F5D8235V3:
355 case TRX_MAGIC_QA:
356 sig = TRX_MAGIC;
357 break;
358 #endif
359 default:
360 // moto
361 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
362 goto ERROR;
364 switch (sig) {
365 case 0x50705710: // WR850G
366 // trx
367 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
368 goto ERROR;
370 break;
371 default:
372 goto ERROR;
374 break;
377 if (sig != TRX_MAGIC) {
378 goto ERROR;
380 if ((safe_fread(((char *)&trx) + 4, 1, sizeof(trx) - 4, f) != (sizeof(trx) - 4)) || (trx.len <= sizeof(trx))) {
381 goto ERROR;
384 model = get_model();
386 switch (model) {
387 #ifdef CONFIG_BCMWL5
388 case MODEL_F7D3301:
389 trx.magic = TRX_MAGIC_F7D3301;
390 break;
391 case MODEL_F7D3302:
392 trx.magic = TRX_MAGIC_F7D3302;
393 break;
394 case MODEL_F7D4302:
395 trx.magic = TRX_MAGIC_F7D4302;
396 break;
397 case MODEL_F5D8235v3:
398 trx.magic = TRX_MAGIC_F5D8235V3;
399 break;
400 #endif
401 default:
402 trx.magic = sig;
403 break;
406 if (!crc_init()) {
407 error = "Not enough memory";
408 goto ERROR;
410 crc = crc_calc(0xFFFFFFFF, (char *)&trx.flag_version, sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version));
412 if (trx.flag_version & TRX_NO_HEADER) {
413 trx.len -= sizeof(struct trx_header);
414 _dprintf("don't write header\n");
417 _dprintf("trx len=%db 0x%x\n", trx.len, trx.len);
419 if ((mf = mtd_open(dev, &mi)) < 0) {
420 error = "Error opening MTD device";
421 goto ERROR;
424 if (mi.erasesize < sizeof(struct trx_header)) {
425 error = "Error obtaining MTD information";
426 goto ERROR;
429 _dprintf("mtd size=%6x, erasesize=%6x\n", mi.size, mi.erasesize);
431 total = ROUNDUP(trx.len, mi.erasesize);
432 if (total > mi.size) {
433 error = "File is too big to fit in MTD";
434 goto ERROR;
437 sysinfo(&si);
438 if ((si.freeram * si.mem_unit) > (total + (256 * 1024))) {
439 ei.length = total;
441 else {
442 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
443 ei.length = mi.erasesize;
445 _dprintf("freeram=%ld ei.length=%d total=%u\n", si.freeram, ei.length, total);
447 if ((buf = malloc(ei.length)) == NULL) {
448 error = "Not enough memory";
449 goto ERROR;
452 #ifdef DEBUG_SIMULATE
453 FILE *of;
454 if ((of = fopen("/mnt/out.bin", "w")) == NULL) {
455 error = "Error creating test file";
456 goto ERROR;
458 #endif
460 if (trx.flag_version & TRX_NO_HEADER) {
461 ofs = 0;
463 else {
464 memcpy(buf, &trx, sizeof(trx));
465 ofs = sizeof(trx);
467 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx.len, trx.len, ofs, ofs);
469 error = NULL;
471 for (ei.start = 0; ei.start < total; ei.start += ei.length) {
472 n = MIN(ei.length, trx.len) - ofs;
473 if (safe_fread(buf + ofs, 1, n, f) != n) {
474 error = "Error reading file";
475 break;
477 trx.len -= (n + ofs);
479 crc = crc_calc(crc, buf + ofs, n);
481 if (trx.len == 0) {
482 _dprintf("crc=%8x trx.crc=%8x\n", crc, trx.crc32);
483 if (crc != trx.crc32) {
484 error = "Image is corrupt";
485 break;
489 if (!web) {
490 printf("Writing %x-%x\r", ei.start, (ei.start + ei.length) - 1);
493 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
494 ofs, n, n, trx.len, ei.start, ei.length, mi.erasesize);
496 n += ofs;
498 _dprintf(" erase start=%x len=%x\n", ei.start, ei.length);
499 _dprintf(" write %x\n", n);
501 #ifdef DEBUG_SIMULATE
502 if (fwrite(buf, 1, n, of) != n) {
503 fclose(of);
504 error = "Error writing to test file";
505 break;
507 #else
508 ioctl(mf, MEMUNLOCK, &ei);
509 if (ioctl(mf, MEMERASE, &ei) != 0 && model != MODEL_WNR3500LV2) {
510 error = "Error erasing MTD block";
511 break;
513 if (write(mf, buf, n) != n) {
514 error = "Error writing to MTD device";
515 break;
517 #endif
518 ofs = 0;
521 // Netgear WNR3500L: write fake len and checksum at the end of mtd
523 char *tmp;
524 char imageInfo[8];
526 switch (model) {
527 case MODEL_WNR3500L:
528 case MODEL_WNR2000v2:
529 error = "Error writing fake Netgear crc";
531 // Netgear CFE has the offset of the checksum hardcoded as
532 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
533 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
534 // We rely on linux partition to be sized correctly by the kernel,
535 // so the checksum area doesn't fall outside of the linux partition,
536 // and doesn't override the rootfs.
537 ofs = (mi.size > (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
539 n = 0x00000004; // fake length - little endian
540 crc = 0x02C0010E; // fake crc - little endian
541 memcpy(&imageInfo[0], (char *)&n, 4);
542 memcpy(&imageInfo[4], (char *)&crc, 4);
544 ei.start = (ofs / mi.erasesize) * mi.erasesize;
545 ei.length = mi.erasesize;
547 if (lseek(mf, ei.start, SEEK_SET) < 0)
548 goto ERROR2;
549 if (buf) free(buf);
550 if (!(buf = malloc(mi.erasesize)))
551 goto ERROR2;
552 if (read(mf, buf, mi.erasesize) != mi.erasesize)
553 goto ERROR2;
554 if (lseek(mf, ei.start, SEEK_SET) < 0)
555 goto ERROR2;
557 tmp = buf + (ofs % mi.erasesize);
558 memcpy(tmp, imageInfo, sizeof(imageInfo));
560 #ifdef DEBUG_SIMULATE
561 if (fseek(of, ei.start, SEEK_SET) < 0)
562 goto ERROR2;
563 if (fwrite(buf, 1, mi.erasesize, of) != n)
564 goto ERROR2;
565 #else
566 ioctl(mf, MEMUNLOCK, &ei);
567 if (ioctl(mf, MEMERASE, &ei) != 0)
568 goto ERROR2;
570 if (write(mf, buf, mi.erasesize) != mi.erasesize)
571 goto ERROR2;
572 #endif
574 ERROR2:
575 _dprintf("%s.\n", error ? : "Write Netgear fake len/crc completed");
576 // ignore crc write errors
577 error = NULL;
578 break;
581 #ifdef DEBUG_SIMULATE
582 fclose(of);
583 #endif
585 ERROR:
586 if (buf) free(buf);
587 if (mf >= 0) {
588 // dummy read to ensure chip(s) are out of lock/suspend state
589 read(mf, &n, sizeof(n));
590 close(mf);
592 if (f) fclose(f);
594 crc_done();
596 #ifdef DEBUG_SIMULATE
597 set_action(ACT_IDLE);
598 #endif
600 printf("%s\n", error ? error : "Image successfully flashed");
601 _dprintf("%s\n", error ? error : "Image successfully flashed");
602 return (error ? 1 : 0);