2 * nandwrite.c - ported to busybox from mtd-utils
4 * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography
6 * Licensed under GPLv2, see file LICENSE in this source tree.
8 * TODO: add support for large (>4GB) MTD devices
11 //applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
13 //kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o
15 //config:config NANDWRITE
16 //config: bool "nandwrite"
18 //config: depends on PLATFORM_LINUX
20 //config: Write to the specified MTD device, with bad blocks awareness
23 #include <mtd/mtd-user.h>
25 //usage:#define nandwrite_trivial_usage
26 //usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]"
27 //usage:#define nandwrite_full_usage "\n\n"
28 //usage: "Write to the specified MTD device\n"
30 //usage: "\n -p Pad to page size"
31 //usage: "\n -s ADDR Start address"
33 static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
34 unsigned block_offset)
38 if (block_offset >= meminfo->size)
39 bb_error_msg_and_die("not enough space in MTD device");
41 if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0)
43 /* ioctl returned 1 => "bad block" */
44 printf("Skipping bad block at 0x%08x\n", block_offset);
45 block_offset += meminfo->erasesize;
49 int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50 int nandwrite_main(int argc UNUSED_PARAM, char **argv)
55 unsigned mtdoffset, meminfo_writesize;
56 struct mtd_info_user meminfo;
57 unsigned char *filebuf;
58 const char *opt_s = "0";
64 opt_complementary = "-1:?2";
65 opts = getopt32(argv, "ps:", &opt_s);
69 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
71 fd = xopen(argv[0], O_RDWR);
72 xioctl(fd, MEMGETINFO, &meminfo);
74 mtdoffset = bb_strtou(opt_s, NULL, 0);
76 bb_error_msg_and_die("invalid number '%s'", opt_s);
78 /* Pull it into a CPU register (hopefully) - smaller code that way */
79 meminfo_writesize = meminfo.writesize;
81 if (mtdoffset & (meminfo_writesize - 1))
82 bb_error_msg_and_die("start address is not page aligned");
84 filebuf = xmalloc(meminfo_writesize);
87 while (mtdoffset < meminfo.size) {
88 unsigned blockstart = mtdoffset & ~(meminfo.erasesize - 1);
89 if (blockstart == mtdoffset) {
90 /* starting a new eraseblock */
91 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart);
92 printf("Writing at 0x%08x\n", mtdoffset);
94 /* get some more data from input */
95 cnt = full_read(STDIN_FILENO, filebuf, meminfo_writesize);
97 /* even with -p, we do not pad past the end of input
98 * (-p only zero-pads last incomplete page)
102 if (cnt < meminfo_writesize) {
104 bb_error_msg_and_die("input size is not rounded up to page size, "
105 "use -p to zero pad");
106 /* zero pad to end of write block */
107 memset(filebuf + cnt, 0, meminfo_writesize - cnt);
109 xlseek(fd, mtdoffset, SEEK_SET);
110 xwrite(fd, filebuf, meminfo_writesize);
111 mtdoffset += meminfo_writesize;
112 if (cnt < meminfo_writesize)
117 /* We filled entire MTD, but did we reach EOF on input? */
118 if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) {
120 bb_error_msg_and_die("not enough space in MTD device");
124 if (ENABLE_FEATURE_CLEAN_UP) {