X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/708fe89a974b78c47f05141a6d6a8441e4c23431..3fb652a5d6ff5fac49f1aa3ba875884eec954661:/openwrt/package/mtd/mtd.c diff --git a/openwrt/package/mtd/mtd.c b/openwrt/package/mtd/mtd.c index 74949fdac..78d38fb6a 100644 --- a/openwrt/package/mtd/mtd.c +++ b/openwrt/package/mtd/mtd.c @@ -2,7 +2,7 @@ * mtd - simple memory technology device manipulation tool * * Copyright (C) 2005 Waldemar Brodkorb , - * Felix Fietkau + * Felix Fietkau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,11 +16,11 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ * - * code is based on linux-mtd example code + * The code is based on the linux-mtd examples. */ #include @@ -43,9 +43,15 @@ #include #define TRX_MAGIC 0x30524448 /* "HDR0" */ -#define BUFSIZE (10 * 1024) +#define BUFSIZE (16 * 1024) #define MAX_ARGS 8 +#define DEBUG + +#define SYSTYPE_UNKNOWN 0 +#define SYSTYPE_BROADCOM 1 +/* to be continued */ + struct trx_header { uint32_t magic; /* "HDR0" */ uint32_t len; /* Length of file including header */ @@ -54,47 +60,42 @@ struct trx_header { uint32_t offsets[3]; /* Offsets of partitions from start of header */ }; +char buf[BUFSIZE]; +int buflen; + int -trx_check(const char *trxfile, const char *mtd) +image_check_bcom(int imagefd, const char *mtd) { + struct trx_header *trx = (struct trx_header *) buf; struct mtd_info_user mtdInfo; - int trxfd, fd; - size_t count; - struct trx_header trx; - struct stat trxstat; - - trxfd = open(trxfile,O_RDONLY); - if(trxfd < 0) { - fprintf(stderr, "Could not open trx image: %s\n", trxfile); - exit(1); - } + int fd; - if (fstat(trxfd,&trxstat) < 0) { - fprintf(stderr, "Could not get trx image file status: %s\n", trxfile); - close(trxfd); - exit(1); + buflen = read(imagefd, buf, 32); + if (buflen < 32) { + fprintf(stdout, "Could not get image header, file too small (%ld bytes)\n", buflen); + return 0; } - count = read(trxfd, &trx, sizeof(struct trx_header)); - if (count < sizeof(struct trx_header)) { - fprintf(stderr, "Could not trx header, file too small (%ld bytes)\n", count); - close(trxfd); - exit(1); + switch(trx->magic) { + case 0x47343557: /* W54G */ + case 0x53343557: /* W54S */ + case 0x73343557: /* W54s */ + case 0x46343557: /* W54F */ + case 0x55343557: /* W54U */ + /* ignore the first 32 bytes */ + buflen = read(imagefd, buf, sizeof(struct trx_header)); + break; } - - if (trx.magic != TRX_MAGIC || trx.len < sizeof(struct trx_header)) { + + if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) { fprintf(stderr, "Bad trx header\n"); fprintf(stderr, "If this is a firmware in bin format, like some of the\n" "original firmware files are, use following command to convert to trx:\n" "dd if=firmware.bin of=firmware.trx bs=32 skip=1\n"); - close(trxfd); - exit(1); + return 0; } - - lseek(trxfd, 0, SEEK_SET); /* check if image fits to mtd device */ - fd = mtd_open(mtd, O_RDWR); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); @@ -103,22 +104,64 @@ trx_check(const char *trxfile, const char *mtd) if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); - close(fd); exit(1); } - if(mtdInfo.size < trxstat.st_size) { + if(mtdInfo.size < trx->len) { fprintf(stderr, "Image too big for partition: %s\n", mtd); - close(trxfd); close(fd); - exit(1); + return 0; } - printf("Writing %s to %s ...\n", trxfile, mtd); + return 1; +} - close(fd); +int +image_check(int imagefd, const char *mtd) +{ + int fd, systype; + size_t count; + char *c; + FILE *f; + + systype = SYSTYPE_UNKNOWN; + f = fopen("/proc/cpuinfo", "r"); + while (!feof(f) && (fgets(buf, BUFSIZE - 1, f) != NULL)) { + if ((strncmp(buf, "system type", 11) == 0) && (c = strchr(buf, ':'))) { + c += 2; + if (strncmp(c, "Broadcom BCM947XX", 17) == 0) + systype = SYSTYPE_BROADCOM; + } + } + fclose(f); + + switch(systype) { + case SYSTYPE_BROADCOM: + return image_check_bcom(imagefd, mtd); + default: + return 1; + } +} + +int mtd_check(char *mtd) +{ + struct mtd_info_user mtdInfo; + int fd; - return(trxfd); + fd = mtd_open(mtd, O_RDWR); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + return 0; + } + + if(ioctl(fd, MEMGETINFO, &mtdInfo)) { + fprintf(stderr, "Could not get MTD device info from %s\n", mtd); + close(fd); + return 0; + } + + close(fd); + return 1; } int @@ -140,7 +183,6 @@ mtd_unlock(const char *mtd) exit(1); } - printf("Unlocking %s ...\n", mtd); mtdLockInfo.start = 0; mtdLockInfo.length = mtdInfo.size; if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) { @@ -192,7 +234,6 @@ mtd_erase(const char *mtd) exit(1); } - printf("Erasing %s ...\n", mtd); mtdEraseInfo.length = mtdInfo.erasesize; for (mtdEraseInfo.start = 0; @@ -213,20 +254,12 @@ mtd_erase(const char *mtd) } int -mtd_write(int trxfd, const char *mtd) +mtd_write(int imagefd, const char *mtd, int quiet) { - int fd,i; - size_t result,size,written; + int fd, i, result; + size_t r, w, e; struct mtd_info_user mtdInfo; struct erase_info_user mtdEraseInfo; - unsigned char src[BUFSIZE],dest[BUFSIZE]; - struct stat trxstat; - - if (fstat(trxfd,&trxstat) < 0) { - fprintf(stderr, "Could not get trx image file status\n"); - close(trxfd); - exit(1); - } fd = mtd_open(mtd, O_RDWR); if(fd < 0) { @@ -240,50 +273,69 @@ mtd_write(int trxfd, const char *mtd) exit(1); } - mtdEraseInfo.start = 0; - mtdEraseInfo.length = trxstat.st_size & ~(mtdInfo.erasesize -1); - if(trxstat.st_size % mtdInfo.erasesize) mtdEraseInfo.length += mtdInfo.erasesize; - - /* erase the chunk */ - if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { - fprintf(stderr, "Erasing mtd failed: %s\n", mtd); - exit(1); - } - - size = trxstat.st_size; - i = BUFSIZE; - written = 0; - - while (size) { - if (size < BUFSIZE) i = size; - read(trxfd,src,i); - result = write(fd,src,i); - if (i != result) { + r = w = e = 0; + if (!quiet) + fprintf(stderr, " [ ]"); + + for (;;) { + /* buffer may contain data already (from trx check) */ + r = buflen; + r += read(imagefd, buf + buflen, BUFSIZE - buflen); + w += r; + + /* EOF */ + if (r <= 0) break; + + /* need to erase the next block before writing data to it */ + while (w > e) { + mtdEraseInfo.start = e; + mtdEraseInfo.length = mtdInfo.erasesize; + + if (!quiet) + fprintf(stderr, "\b\b\b[e]"); + /* erase the chunk */ + if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { + fprintf(stderr, "Erasing mtd failed: %s\n", mtd); + exit(1); + } + e += mtdInfo.erasesize; + } + + if (!quiet) + fprintf(stderr, "\b\b\b[w]"); + + if ((result = write(fd, buf, r)) < r) { if (result < 0) { - fprintf(stderr,"Error while writing image"); + fprintf(stderr, "Error writing image.\n"); + exit(1); + } else { + fprintf(stderr, "Insufficient space.\n"); exit(1); } - fprintf(stderr,"Error writing image"); - exit(1); } - written += i; - size -= i; + + buflen = 0; } + if (!quiet) + fprintf(stderr, "\b\b\b\b"); return 0; } void usage(void) { - printf("Usage: mtd [ ...] [ ...] \n\n" + fprintf(stderr, "Usage: mtd [ ...] [ ...] \n\n" "The device is in the format of mtdX (eg: mtd4) or its label.\n" "mtd recognizes these commands:\n" - " unlock unlock the device\n" - " erase erase all data on device\n" - " write write imagefile to device\n" + " unlock unlock the device\n" + " erase erase all data on device\n" + " write |- write (use - for stdin) to device\n" "Following options are available:\n" - " -r reboot after successful command\n" - " -e erase before executing the command\n\n" + " -q quiet mode (once: no [w] on writing,\n" + " twice: no status messages)\n" + " -r reboot after successful command\n" + " -f force write without trx checks\n" + " -e erase before executing the command\n\n" "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n" " mtd -r write linux.trx linux\n\n"); exit(1); @@ -291,8 +343,8 @@ void usage(void) int main (int argc, char **argv) { - int ch, i, boot, unlock, trxfd; - char *erase[MAX_ARGS], *device; + int ch, i, boot, unlock, imagefd, force, quiet, unlocked; + char *erase[MAX_ARGS], *device, *imagefile; enum { CMD_ERASE, CMD_WRITE, @@ -301,12 +353,21 @@ int main (int argc, char **argv) erase[0] = NULL; boot = 0; + force = 0; + buflen = 0; + quiet = 0; - while ((ch = getopt(argc, argv, "re:")) != -1) + while ((ch = getopt(argc, argv, "frqe:")) != -1) switch (ch) { + case 'f': + force = 1; + break; case 'r': boot = 1; break; + case 'q': + quiet++; + break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) @@ -335,31 +396,70 @@ int main (int argc, char **argv) } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; + + if (strcmp(argv[1], "-") == 0) { + imagefile = ""; + imagefd = 0; + } else { + imagefile = argv[1]; + if ((imagefd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); + exit(1); + } + } + /* check trx file before erasing or writing anything */ - trxfd = trx_check(argv[1], device); + if (!image_check(imagefd, device)) { + if ((quiet < 2) || !force) + fprintf(stderr, "TRX check failed!\n"); + if (!force) + exit(1); + } else { + if (!mtd_check(device)) { + fprintf(stderr, "Can't open device for writing!\n"); + exit(1); + } + } } else { usage(); } sync(); - + i = 0; + unlocked = 0; while (erase[i] != NULL) { + if (quiet < 2) + fprintf(stderr, "Unlocking %s ...\n", erase[i]); mtd_unlock(erase[i]); + if (quiet < 2) + fprintf(stderr, "Erasing %s ...\n", erase[i]); mtd_erase(erase[i]); + if (strcmp(erase[i], device) == 0) + unlocked = 1; i++; } - mtd_unlock(device); - + if (!unlocked) { + if (quiet < 2) + fprintf(stderr, "Unlocking %s ...\n", device); + mtd_unlock(device); + } + switch (cmd) { case CMD_UNLOCK: break; case CMD_ERASE: + if (quiet < 2) + fprintf(stderr, "Erasing %s ...\n", device); mtd_erase(device); break; case CMD_WRITE: - mtd_write(trxfd, device); + if (quiet < 2) + fprintf(stderr, "Writing from %s to %s ... ", imagefile, device); + mtd_write(imagefd, device, quiet); + if (quiet < 2) + fprintf(stderr, "\n"); break; }