MiniDLNA update: 1.0.19.1 to 1.0.20
[tomato.git] / release / src / router / rc / mtd.c
blob483b2295300f54b8d8fe6745b669362e7bc5350f
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 0x30303145: // E100 E1000
300 case 0x3031304D: // M010 M10
301 case 0x3032304D: // M020 M20
302 case 0x3036314E: // N160 WRT160N
303 case 0x42435745: // EWCB WRT300N v1
304 case 0x4E303133: // 310N WRT310N v1/v2
305 // case 0x32435745: // EWC2 WRT300N?
306 case 0x3035314E: // N150 WRT150N
307 case 0x30303234: // 4200 E4200
308 if (safe_fread(((char *)&cth) + 4, 1, sizeof(cth) - 4, f) != (sizeof(cth) - 4)) {
309 goto ERROR;
311 if (memcmp(cth.id, "U2ND", 4) != 0) {
312 goto ERROR;
315 // trx should be next...
316 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
317 goto ERROR;
319 break;
320 case 0x5E24232A: // Netgear
321 // header length is next
322 if (safe_fread(&n, 1, sizeof(n), f) != sizeof(n)) {
323 goto ERROR;
325 // skip the header - we can't use seek() for fifo, so read the rest of the header
326 n = ntohl(n) - sizeof(sig) - sizeof(n);
327 if ((buf = malloc(n + 1)) == NULL) {
328 error = "Not enough memory";
329 goto ERROR;
331 if (safe_fread(buf, 1, n, f) != n) {
332 goto ERROR;
334 free(buf);
335 buf = NULL;
336 // trx should be next...
337 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
338 goto ERROR;
340 break;
341 case TRX_MAGIC:
342 break;
343 #ifdef CONFIG_BCMWL5
344 case TRX_MAGIC_F7D3301:
345 case TRX_MAGIC_F7D3302:
346 case TRX_MAGIC_F7D4302:
347 case TRX_MAGIC_F5D8235V3:
348 case TRX_MAGIC_QA:
349 sig = TRX_MAGIC;
350 break;
351 #endif
352 default:
353 // moto
354 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
355 goto ERROR;
357 switch (sig) {
358 case 0x50705710: // WR850G
359 // trx
360 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
361 goto ERROR;
363 break;
364 default:
365 goto ERROR;
367 break;
370 if (sig != TRX_MAGIC) {
371 goto ERROR;
373 if ((safe_fread(((char *)&trx) + 4, 1, sizeof(trx) - 4, f) != (sizeof(trx) - 4)) || (trx.len <= sizeof(trx))) {
374 goto ERROR;
377 model = get_model();
379 switch (model) {
380 #ifdef CONFIG_BCMWL5
381 case MODEL_F7D3301:
382 trx.magic = TRX_MAGIC_F7D3301;
383 break;
384 case MODEL_F7D3302:
385 trx.magic = TRX_MAGIC_F7D3302;
386 break;
387 case MODEL_F7D4302:
388 trx.magic = TRX_MAGIC_F7D4302;
389 break;
390 case MODEL_F5D8235v3:
391 trx.magic = TRX_MAGIC_F5D8235V3;
392 break;
393 #endif
394 default:
395 trx.magic = sig;
396 break;
399 if (!crc_init()) {
400 error = "Not enough memory";
401 goto ERROR;
403 crc = crc_calc(0xFFFFFFFF, (char *)&trx.flag_version, sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version));
405 if (trx.flag_version & TRX_NO_HEADER) {
406 trx.len -= sizeof(struct trx_header);
407 _dprintf("don't write header\n");
410 _dprintf("trx len=%db 0x%x\n", trx.len, trx.len);
412 if ((mf = mtd_open(dev, &mi)) < 0) {
413 error = "Error opening MTD device";
414 goto ERROR;
417 if (mi.erasesize < sizeof(struct trx_header)) {
418 error = "Error obtaining MTD information";
419 goto ERROR;
422 _dprintf("mtd size=%6x, erasesize=%6x\n", mi.size, mi.erasesize);
424 total = ROUNDUP(trx.len, mi.erasesize);
425 if (total > mi.size) {
426 error = "File is too big to fit in MTD";
427 goto ERROR;
430 sysinfo(&si);
431 if ((si.freeram * si.mem_unit) > (total + (256 * 1024))) {
432 ei.length = total;
434 else {
435 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
436 ei.length = mi.erasesize;
438 _dprintf("freeram=%ld ei.length=%d total=%u\n", si.freeram, ei.length, total);
440 if ((buf = malloc(ei.length)) == NULL) {
441 error = "Not enough memory";
442 goto ERROR;
445 #ifdef DEBUG_SIMULATE
446 FILE *of;
447 if ((of = fopen("/mnt/out.bin", "w")) == NULL) {
448 error = "Error creating test file";
449 goto ERROR;
451 #endif
453 if (trx.flag_version & TRX_NO_HEADER) {
454 ofs = 0;
456 else {
457 memcpy(buf, &trx, sizeof(trx));
458 ofs = sizeof(trx);
460 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx.len, trx.len, ofs, ofs);
462 error = NULL;
464 for (ei.start = 0; ei.start < total; ei.start += ei.length) {
465 n = MIN(ei.length, trx.len) - ofs;
466 if (safe_fread(buf + ofs, 1, n, f) != n) {
467 error = "Error reading file";
468 break;
470 trx.len -= (n + ofs);
472 crc = crc_calc(crc, buf + ofs, n);
474 if (trx.len == 0) {
475 _dprintf("crc=%8x trx.crc=%8x\n", crc, trx.crc32);
476 if (crc != trx.crc32) {
477 error = "Image is corrupt";
478 break;
482 if (!web) {
483 printf("Writing %x-%x\r", ei.start, (ei.start + ei.length) - 1);
486 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
487 ofs, n, n, trx.len, ei.start, ei.length, mi.erasesize);
489 n += ofs;
491 _dprintf(" erase start=%x len=%x\n", ei.start, ei.length);
492 _dprintf(" write %x\n", n);
494 #ifdef DEBUG_SIMULATE
495 if (fwrite(buf, 1, n, of) != n) {
496 fclose(of);
497 error = "Error writing to test file";
498 break;
500 #else
501 ioctl(mf, MEMUNLOCK, &ei);
502 if (ioctl(mf, MEMERASE, &ei) != 0) {
503 error = "Error erasing MTD block";
504 break;
506 if (write(mf, buf, n) != n) {
507 error = "Error writing to MTD device";
508 break;
510 #endif
511 ofs = 0;
514 // Netgear WNR3500L: write fake len and checksum at the end of mtd
516 char *tmp;
517 char imageInfo[8];
519 switch (model) {
520 case MODEL_WNR3500L:
521 case MODEL_WNR2000v2:
522 error = "Error writing fake Netgear crc";
524 // Netgear CFE has the offset of the checksum hardcoded as
525 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
526 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
527 // We rely on linux partition to be sized correctly by the kernel,
528 // so the checksum area doesn't fall outside of the linux partition,
529 // and doesn't override the rootfs.
530 ofs = (mi.size > (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
532 n = 0x00000004; // fake length - little endian
533 crc = 0x02C0010E; // fake crc - little endian
534 memcpy(&imageInfo[0], (char *)&n, 4);
535 memcpy(&imageInfo[4], (char *)&crc, 4);
537 ei.start = (ofs / mi.erasesize) * mi.erasesize;
538 ei.length = mi.erasesize;
540 if (lseek(mf, ei.start, SEEK_SET) < 0)
541 goto ERROR2;
542 if (buf) free(buf);
543 if (!(buf = malloc(mi.erasesize)))
544 goto ERROR2;
545 if (read(mf, buf, mi.erasesize) != mi.erasesize)
546 goto ERROR2;
547 if (lseek(mf, ei.start, SEEK_SET) < 0)
548 goto ERROR2;
550 tmp = buf + (ofs % mi.erasesize);
551 memcpy(tmp, imageInfo, sizeof(imageInfo));
553 #ifdef DEBUG_SIMULATE
554 if (fseek(of, ei.start, SEEK_SET) < 0)
555 goto ERROR2;
556 if (fwrite(buf, 1, mi.erasesize, of) != n)
557 goto ERROR2;
558 #else
559 ioctl(mf, MEMUNLOCK, &ei);
560 if (ioctl(mf, MEMERASE, &ei) != 0)
561 goto ERROR2;
563 if (write(mf, buf, mi.erasesize) != mi.erasesize)
564 goto ERROR2;
565 #endif
567 ERROR2:
568 _dprintf("%s.\n", error ? : "Write Netgear fake len/crc completed");
569 // ignore crc write errors
570 error = NULL;
571 break;
574 #ifdef DEBUG_SIMULATE
575 fclose(of);
576 #endif
578 ERROR:
579 if (buf) free(buf);
580 if (mf >= 0) {
581 // dummy read to ensure chip(s) are out of lock/suspend state
582 read(mf, &n, sizeof(n));
583 close(mf);
585 if (f) fclose(f);
587 crc_done();
589 #ifdef DEBUG_SIMULATE
590 set_action(ACT_IDLE);
591 #endif
593 printf("%s\n", error ? error : "Image successfully flashed");
594 _dprintf("%s\n", error ? error : "Image successfully flashed");
595 return (error ? 1 : 0);