diff options
author | Baruch Siach <baruch@tkos.co.il> | 2010-08-25 16:36:17 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-08-25 16:36:17 +0200 |
commit | 6f32ea4039535c48759a217fd6352193846a393c (patch) | |
tree | dead4ac04b0f2d6c44f7d80172f8b2756b9cfd7c | |
parent | 159677c8842b985c9365b82178b97456ca8a1727 (diff) |
nandwrite: new applet
function old new delta
nandwrite_main - 382 +382
packed_usage 27119 27135 +16
applet_names 2275 2285 +10
applet_main 1340 1344 +4
applet_nameofs 670 672 +2
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 4/0 up/down: 414/0) Total: 414 bytes
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r-- | miscutils/nandwrite.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c new file mode 100644 index 000000000..a20f7f384 --- /dev/null +++ b/miscutils/nandwrite.c @@ -0,0 +1,128 @@ +/* + * nandwrite.c - ported to busybox from mtd-utils + * + * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography + * + * Licensed under GPLv2, see file LICENSE in this source tree. + * + * TODO: add support for large (>4GB) MTD devices + */ + +//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o + +//config:config NANDWRITE +//config: bool "nandwrite" +//config: default n +//config: depends on PLATFORM_LINUX +//config: help +//config: Write to the specified MTD device, with bad blocks awareness + +#include "libbb.h" +#include <mtd/mtd-user.h> + +//usage:#define nandwrite_trivial_usage +//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" +//usage:#define nandwrite_full_usage "\n\n" +//usage: "Write to the specified MTD device\n" +//usage: "\nOptions:" +//usage: "\n -p Pad to page size" +//usage: "\n -s ADDR Start address" + +static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo, + unsigned block_offset) +{ + while (1) { + loff_t offs; + if (block_offset >= meminfo->size) + bb_error_msg_and_die("not enough space in MTD device"); + offs = block_offset; + if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0) + return block_offset; + /* ioctl returned 1 => "bad block" */ + printf("Skipping bad block at 0x%08x\n", block_offset); + block_offset += meminfo->erasesize; + } +} + +int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nandwrite_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + int fd; + ssize_t cnt; + unsigned mtdoffset, meminfo_writesize; + struct mtd_info_user meminfo; + unsigned char *filebuf; + const char *opt_s = "0"; + enum { + OPT_p = (1 << 0), + OPT_s = (1 << 1), + }; + + opt_complementary = "-1:?2"; + opts = getopt32(argv, "ps:", &opt_s); + argv += optind; + + if (argv[1]) + xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); + + fd = xopen(argv[0], O_RDWR); + xioctl(fd, MEMGETINFO, &meminfo); + + mtdoffset = xatou(opt_s); + + /* Pull it into a CPU register (hopefully) - smaller code that way */ + meminfo_writesize = meminfo.writesize; + + if (mtdoffset & (meminfo_writesize - 1)) + bb_error_msg_and_die("start address is not page aligned"); + + filebuf = xmalloc(meminfo_writesize); + + cnt = -1; + while (mtdoffset < meminfo.size) { + unsigned blockstart = mtdoffset & ~(meminfo.erasesize - 1); + if (blockstart == mtdoffset) { + /* starting a new eraseblock */ + mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); + printf("Writing at 0x%08x\n", mtdoffset); + } + /* get some more data from input */ + cnt = full_read(STDIN_FILENO, filebuf, meminfo_writesize); + if (cnt == 0) { + /* even with -p, we do not pad past the end of input + * (-p only zero-pads last incomplete page) + */ + break; + } + if (cnt < meminfo_writesize) { + if (!(opts & OPT_p)) + bb_error_msg_and_die("input size is not rounded up to page size, " + "use -p to zero pad"); + /* zero pad to end of write block */ + memset(filebuf + cnt, 0, meminfo_writesize - cnt); + } + xlseek(fd, mtdoffset, SEEK_SET); + xwrite(fd, filebuf, meminfo_writesize); + mtdoffset += meminfo_writesize; + if (cnt < meminfo_writesize) + break; + } + + if (cnt != 0) { + /* We filled entire MTD, but did we reach EOF on input? */ + if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) { + /* no */ + bb_error_msg_and_die("not enough space in MTD device"); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + free(filebuf); + close(fd); + } + + return EXIT_SUCCESS; +} |