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>
19 /* If 1, simulates "flashing" by writing to existing regular file */
22 #define OPT_v (1 << 0)
24 #define BUFSIZE (4 * 1024)
26 static void progress(int mode
, uoff_t count
, uoff_t total
)
30 if (!option_mask32
) //if (!(option_mask32 & OPT_v))
32 percent
= count
* 100;
34 percent
= (unsigned) (percent
/ total
);
35 printf("\r%s: %"OFF_FMT
"u/%"OFF_FMT
"u (%u%%) ",
36 (mode
< 0) ? "Erasing block" : ((mode
== 0) ? "Writing kb" : "Verifying kb"),
37 count
, total
, (unsigned)percent
);
41 static void progress_newline(void)
43 if (!option_mask32
) //if (!(option_mask32 & OPT_v))
48 int flashcp_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
49 int flashcp_main(int argc UNUSED_PARAM
, char **argv
)
51 int fd_f
, fd_d
; /* input file and mtd device file descriptors */
54 struct mtd_info_user mtd
;
55 struct erase_info_user e
;
57 // const char *filename, *devicename;
58 RESERVE_CONFIG_UBUFFER(buf
, BUFSIZE
);
59 RESERVE_CONFIG_UBUFFER(buf2
, BUFSIZE
);
61 opt_complementary
= "=2"; /* exactly 2 non-option args: file, dev */
62 /*opts =*/ getopt32(argv
, "v");
64 // filename = *argv++;
65 // devicename = *argv;
66 #define filename argv[0]
67 #define devicename argv[1]
69 /* open input file and mtd device and do sanity checks */
70 fd_f
= xopen(filename
, O_RDONLY
);
72 fd_d
= xopen(devicename
, O_SYNC
| O_RDWR
);
74 if (ioctl(fd_d
, MEMGETINFO
, &mtd
) < 0) {
75 bb_error_msg_and_die("%s is not a MTD flash device", devicename
);
77 if (statb
.st_size
> mtd
.size
) {
78 bb_error_msg_and_die("%s bigger than %s", filename
, devicename
);
81 mtd
.erasesize
= 64 * 1024;
84 /* always erase a complete block */
85 erase_count
= (uoff_t
)(statb
.st_size
+ mtd
.erasesize
- 1) / mtd
.erasesize
;
86 /* erase 1 block at a time to be able to give verbose output */
87 e
.length
= mtd
.erasesize
;
90 * (2) will it work for multi-gigabyte devices?
91 * (3) worse wrt error detection granularity
93 /* optimization: if not verbose, erase in one go */
94 if (!opts
) { // if (!(opts & OPT_v))
95 e
.length
= mtd
.erasesize
* erase_count
;
100 for (i
= 1; i
<= erase_count
; i
++) {
101 progress(-1, 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
= 0; i
<= 1; i
++) {
120 xlseek(fd_f
, 0, SEEK_SET
);
121 xlseek(fd_d
, 0, SEEK_SET
);
127 progress(i
, done
/ 1024, (uoff_t
)statb
.st_size
/ 1024);
128 rem
= statb
.st_size
- done
;
133 xread(fd_f
, buf
, count
);
137 memset((char*)buf
+ count
, 0, BUFSIZE
- count
);
139 ret
= full_write(fd_d
, buf
, BUFSIZE
);
140 if (ret
!= BUFSIZE
) {
141 bb_perror_msg_and_die("write error at 0x%"OFF_FMT
"x on %s, "
143 done
, devicename
, ret
);
145 } else { /* i == 1 */
146 xread(fd_d
, buf2
, count
);
147 if (memcmp(buf
, buf2
, count
) != 0) {
148 bb_error_msg_and_die("verification mismatch at 0x%"OFF_FMT
"x", done
);
157 /* we won't come here if there was an error */