diff options
-rw-r--r-- | miscutils/nandwrite.c | 65 |
1 files changed, 56 insertions, 9 deletions
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 8c4da802f..a64b95bc5 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -36,7 +36,7 @@ //usage: "\n -s ADDR Start address" //usage:#define nanddump_trivial_usage -//usage: "[-o] [-b] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" +//usage: "[-o] [-b|--bb=padbad|skipbad] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" //usage:#define nanddump_full_usage "\n\n" //usage: "Dump MTD_DEVICE\n" //usage: "\n -o Dump oob data" @@ -44,6 +44,12 @@ //usage: "\n -s ADDR Start address" //usage: "\n -l LEN Length" //usage: "\n -f FILE Dump to file ('-' for stdout)" +//usage: "\n --bb=METHOD:" +//usage: "\n skipbad: skip bad blocks" +//usage: "\n padbad: substitute bad blocks by 0xff (default)" +//usage: "\n The difference between omit and skip bad block is that in the omit" +//usage: "\n case, the length of the bad block is counted as part of the total" +//usage: "\n dump length, and in the skip case, it's not." #include "libbb.h" #include <mtd/mtd-user.h> @@ -57,6 +63,11 @@ #define OPT_b (1 << 2) #define OPT_f (1 << 3) #define OPT_l (1 << 4) +#define OPT_bb (1 << 5) /* must be the last one in the list */ + +#define BB_PADBAD (1 << 0) +#define BB_SKIPBAD (1 << 1) +#define BB_OMITBAD (1 << 2) /* helper for writing out 0xff for bad blocks pad */ static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob) @@ -102,6 +113,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) /* Buffer for OOB data */ unsigned char *oobbuf; unsigned opts; + unsigned bb_method = BB_PADBAD; int fd; ssize_t cnt; unsigned mtdoffset, meminfo_writesize, blockstart, limit; @@ -109,11 +121,14 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) struct mtd_info_user meminfo; struct mtd_oob_buf oob; unsigned char *filebuf; - const char *opt_s = "0", *opt_f = "-", *opt_l; + const char *opt_s = "0", *opt_f = "-", *opt_l, *opt_bb; + static const char nanddump_longopts[] ALIGN1 = + "bb\0" Required_argument "\xff"; /* no short equivalent */ if (IS_NANDDUMP) { opt_complementary = "=1"; - opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l); + applet_long_options = nanddump_longopts; + opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l, &opt_bb); } else { /* nandwrite */ opt_complementary = "-1:?2"; opts = getopt32(argv, "ps:", &opt_s); @@ -138,6 +153,20 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) if (length < meminfo.size - mtdoffset) end_addr = mtdoffset + length; } + if (IS_NANDDUMP) { + if ((opts & OPT_b) && (opts & OPT_bb)) + bb_show_usage(); + if (opts & OPT_b) + bb_method = BB_OMITBAD; + if (opts & OPT_bb) { + if (!strcmp("skipbad", opt_bb)) + bb_method = BB_SKIPBAD; + else if (!strcmp("padbad", opt_bb)) + bb_method = BB_PADBAD; + else + bb_show_usage(); + } + } /* Pull it into a CPU register (hopefully) - smaller code that way */ meminfo_writesize = meminfo.writesize; @@ -162,9 +191,16 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) tmp = next_good_eraseblock(fd, &meminfo, blockstart); if (tmp != blockstart) { /* bad block(s), advance mtdoffset */ - if (IS_NANDDUMP && !(opts & OPT_b)) { - int bad_len = MIN(tmp, end_addr) - mtdoffset; - dump_bad(&meminfo, bad_len, opts & OPT_o); + if (IS_NANDDUMP) { + if (bb_method == BB_PADBAD) { + int bad_len = MIN(tmp, end_addr) - mtdoffset; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } + /* with option skipbad, increase the total length */ + if (bb_method == BB_SKIPBAD) { + end_addr += (tmp - blockstart); + } + /* omitbad: do nothing */ } mtdoffset = tmp; } @@ -182,9 +218,20 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); if (IS_NANDWRITE) printf("Writing at 0x%08x\n", mtdoffset); - else if (mtdoffset > blockstart && !(opts & OPT_b)) { - int bad_len = MIN(mtdoffset, limit) - blockstart; - dump_bad(&meminfo, bad_len, opts & OPT_o); + else if (mtdoffset > blockstart) { + if (bb_method == BB_PADBAD) { + /* dump FF padded bad block */ + int bad_len = MIN(mtdoffset, limit) - blockstart; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } else if (bb_method == BB_SKIPBAD) { + /* for skipbad, increase the length */ + if ((end_addr + mtdoffset - blockstart) > end_addr) + end_addr += (mtdoffset - blockstart); + else + end_addr = ~0; + limit = MIN(meminfo.size, end_addr); + } + /* omitbad: do nothing */ } if (mtdoffset >= limit) break; |