allow coexistance of N build and AC build.
[tomato.git] / release / src / router / rc / mtd.c
blob7662fcc4219d32a561c5b399e1a2ccfe4bade501
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 0x30303945: // E900 E900
325 case 0x30303145: // E100 E1000
326 case 0x30323145: // E120 E1200v1
327 case 0x32323145: // E122 E1200v2
328 case 0x30353145: // E150 E1500
329 case 0x30353531: // 1550 E1550
330 case 0x3031304D: // M010 M10
331 case 0x3032304D: // M020 M20
332 case 0x3036314E: // N160 WRT160N
333 case 0x42435745: // EWCB WRT300N v1
334 case 0x4E303133: // 310N WRT310N v1/v2
335 // case 0x32435745: // EWC2 WRT300N?
336 case 0x3035314E: // N150 WRT150N
337 case 0x58353245: // E25X E2500
338 case 0x30303233: // 3200 E3200
339 case 0x30303234: // 4200 E4200
340 if (safe_fread(((char *)&cth) + 4, 1, sizeof(cth) - 4, f) != (sizeof(cth) - 4)) {
341 goto ERROR;
343 if (memcmp(cth.id, "U2ND", 4) != 0) {
344 goto ERROR;
347 // trx should be next...
348 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
349 goto ERROR;
351 break;
352 case 0x5E24232A: // Netgear
353 // header length is next
354 if (safe_fread(&n, 1, sizeof(n), f) != sizeof(n)) {
355 goto ERROR;
357 // skip the header - we can't use seek() for fifo, so read the rest of the header
358 n = ntohl(n) - sizeof(sig) - sizeof(n);
359 if ((buf = malloc(n + 1)) == NULL) {
360 error = "Not enough memory";
361 goto ERROR;
363 if (safe_fread(buf, 1, n, f) != n) {
364 goto ERROR;
366 free(buf);
367 buf = NULL;
368 // trx should be next...
369 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
370 goto ERROR;
372 break;
373 case TRX_MAGIC:
374 break;
375 #ifdef CONFIG_BCMWL5
376 #ifndef CONFIG_BCMWL6
377 case TRX_MAGIC_F7D3301:
378 case TRX_MAGIC_F7D3302:
379 case TRX_MAGIC_F7D4302:
380 case TRX_MAGIC_F5D8235V3:
381 case TRX_MAGIC_QA:
382 sig = TRX_MAGIC;
383 break;
384 #endif
385 #endif
386 default:
387 // moto
388 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
389 goto ERROR;
391 switch (sig) {
392 case 0x50705710: // WR850G
393 // trx
394 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
395 goto ERROR;
397 break;
398 default:
399 goto ERROR;
401 break;
404 if (sig != TRX_MAGIC) {
405 goto ERROR;
407 if ((safe_fread(((char *)&trx) + 4, 1, sizeof(trx) - 4, f) != (sizeof(trx) - 4)) || (trx.len <= sizeof(trx))) {
408 goto ERROR;
411 model = get_model();
413 switch (model) {
414 #ifdef CONFIG_BCMWL5
415 #ifndef CONFIG_BCMWL6
416 case MODEL_F7D3301:
417 trx.magic = TRX_MAGIC_F7D3301;
418 break;
419 case MODEL_F7D3302:
420 trx.magic = TRX_MAGIC_F7D3302;
421 break;
422 case MODEL_F7D4302:
423 trx.magic = TRX_MAGIC_F7D4302;
424 break;
425 case MODEL_F5D8235v3:
426 trx.magic = TRX_MAGIC_F5D8235V3;
427 break;
428 #endif
429 #endif
430 default:
431 trx.magic = sig;
432 break;
435 if (!crc_init()) {
436 error = "Not enough memory";
437 goto ERROR;
439 crc = crc_calc(0xFFFFFFFF, (char *)&trx.flag_version, sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version));
441 if (trx.flag_version & TRX_NO_HEADER) {
442 trx.len -= sizeof(struct trx_header);
443 _dprintf("don't write header\n");
446 _dprintf("trx len=%db 0x%x\n", trx.len, trx.len);
448 if ((mf = mtd_open(dev, &mi)) < 0) {
449 error = "Error opening MTD device";
450 goto ERROR;
453 if (mi.erasesize < sizeof(struct trx_header)) {
454 error = "Error obtaining MTD information";
455 goto ERROR;
458 _dprintf("mtd size=%6x, erasesize=%6x\n", mi.size, mi.erasesize);
460 total = ROUNDUP(trx.len, mi.erasesize);
461 if (total > mi.size) {
462 error = "File is too big to fit in MTD";
463 goto ERROR;
466 sysinfo(&si);
467 if ((si.freeram * si.mem_unit) > (total + (256 * 1024))) {
468 ei.length = total;
470 else {
471 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
472 ei.length = mi.erasesize;
474 _dprintf("freeram=%ld ei.length=%d total=%u\n", si.freeram, ei.length, total);
476 if ((buf = malloc(ei.length)) == NULL) {
477 error = "Not enough memory";
478 goto ERROR;
481 #ifdef DEBUG_SIMULATE
482 FILE *of;
483 if ((of = fopen("/mnt/out.bin", "w")) == NULL) {
484 error = "Error creating test file";
485 goto ERROR;
487 #endif
489 if (trx.flag_version & TRX_NO_HEADER) {
490 ofs = 0;
492 else {
493 memcpy(buf, &trx, sizeof(trx));
494 ofs = sizeof(trx);
496 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx.len, trx.len, ofs, ofs);
498 error = NULL;
500 for (ei.start = 0; ei.start < total; ei.start += ei.length) {
501 n = MIN(ei.length, trx.len) - ofs;
502 if (safe_fread(buf + ofs, 1, n, f) != n) {
503 error = "Error reading file";
504 break;
506 trx.len -= (n + ofs);
508 crc = crc_calc(crc, buf + ofs, n);
510 if (trx.len == 0) {
511 _dprintf("crc=%8x trx.crc=%8x\n", crc, trx.crc32);
512 if (crc != trx.crc32) {
513 error = "Image is corrupt";
514 break;
518 if (!web) {
519 printf("Writing %x-%x\r", ei.start, (ei.start + ei.length) - 1);
522 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
523 ofs, n, n, trx.len, ei.start, ei.length, mi.erasesize);
525 n += ofs;
527 _dprintf(" erase start=%x len=%x\n", ei.start, ei.length);
528 _dprintf(" write %x\n", n);
530 #ifdef DEBUG_SIMULATE
531 if (fwrite(buf, 1, n, of) != n) {
532 fclose(of);
533 error = "Error writing to test file";
534 break;
536 #else
537 ioctl(mf, MEMUNLOCK, &ei);
538 if (ioctl(mf, MEMERASE, &ei) != 0 && model != MODEL_WNR3500LV2) {
539 error = "Error erasing MTD block";
540 break;
542 if (write(mf, buf, n) != n) {
543 error = "Error writing to MTD device";
544 break;
546 #endif
547 ofs = 0;
550 // Netgear WNR3500L: write fake len and checksum at the end of mtd
552 char *tmp;
553 char imageInfo[8];
555 switch (model) {
556 case MODEL_WNR3500L:
557 case MODEL_WNR2000v2:
558 error = "Error writing fake Netgear crc";
560 // Netgear CFE has the offset of the checksum hardcoded as
561 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
562 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
563 // We rely on linux partition to be sized correctly by the kernel,
564 // so the checksum area doesn't fall outside of the linux partition,
565 // and doesn't override the rootfs.
566 ofs = (mi.size > (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
568 n = 0x00000004; // fake length - little endian
569 crc = 0x02C0010E; // fake crc - little endian
570 memcpy(&imageInfo[0], (char *)&n, 4);
571 memcpy(&imageInfo[4], (char *)&crc, 4);
573 ei.start = (ofs / mi.erasesize) * mi.erasesize;
574 ei.length = mi.erasesize;
576 if (lseek(mf, ei.start, SEEK_SET) < 0)
577 goto ERROR2;
578 if (buf) free(buf);
579 if (!(buf = malloc(mi.erasesize)))
580 goto ERROR2;
581 if (read(mf, buf, mi.erasesize) != mi.erasesize)
582 goto ERROR2;
583 if (lseek(mf, ei.start, SEEK_SET) < 0)
584 goto ERROR2;
586 tmp = buf + (ofs % mi.erasesize);
587 memcpy(tmp, imageInfo, sizeof(imageInfo));
589 #ifdef DEBUG_SIMULATE
590 if (fseek(of, ei.start, SEEK_SET) < 0)
591 goto ERROR2;
592 if (fwrite(buf, 1, mi.erasesize, of) != n)
593 goto ERROR2;
594 #else
595 ioctl(mf, MEMUNLOCK, &ei);
596 if (ioctl(mf, MEMERASE, &ei) != 0)
597 goto ERROR2;
599 if (write(mf, buf, mi.erasesize) != mi.erasesize)
600 goto ERROR2;
601 #endif
603 ERROR2:
604 _dprintf("%s.\n", error ? : "Write Netgear fake len/crc completed");
605 // ignore crc write errors
606 error = NULL;
607 break;
610 #ifdef DEBUG_SIMULATE
611 fclose(of);
612 #endif
614 ERROR:
615 if (buf) free(buf);
616 if (mf >= 0) {
617 // dummy read to ensure chip(s) are out of lock/suspend state
618 read(mf, &n, sizeof(n));
619 close(mf);
621 if (f) fclose(f);
623 crc_done();
625 #ifdef DEBUG_SIMULATE
626 set_action(ACT_IDLE);
627 #endif
629 printf("%s\n", error ? error : "Image successfully flashed");
630 _dprintf("%s\n", error ? error : "Image successfully flashed");
631 return (error ? 1 : 0);