1 /* vi: set sw=4 ts=4: */
3 * busybox reimplementation of flashcp
5 * (C) 2009 Stefan Seyfried <seife@sphairon.com>
7 * Licensed under GPLv2, see file LICENSE in this source tree.
10 //usage:#define flashcp_trivial_usage
11 //usage: "-v FILE MTD_DEVICE"
12 //usage:#define flashcp_full_usage "\n\n"
13 //usage: "Copy an image to MTD device\n"
14 //usage: "\n -v Verbose"
17 #include <mtd/mtd-user.h>
21 #define OPT_v (1 << 0)
23 #define BUFSIZE (8 * 1024)
25 static void progress(int mode
, uoff_t count
, uoff_t total
)
29 if (!option_mask32
) //if (!(option_mask32 & OPT_v))
31 percent
= count
* 100;
33 percent
= (unsigned) (percent
/ total
);
34 printf("\r%s: %"OFF_FMT
"u/%"OFF_FMT
"u (%u%%) ",
35 (mode
== 0) ? "Erasing block" : ((mode
== 1) ? "Writing kb" : "Verifying kb"),
36 count
, total
, (unsigned)percent
);
40 static void progress_newline(void)
42 if (!option_mask32
) //if (!(option_mask32 & OPT_v))
47 int flashcp_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
48 int flashcp_main(int argc UNUSED_PARAM
, char **argv
)
50 int fd_f
, fd_d
; /* input file and mtd device file descriptors */
53 struct mtd_info_user mtd
;
54 struct erase_info_user e
;
56 // const char *filename, *devicename;
57 RESERVE_CONFIG_UBUFFER(buf
, BUFSIZE
);
58 RESERVE_CONFIG_UBUFFER(buf2
, BUFSIZE
);
60 opt_complementary
= "=2"; /* exactly 2 non-option args: file, dev */
61 /*opts =*/ getopt32(argv
, "v");
63 // filename = *argv++;
64 // devicename = *argv;
65 #define filename argv[0]
66 #define devicename argv[1]
68 /* open input file and mtd device and do sanity checks */
69 fd_f
= xopen(filename
, O_RDONLY
);
71 fd_d
= xopen(devicename
, O_SYNC
| O_RDWR
);
73 if (ioctl(fd_d
, MEMGETINFO
, &mtd
) < 0) {
74 bb_error_msg_and_die("%s is not a MTD flash device", devicename
);
76 if (statb
.st_size
> mtd
.size
) {
77 bb_error_msg_and_die("%s bigger than %s", filename
, devicename
);
80 mtd
.erasesize
= 64 * 1024;
83 /* always erase a complete block */
84 erase_count
= (uoff_t
)(statb
.st_size
+ mtd
.erasesize
- 1) / mtd
.erasesize
;
85 /* erase 1 block at a time to be able to give verbose output */
86 e
.length
= mtd
.erasesize
;
89 * (2) will it work for multi-gigabyte devices?
90 * (3) worse wrt error detection granularity
92 /* optimization: if not verbose, erase in one go */
93 if (!opts
) { // if (!(opts & OPT_v))
94 e
.length
= mtd
.erasesize
* erase_count
;
99 for (i
= 1; i
<= erase_count
; i
++) {
100 progress(0, i
, erase_count
);
103 if (ioctl(fd_d
, MEMERASE
, &e
) < 0) {
104 bb_perror_msg_and_die("erase error at 0x%llx on %s",
105 (long long)e
.start
, devicename
);
110 e
.start
+= mtd
.erasesize
;
114 /* doing this outer loop gives significantly smaller code
115 * than doing two separate loops for writing and verifying */
116 for (i
= 1; i
<= 2; i
++) {
120 xlseek(fd_f
, 0, SEEK_SET
);
121 xlseek(fd_d
, 0, SEEK_SET
);
125 uoff_t rem
= statb
.st_size
- done
;
130 progress(i
, done
/ 1024, (uoff_t
)statb
.st_size
/ 1024);
131 xread(fd_f
, buf
, count
);
135 ret
= full_write(fd_d
, buf
, count
);
137 bb_perror_msg_and_die("write error at 0x%"OFF_FMT
"x on %s, "
139 done
, devicename
, ret
);
141 } else { /* i == 2 */
142 xread(fd_d
, buf2
, count
);
143 if (memcmp(buf
, buf2
, count
)) {
144 bb_error_msg_and_die("verification mismatch at 0x%"OFF_FMT
"x", done
);
153 /* we won't come here if there was an error */