#define _GNU_SOURCE
#include <byteswap.h>
+#include <endian.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
#include <mtd/mtd-user.h>
+#include "crc32.h"
#include "fis.h"
#include "mtd.h"
#define TRX_MAGIC 0x48445230 /* "HDR0" */
#define SEAMA_MAGIC 0x5ea3a417
+#define WRG_MAGIC 0x20040220
+#define WRGG03_MAGIC 0x20080321
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be32(x) (x)
#define be32_to_cpu(x) (x)
+#define le32_to_cpu(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_be32(x) bswap_32(x)
#define be32_to_cpu(x) bswap_32(x)
+#define le32_to_cpu(x) (x)
#else
#error "Unsupported endianness"
#endif
MTD_IMAGE_FORMAT_UNKNOWN,
MTD_IMAGE_FORMAT_TRX,
MTD_IMAGE_FORMAT_SEAMA,
+ MTD_IMAGE_FORMAT_WRG,
+ MTD_IMAGE_FORMAT_WRGG03,
};
static char *buf = NULL;
static char *imagefile = NULL;
static enum mtd_image_format imageformat = MTD_IMAGE_FORMAT_UNKNOWN;
static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
+static char *tpl_uboot_args_part;
static int buflen = 0;
int quiet;
int no_erase;
imageformat = MTD_IMAGE_FORMAT_TRX;
else if (be32_to_cpu(magic) == SEAMA_MAGIC)
imageformat = MTD_IMAGE_FORMAT_SEAMA;
+ else if (le32_to_cpu(magic) == WRG_MAGIC)
+ imageformat = MTD_IMAGE_FORMAT_WRG;
+ else if (le32_to_cpu(magic) == WRGG03_MAGIC)
+ imageformat = MTD_IMAGE_FORMAT_WRGG03;
switch (imageformat) {
case MTD_IMAGE_FORMAT_TRX:
ret = trx_check(imagefd, mtd, buf, &buflen);
break;
case MTD_IMAGE_FORMAT_SEAMA:
+ case MTD_IMAGE_FORMAT_WRG:
+ case MTD_IMAGE_FORMAT_WRGG03:
break;
default:
#ifdef target_brcm
ssize_t r, w, e;
ssize_t skip = 0;
uint32_t offset = 0;
+ int buflen_raw = 0;
int jffs2_replaced = 0;
int skip_bad_blocks = 0;
#ifdef FIS_SUPPORT
static struct fis_part new_parts[MAX_ARGS];
static struct fis_part old_parts[MAX_ARGS];
+ struct fis_part *cur_part = NULL;
int n_new = 0, n_old = 0;
if (fis_layout) {
memset(&old_parts, 0, sizeof(old_parts));
memset(&new_parts, 0, sizeof(new_parts));
+ if (!part_offset)
+ cur_part = new_parts;
do {
next = strchr(tmp, ':');
lseek(fd, part_offset, SEEK_SET);
}
+ /* Write TP-Link recovery flag */
+ if (tpl_uboot_args_part && mtd_tpl_recoverflag_write) {
+ if (quiet < 2)
+ fprintf(stderr, "Writing recovery flag to %s\n", tpl_uboot_args_part);
+ result = mtd_tpl_recoverflag_write(tpl_uboot_args_part, true);
+ if (result < 0) {
+ fprintf(stderr, "Could not write TP-Link recovery flag to %s: %i", mtd, result);
+ exit(1);
+ }
+ }
+
indicate_writing(mtd);
w = e = 0;
buflen += r;
}
+ if (buflen_raw == 0)
+ buflen_raw = buflen;
+
if (buflen == 0)
break;
if (skip > 0) {
skip -= buflen;
+ buflen_raw = 0;
buflen = 0;
if (skip <= 0)
indicate_writing(mtd);
if (!quiet)
fprintf(stderr, "\b\b\b ");
if (quiet < 2)
- fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
+ fprintf(stderr, "\nAppending jffs2 data from %s to %s..\n.", jffs2file, mtd);
/* got an EOF marker - this is the place to add some jffs2 data */
skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
jffs2_replaced = 1;
w += skip;
e += skip;
skip -= buflen;
+ buflen_raw = 0;
buflen = 0;
offset = 0;
continue;
continue;
}
- if (mtd_erase_block(fd, e) < 0) {
+ if (mtd_erase_block(fd, e + part_offset) < 0) {
if (next) {
if (w < e) {
write(fd, buf + offset, e - w);
}
w += buflen;
+#ifdef FIS_SUPPORT
+ if (cur_part && cur_part->size
+ && cur_part < &new_parts[MAX_ARGS - 1]
+ && cur_part->length + buflen_raw > cur_part->size)
+ cur_part++;
+ if (cur_part) {
+ cur_part->length += buflen_raw;
+ cur_part->crc = crc32(cur_part->crc, buf, buflen_raw);
+ }
+#endif
+ buflen_raw = 0;
buflen = 0;
offset = 0;
}
break;
case MTD_IMAGE_FORMAT_SEAMA:
if (mtd_fixseama)
- mtd_fixseama(mtd, 0);
+ mtd_fixseama(mtd, 0, 0);
+ break;
+ case MTD_IMAGE_FORMAT_WRG:
+ if (mtd_fixwrg)
+ mtd_fixwrg(mtd, 0, 0);
+ break;
+ case MTD_IMAGE_FORMAT_WRGG03:
+ if (mtd_fixwrgg)
+ mtd_fixwrgg(mtd, 0, 0);
break;
default:
break;
#endif
close(fd);
+
+ /* Clear TP-Link recovery flag */
+ if (tpl_uboot_args_part && mtd_tpl_recoverflag_write) {
+ if (quiet < 2)
+ fprintf(stderr, "Removing recovery flag from %s\n", tpl_uboot_args_part);
+ result = mtd_tpl_recoverflag_write(tpl_uboot_args_part, false);
+ if (result < 0) {
+ fprintf(stderr, "Could not clear TP-Link recovery flag to %s: %i", mtd, result);
+ exit(1);
+ }
+ }
+
return 0;
}
fprintf(stderr,
" fixseama fix the checksum in a seama header on first boot\n");
}
+ if (mtd_fixwrg) {
+ fprintf(stderr,
+ " fixwrg fix the checksum in a wrg header on first boot\n");
+ }
+ if (mtd_fixwrgg) {
+ fprintf(stderr,
+ " fixwrgg fix the checksum in a wrgg header on first boot\n");
+ }
fprintf(stderr,
"Following options are available:\n"
" -q quiet mode (once: no [w] on writing,\n"
" -d <name> directory for jffs2write, defaults to \"tmp\"\n"
" -j <name> integrate <file> into jffs2 data when writing an image\n"
" -s <number> skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n"
- " -p write beginning at partition offset\n"
+ " -p <number> write beginning at partition offset\n"
" -l <length> the length of data that we want to dump\n");
if (mtd_fixtrx) {
fprintf(stderr,
" -o offset offset of the image header in the partition(for fixtrx)\n");
+ }
+ if (mtd_fixtrx || mtd_fixseama || mtd_fixwrg || mtd_fixwrgg) {
fprintf(stderr,
- " -c datasize amount of data to be used for checksum calculation (for fixtrx)\n");
+ " -c datasize amount of data to be used for checksum calculation (for fixtrx / fixseama / fixwrg / fixwrgg)\n");
+ }
+ if (mtd_tpl_recoverflag_write) {
+ fprintf(stderr,
+ " -t <partition> write TP-Link recovery-flag to <partition> (for write)\n");
}
fprintf(stderr,
#ifdef FIS_SUPPORT
CMD_JFFS2WRITE,
CMD_FIXTRX,
CMD_FIXSEAMA,
+ CMD_FIXWRG,
+ CMD_FIXWRGG,
CMD_VERIFY,
CMD_DUMP,
CMD_RESETBC,
#ifdef FIS_SUPPORT
"F:"
#endif
- "frnqe:d:s:j:p:o:c:l:")) != -1)
+ "frnqe:d:s:j:p:o:c:t:l:")) != -1)
switch (ch) {
case 'f':
force = 1;
usage();
}
break;
+ case 't':
+ tpl_uboot_args_part = optarg;
+ break;
#ifdef FIS_SUPPORT
case 'F':
fis_layout = optarg;
} else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
cmd = CMD_FIXSEAMA;
device = argv[1];
+ } else if (((strcmp(argv[0], "fixwrg") == 0) && (argc == 2)) && mtd_fixwrg) {
+ cmd = CMD_FIXWRG;
+ device = argv[1];
+ } else if (((strcmp(argv[0], "fixwrgg") == 0) && (argc == 2)) && mtd_fixwrgg) {
+ cmd = CMD_FIXWRGG;
+ device = argv[1];
} else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) {
cmd = CMD_VERIFY;
imagefile = argv[1];
break;
case CMD_FIXSEAMA:
if (mtd_fixseama)
- mtd_fixseama(device, 0);
+ mtd_fixseama(device, 0, data_size);
+ break;
+ case CMD_FIXWRG:
+ if (mtd_fixwrg)
+ mtd_fixwrg(device, 0, data_size);
+ break;
+ case CMD_FIXWRGG:
+ if (mtd_fixwrgg)
+ mtd_fixwrgg(device, 0, data_size);
break;
}