Allow flashing with Netgear .chk images
[tomato.git] / release / src / router / rc / mtd.c
blob3c89dc16c60fced12680e49f307e5e149919d05c
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, void *buf, int len)
106 while (len-- > 0) {
107 crc = crc_table[(crc ^ *((char *)buf)) & 0xFF] ^ (crc >> 8);
108 (char *)buf++;
110 return crc;
113 // -----------------------------------------------------------------------------
116 int mtd_getinfo(const char *mtdname, int *part, int *size)
118 FILE *f;
119 char s[256];
120 char t[256];
121 int r;
123 r = 0;
124 if ((strlen(mtdname) < 128) && (strcmp(mtdname, "pmon") != 0)) {
125 sprintf(t, "\"%s\"", mtdname);
126 if ((f = fopen("/proc/mtd", "r")) != NULL) {
127 while (fgets(s, sizeof(s), f) != NULL) {
128 if ((sscanf(s, "mtd%d: %x", part, size) == 2) && (strstr(s, t) != NULL)) {
129 // don't accidentally mess with bl (0)
130 if (*part > 0) r = 1;
131 break;
134 fclose(f);
137 if (!r) {
138 *size = 0;
139 *part = -1;
141 return r;
144 static int mtd_open(const char *mtdname)
146 char path[256];
147 int part;
148 int size;
150 if (mtd_getinfo(mtdname, &part, &size)) {
151 sprintf(path, MTD_DEV(%d), part);
152 return open(path, O_RDWR|O_SYNC);
154 return -1;
157 static int _unlock_erase(const char *mtdname, int erase)
159 int mf;
160 mtd_info_t mi;
161 erase_info_t ei;
162 int r;
164 if (!wait_action_idle(5)) return 0;
165 set_action(ACT_ERASE_NVRAM);
166 if (erase) led(LED_DIAG, 1);
168 r = 0;
169 if ((mf = mtd_open(mtdname)) >= 0) {
170 if (ioctl(mf, MEMGETINFO, &mi) == 0) {
171 r = 1;
172 #if 1
173 ei.length = mi.erasesize;
174 for (ei.start = 0; ei.start < mi.size; ei.start += mi.erasesize) {
175 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, (ei.start + ei.length) - 1);
176 fflush(stdout);
178 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
179 // perror("MEMUNLOCK");
180 // r = 0;
181 // break;
183 if (erase) {
184 if (ioctl(mf, MEMERASE, &ei) != 0) {
185 perror("MEMERASE");
186 r = 0;
187 break;
191 #else
192 ei.start = 0;
193 ei.length = mi.size;
195 printf("%sing 0x%x - 0x%x\n", erase ? "Eras" : "Unlock", ei.start, ei.length - 1);
196 fflush(stdout);
198 if (ioctl(mf, MEMUNLOCK, &ei) != 0) {
199 perror("MEMUNLOCK");
200 r = 0;
202 else if (erase) {
203 if (ioctl(mf, MEMERASE, &ei) != 0) {
204 perror("MEMERASE");
205 r = 0;
208 #endif
210 // checkme:
211 char buf[2];
212 read(mf, &buf, sizeof(buf));
214 close(mf);
217 if (erase) led(LED_DIAG, 0);
218 set_action(ACT_IDLE);
220 if (r) printf("\"%s\" successfully %s.\n", mtdname, erase ? "erased" : "unlocked");
221 else printf("\nError %sing MTD\n", erase ? "eras" : "unlock");
223 sleep(1);
224 return r;
227 int mtd_unlock(const char *mtdname)
229 return _unlock_erase(mtdname, 0);
232 int mtd_erase(const char *mtdname)
234 return _unlock_erase(mtdname, 1);
237 int mtd_unlock_erase_main(int argc, char *argv[])
239 char c;
240 char *dev = NULL;
242 while ((c = getopt(argc, argv, "d:")) != -1) {
243 switch (c) {
244 case 'd':
245 dev = optarg;
246 break;
250 if (!dev) {
251 usage_exit(argv[0], "-d part");
254 return _unlock_erase(dev, strstr(argv[0], "erase") ? 1 : 0);
257 int mtd_write_main(int argc, char *argv[])
259 int mf = -1;
260 mtd_info_t mi;
261 erase_info_t ei;
262 uint32 sig;
263 struct trx_header trx;
264 struct code_header cth;
265 uint32 crc;
266 FILE *f;
267 char *buf = NULL;
268 const char *error;
269 uint32 total;
270 uint32 n;
271 struct sysinfo si;
272 uint32 ofs;
273 char c;
274 int web = 0;
275 char *iname = NULL;
276 char *dev = NULL;
278 while ((c = getopt(argc, argv, "i:d:w")) != -1) {
279 switch (c) {
280 case 'i':
281 iname = optarg;
282 break;
283 case 'd':
284 dev = optarg;
285 break;
286 case 'w':
287 web = 1;
288 break;
292 if ((iname == NULL) || (dev == NULL)) {
293 usage_exit(argv[0], "-i file -d part");
296 if (!wait_action_idle(10)) {
297 printf("System is busy\n");
298 return 1;
300 set_action(ACT_WEB_UPGRADE);
302 if ((f = fopen(iname, "r")) == NULL) {
303 error = "Error opening input file";
304 goto ERROR;
307 error = "File contains an invalid header";
309 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
310 goto ERROR;
312 switch (sig) {
313 case 0x47343557: // W54G G, GL
314 case 0x53343557: // W54S GS
315 case 0x73343557: // W54s GS v4
316 case 0x55343557: // W54U SL
317 case 0x31345257: // WR41 WRH54G
318 #if TOMATO_N
319 case 0x42435745: // EWCB WRT300N v1
320 // case 0x32435745: // EWC2 WRT300N?
321 case 0x3035314E: // N150 WRT150N
322 #endif
323 if (safe_fread(((char *)&cth) + 4, 1, sizeof(cth) - 4, f) != (sizeof(cth) - 4)) {
324 goto ERROR;
326 if (memcmp(cth.id, "U2ND", 4) != 0) {
327 goto ERROR;
330 // trx should be next...
331 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
332 goto ERROR;
334 break;
335 case 0x5E24232A: // Netgear
336 // header length is next
337 if (safe_fread(&n, 1, sizeof(n), f) != sizeof(n)) {
338 goto ERROR;
340 // skip the header
341 if (fseek(f, ntohl(n), SEEK_SET) != 0) {
342 goto ERROR;
344 // trx should be next...
345 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
346 goto ERROR;
348 break;
349 case TRX_MAGIC:
350 break;
351 default:
352 // moto
353 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
354 goto ERROR;
356 switch (sig) {
357 case 0x50705710: // WR850G
358 // trx
359 if (safe_fread(&sig, 1, sizeof(sig), f) != sizeof(sig)) {
360 goto ERROR;
362 break;
363 default:
364 goto ERROR;
366 break;
369 if (sig != TRX_MAGIC) {
370 goto ERROR;
372 if ((safe_fread(((char *)&trx) + 4, 1, sizeof(trx) - 4, f) != (sizeof(trx) - 4)) || (trx.len <= sizeof(trx))) {
373 goto ERROR;
375 trx.magic = sig;
377 if (!crc_init()) {
378 error = "Not enough memory";
379 goto ERROR;
381 crc = crc_calc(0xFFFFFFFF, (uint8*)&trx.flag_version, sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version));
383 if (trx.flag_version & TRX_NO_HEADER) {
384 trx.len -= sizeof(struct trx_header);
385 _dprintf("don't write header\n");
388 _dprintf("trx len=%db 0x%x\n", trx.len, trx.len);
390 if ((mf = mtd_open(dev)) < 0) {
391 error = "Error opening MTD device";
392 goto ERROR;
395 if ((ioctl(mf, MEMGETINFO, &mi) != 0) || (mi.erasesize < sizeof(struct trx_header))) {
396 error = "Error obtaining MTD information";
397 goto ERROR;
400 _dprintf("mtd size=%6x, erasesize=%6x\n", mi.size, mi.erasesize);
402 total = ROUNDUP(trx.len, mi.erasesize);
403 if (total > mi.size) {
404 error = "File is too big to fit in MTD";
405 goto ERROR;
408 sysinfo(&si);
409 if ((si.freeram * si.mem_unit) > (total + (256 * 1024))) {
410 ei.length = total;
412 else {
413 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
414 ei.length = mi.erasesize;
416 _dprintf("freeram=%ld ei.length=%d total=%u\n", si.freeram, ei.length, total);
418 if ((buf = malloc(ei.length)) == NULL) {
419 error = "Not enough memory";
420 goto ERROR;
423 #ifdef DEBUG_SIMULATE
424 FILE *of;
425 if ((of = fopen("/mnt/out.bin", "w")) == NULL) {
426 error = "Error creating test file";
427 goto ERROR;
429 #endif
431 if (trx.flag_version & TRX_NO_HEADER) {
432 ofs = 0;
434 else {
435 memcpy(buf, &trx, sizeof(trx));
436 ofs = sizeof(trx);
438 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx.len, trx.len, ofs, ofs);
440 error = NULL;
442 for (ei.start = 0; ei.start < total; ei.start += ei.length) {
443 n = MIN(ei.length, trx.len) - ofs;
444 if (safe_fread(buf + ofs, 1, n, f) != n) {
445 error = "Error reading file";
446 break;
448 trx.len -= (n + ofs);
450 crc = crc_calc(crc, buf + ofs, n);
452 if (trx.len == 0) {
453 _dprintf("crc=%8x trx.crc=%8x\n", crc, trx.crc32);
454 if (crc != trx.crc32) {
455 error = "Image is corrupt";
456 break;
460 if (!web) {
461 printf("Writing %x-%x\r", ei.start, (ei.start + ei.length) - 1);
464 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
465 ofs, n, n, trx.len, ei.start, ei.length, mi.erasesize);
467 n += ofs;
469 _dprintf(" erase start=%x len=%x\n", ei.start, ei.length);
470 _dprintf(" write %x\n", n);
472 #ifdef DEBUG_SIMULATE
473 if (fwrite(buf, 1, n, of) != n) {
474 fclose(of);
475 error = "Error writing to test file";
476 break;
478 #else
479 ioctl(mf, MEMUNLOCK, &ei);
480 if (ioctl(mf, MEMERASE, &ei) != 0) {
481 error = "Error erasing MTD block";
482 break;
484 if (write(mf, buf, n) != n) {
485 error = "Error writing to MTD device";
486 break;
488 #endif
489 ofs = 0;
492 #ifdef DEBUG_SIMULATE
493 fclose(of);
494 #endif
496 ERROR:
497 if (buf) free(buf);
498 if (mf >= 0) {
499 read(mf, &n, sizeof(n));
500 close(mf);
502 if (f) fclose(f);
504 crc_done();
506 // set_action(ACT_IDLE);
508 printf("%s\n", error ? error : "Image successfully flashed");
509 _dprintf("%s\n", error ? error : "Image successfully flashed");
510 return (error ? 1 : 0);