New routers supported
[tomato.git] / release / src / router / rc / mtd.c
blob4cdac738fb0183f6dcb3eb091ea0550e513ea602
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 #ifdef CONFIG_BCMWL6
141 int r, ret, skipbb;
142 #else
143 int r;
144 #endif
146 if (!wait_action_idle(5)) return 0;
147 set_action(ACT_ERASE_NVRAM);
148 if (erase) led(LED_DIAG, 1);
150 r = 0;
151 #ifdef CONFIG_BCMWL6
152 skipbb = 0;
153 #endif
154 if ((mf = mtd_open(mtdname, &mi)) >= 0) {
155 r = 1;
156 #if 1
157 ei.length = mi.erasesize;
158 for (ei.start = 0; ei.start < mi.size; ei.start += mi.erasesize) {
159 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, (ei.start + ei.length) - 1);
160 fflush(stdout);
162 #ifdef CONFIG_BCMWL6
163 if (!skipbb) {
164 loff_t offset = ei.start;
166 if ((ret = ioctl(mf, MEMGETBADBLOCK, &offset)) > 0) {
167 printf("Skipping bad block at 0x%08x\n", ei.start);
168 continue;
169 } else if (ret < 0) {
170 if (errno == EOPNOTSUPP) {
171 skipbb = 1; // Not supported by this device
172 } else {
173 perror("MEMGETBADBLOCK");
174 r = 0;
175 break;
179 #endif
180 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
181 // perror("MEMUNLOCK");
182 // r = 0;
183 // break;
185 if (erase) {
186 if (ioctl(mf, MEMERASE, &ei) != 0) {
187 perror("MEMERASE");
188 r = 0;
189 break;
193 #else
194 ei.start = 0;
195 ei.length = mi.size;
197 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, ei.length - 1);
198 fflush(stdout);
200 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
201 perror("MEMUNLOCK");
202 r = 0;
204 else if (erase) {
205 if (ioctl(mf, MEMERASE, &ei) != 0) {
206 perror("MEMERASE");
207 r = 0;
210 #endif
212 // checkme:
213 char buf[2];
214 read(mf, &buf, sizeof(buf));
215 close(mf);
218 if (erase) led(LED_DIAG, 0);
219 set_action(ACT_IDLE);
221 if (r) printf("\"%s\" successfully %s.\n", mtdname, erase ? "erased" : "unlocked");
222 else printf("\nError %sing MTD\n", erase ? "eras" : "unlock");
224 sleep(1);
225 return r;
228 int mtd_unlock(const char *mtdname)
230 return _unlock_erase(mtdname, 0);
233 int mtd_erase(const char *mtdname)
235 return _unlock_erase(mtdname, 1);
238 int mtd_unlock_erase_main(int argc, char *argv[])
240 char c;
241 char *dev = NULL;
243 while ((c = getopt(argc, argv, "d:")) != -1) {
244 switch (c) {
245 case 'd':
246 dev = optarg;
247 break;
251 if (!dev) {
252 usage_exit(argv[0], "-d part");
255 return _unlock_erase(dev, strstr(argv[0], "erase") ? 1 : 0);
258 int mtd_write_main(int argc, char *argv[])
260 int mf = -1;
261 mtd_info_t mi;
262 erase_info_t ei;
263 uint32 sig;
264 struct trx_header trx;
265 struct code_header cth;
266 uint32 crc;
267 FILE *f;
268 char *buf = NULL;
269 const char *error;
270 uint32 total;
271 uint32 n;
272 struct sysinfo si;
273 uint32 ofs;
274 char c;
275 int web = 0;
276 char *iname = NULL;
277 char *dev = NULL;
278 int model;
280 while ((c = getopt(argc, argv, "i:d:w")) != -1) {
281 switch (c) {
282 case 'i':
283 iname = optarg;
284 break;
285 case 'd':
286 dev = optarg;
287 break;
288 case 'w':
289 web = 1;
290 break;
294 if ((iname == NULL) || (dev == NULL)) {
295 usage_exit(argv[0], "-i file -d part");
298 if (!wait_action_idle(10)) {
299 printf("System is busy\n");
300 return 1;
302 set_action(ACT_WEB_UPGRADE);
304 if ((f = fopen(iname, "r")) == NULL) {
305 error = "Error opening input file";
306 goto ERROR;
309 error = "File contains an invalid header";
311 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
312 goto ERROR;
314 switch (sig) {
315 case 0x47343557: // W54G G, GL
316 case 0x53343557: // W54S GS
317 case 0x73343557: // W54s GS v4
318 case 0x55343557: // W54U SL
319 case 0x31345257: // WR41 WRH54G
320 case 0x4E303233: // 320N WRT320N
321 case 0x4E583233: // 32XN E2000
322 case 0x4E303136: // 610N WRT610N v2
323 case 0x4E583136: // 61XN E3000
324 case 0x30303845: // E800 E800
325 case 0x30303945: // E900 E900
326 case 0x30303145: // E100 E1000
327 case 0x30323145: // E120 E1200v1
328 case 0x32323145: // E122 E1200v2
329 case 0x30353145: // E150 E1500
330 case 0x30353531: // 1550 E1550
331 case 0x3031304D: // M010 M10
332 case 0x3032304D: // M020 M20
333 case 0x3036314E: // N160 WRT160N
334 case 0x42435745: // EWCB WRT300N v1
335 case 0x4E303133: // 310N WRT310N v1/v2
336 // case 0x32435745: // EWC2 WRT300N?
337 case 0x3035314E: // N150 WRT150N
338 case 0x58353245: // E25X E2500
339 case 0x30303233: // 3200 E3200
340 case 0x30303234: // 4200 E4200
341 if (safe_fread(((char *)&cth) + 4, 1, sizeof(cth) - 4, f) != (sizeof(cth) - 4)) {
342 goto ERROR;
344 if (memcmp(cth.id, "U2ND", 4) != 0) {
345 goto ERROR;
348 // trx should be next...
349 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
350 goto ERROR;
352 break;
353 case 0x5E24232A: // Netgear
354 // header length is next
355 if (safe_fread(&n, 1, sizeof(n), f) != sizeof(n)) {
356 goto ERROR;
358 // skip the header - we can't use seek() for fifo, so read the rest of the header
359 n = ntohl(n) - sizeof(sig) - sizeof(n);
360 if ((buf = malloc(n + 1)) == NULL) {
361 error = "Not enough memory";
362 goto ERROR;
364 if (safe_fread(buf, 1, n, f) != n) {
365 goto ERROR;
367 free(buf);
368 buf = NULL;
369 // trx should be next...
370 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
371 goto ERROR;
373 break;
374 case TRX_MAGIC:
375 break;
376 #ifdef CONFIG_BCMWL5
377 #ifndef CONFIG_BCMWL6
378 case TRX_MAGIC_F7D3301:
379 case TRX_MAGIC_F7D3302:
380 case TRX_MAGIC_F7D4302:
381 case TRX_MAGIC_F5D8235V3:
382 case TRX_MAGIC_QA:
383 sig = TRX_MAGIC;
384 break;
385 #endif
386 #endif
387 default:
388 // moto
389 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
390 goto ERROR;
392 switch (sig) {
393 case 0x50705710: // WR850G
394 // trx
395 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
396 goto ERROR;
398 break;
399 default:
400 goto ERROR;
402 break;
405 if (sig != TRX_MAGIC) {
406 goto ERROR;
408 if ((safe_fread(((char *)&trx) + 4, 1, sizeof(trx) - 4, f) != (sizeof(trx) - 4)) || (trx.len <= sizeof(trx))) {
409 goto ERROR;
412 model = get_model();
414 switch (model) {
415 #ifdef CONFIG_BCMWL5
416 #ifndef CONFIG_BCMWL6
417 case MODEL_F7D3301:
418 trx.magic = TRX_MAGIC_F7D3301;
419 break;
420 case MODEL_F7D3302:
421 trx.magic = TRX_MAGIC_F7D3302;
422 break;
423 case MODEL_F7D4302:
424 trx.magic = TRX_MAGIC_F7D4302;
425 break;
426 case MODEL_F5D8235v3:
427 trx.magic = TRX_MAGIC_F5D8235V3;
428 break;
429 #endif
430 #endif
431 default:
432 trx.magic = sig;
433 break;
436 if (!crc_init()) {
437 error = "Not enough memory";
438 goto ERROR;
440 crc = crc_calc(0xFFFFFFFF, (char *)&trx.flag_version, sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version));
442 if (trx.flag_version & TRX_NO_HEADER) {
443 trx.len -= sizeof(struct trx_header);
444 _dprintf("don't write header\n");
447 _dprintf("trx len=%db 0x%x\n", trx.len, trx.len);
449 if ((mf = mtd_open(dev, &mi)) < 0) {
450 error = "Error opening MTD device";
451 goto ERROR;
454 if (mi.erasesize < sizeof(struct trx_header)) {
455 error = "Error obtaining MTD information";
456 goto ERROR;
459 _dprintf("mtd size=%6x, erasesize=%6x\n", mi.size, mi.erasesize);
461 total = ROUNDUP(trx.len, mi.erasesize);
462 if (total > mi.size) {
463 error = "File is too big to fit in MTD";
464 goto ERROR;
467 sysinfo(&si);
468 if ((si.freeram * si.mem_unit) > (total + (256 * 1024))) {
469 ei.length = total;
471 else {
472 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
473 ei.length = mi.erasesize;
475 _dprintf("freeram=%ld ei.length=%d total=%u\n", si.freeram, ei.length, total);
477 if ((buf = malloc(ei.length)) == NULL) {
478 error = "Not enough memory";
479 goto ERROR;
482 #ifdef DEBUG_SIMULATE
483 FILE *of;
484 if ((of = fopen("/mnt/out.bin", "w")) == NULL) {
485 error = "Error creating test file";
486 goto ERROR;
488 #endif
490 if (trx.flag_version & TRX_NO_HEADER) {
491 ofs = 0;
493 else {
494 memcpy(buf, &trx, sizeof(trx));
495 ofs = sizeof(trx);
497 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx.len, trx.len, ofs, ofs);
499 error = NULL;
501 for (ei.start = 0; ei.start < total; ei.start += ei.length) {
502 n = MIN(ei.length, trx.len) - ofs;
503 if (safe_fread(buf + ofs, 1, n, f) != n) {
504 error = "Error reading file";
505 break;
507 trx.len -= (n + ofs);
509 crc = crc_calc(crc, buf + ofs, n);
511 if (trx.len == 0) {
512 _dprintf("crc=%8x trx.crc=%8x\n", crc, trx.crc32);
513 if (crc != trx.crc32) {
514 error = "Image is corrupt";
515 break;
519 if (!web) {
520 printf("Writing %x-%x\r", ei.start, (ei.start + ei.length) - 1);
523 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
524 ofs, n, n, trx.len, ei.start, ei.length, mi.erasesize);
526 n += ofs;
528 _dprintf(" erase start=%x len=%x\n", ei.start, ei.length);
529 _dprintf(" write %x\n", n);
531 #ifdef DEBUG_SIMULATE
532 if (fwrite(buf, 1, n, of) != n) {
533 fclose(of);
534 error = "Error writing to test file";
535 break;
537 #else
538 ioctl(mf, MEMUNLOCK, &ei);
539 if (ioctl(mf, MEMERASE, &ei) != 0 && model != MODEL_WNR3500LV2) {
540 error = "Error erasing MTD block";
541 break;
543 if (write(mf, buf, n) != n) {
544 error = "Error writing to MTD device";
545 break;
547 #endif
548 ofs = 0;
551 // Netgear WNR3500L: write fake len and checksum at the end of mtd
553 char *tmp;
554 char imageInfo[8];
556 switch (model) {
557 case MODEL_WNR3500L:
558 case MODEL_WNR2000v2:
559 error = "Error writing fake Netgear crc";
561 // Netgear CFE has the offset of the checksum hardcoded as
562 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
563 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
564 // We rely on linux partition to be sized correctly by the kernel,
565 // so the checksum area doesn't fall outside of the linux partition,
566 // and doesn't override the rootfs.
567 ofs = (mi.size > (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
569 n = 0x00000004; // fake length - little endian
570 crc = 0x02C0010E; // fake crc - little endian
571 memcpy(&imageInfo[0], (char *)&n, 4);
572 memcpy(&imageInfo[4], (char *)&crc, 4);
574 ei.start = (ofs / mi.erasesize) * mi.erasesize;
575 ei.length = mi.erasesize;
577 if (lseek(mf, ei.start, SEEK_SET) < 0)
578 goto ERROR2;
579 if (buf) free(buf);
580 if (!(buf = malloc(mi.erasesize)))
581 goto ERROR2;
582 if (read(mf, buf, mi.erasesize) != mi.erasesize)
583 goto ERROR2;
584 if (lseek(mf, ei.start, SEEK_SET) < 0)
585 goto ERROR2;
587 tmp = buf + (ofs % mi.erasesize);
588 memcpy(tmp, imageInfo, sizeof(imageInfo));
590 #ifdef DEBUG_SIMULATE
591 if (fseek(of, ei.start, SEEK_SET) < 0)
592 goto ERROR2;
593 if (fwrite(buf, 1, mi.erasesize, of) != n)
594 goto ERROR2;
595 #else
596 ioctl(mf, MEMUNLOCK, &ei);
597 if (ioctl(mf, MEMERASE, &ei) != 0)
598 goto ERROR2;
600 if (write(mf, buf, mi.erasesize) != mi.erasesize)
601 goto ERROR2;
602 #endif
604 ERROR2:
605 _dprintf("%s.\n", error ? : "Write Netgear fake len/crc completed");
606 // ignore crc write errors
607 error = NULL;
608 break;
611 #ifdef DEBUG_SIMULATE
612 fclose(of);
613 #endif
615 ERROR:
616 if (buf) free(buf);
617 if (mf >= 0) {
618 // dummy read to ensure chip(s) are out of lock/suspend state
619 read(mf, &n, sizeof(n));
620 close(mf);
622 if (f) fclose(f);
624 crc_done();
626 #ifdef DEBUG_SIMULATE
627 set_action(ACT_IDLE);
628 #endif
630 printf("%s\n", error ? error : "Image successfully flashed");
631 _dprintf("%s\n", error ? error : "Image successfully flashed");
632 return (error ? 1 : 0);