1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include "libbb.h"
34#include <mtd/mtd-user.h>
35#include <linux/jffs2.h>
36
37#define OPTION_J (1 << 0)
38#define OPTION_N (1 << 1)
39#define OPTION_Q (1 << 2)
40#define IS_NAND (1 << 3)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#undef cpu_to_je16
61#undef cpu_to_je32
62#define cpu_to_je16(v) ((jint16_t){(v)})
63#define cpu_to_je32(v) ((jint32_t){(v)})
64
65static void show_progress(mtd_info_t *meminfo, erase_info_t *erase)
66{
67 printf("\rErasing %u Kibyte @ %x - %2u%% complete.",
68 (unsigned)meminfo->erasesize / 1024,
69 erase->start,
70 (unsigned) ((unsigned long long) erase->start * 100 / meminfo->size)
71 );
72 fflush_all();
73}
74
75int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
76int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
77{
78 struct jffs2_unknown_node cleanmarker;
79 mtd_info_t meminfo;
80 int fd, clmpos, clmlen;
81 erase_info_t erase;
82 struct stat st;
83 unsigned int flags;
84 char *mtd_name;
85
86 flags = getopt32(argv, "^" "jNq" "\0" "=1");
87
88 mtd_name = argv[optind];
89 fd = xopen(mtd_name, O_RDWR);
90 fstat(fd, &st);
91 if (!S_ISCHR(st.st_mode))
92 bb_error_msg_and_die("%s: not a char device", mtd_name);
93
94 xioctl(fd, MEMGETINFO, &meminfo);
95 erase.length = meminfo.erasesize;
96 if (meminfo.type == MTD_NANDFLASH)
97 flags |= IS_NAND;
98
99 clmpos = 0;
100 clmlen = 8;
101 if (flags & OPTION_J) {
102 uint32_t *crc32_table;
103
104 crc32_table = crc32_new_table_le();
105
106 cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
107 cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
108 if (!(flags & IS_NAND))
109 cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node));
110 else {
111 struct nand_oobinfo oobinfo;
112
113 xioctl(fd, MEMGETOOBSEL, &oobinfo);
114
115
116 if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
117
118 clmpos = oobinfo.oobfree[0][0];
119 clmlen = oobinfo.oobfree[0][1];
120 if (clmlen > 8)
121 clmlen = 8;
122 if (clmlen == 0)
123 bb_error_msg_and_die("autoplacement selected and no empty space in oob");
124 } else {
125
126 switch (meminfo.oobsize) {
127 case 8:
128 clmpos = 6;
129 clmlen = 2;
130 break;
131 case 16:
132 clmpos = 8;
133
134 break;
135 case 64:
136 clmpos = 16;
137
138 break;
139 }
140 }
141 cleanmarker.totlen = cpu_to_je32(8);
142 }
143
144 cleanmarker.hdr_crc = cpu_to_je32(
145 crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table)
146 );
147 }
148
149
150 applet_name = xasprintf("\n%s: %s", applet_name, mtd_name);
151
152 for (erase.start = 0; erase.start < meminfo.size;
153 erase.start += meminfo.erasesize) {
154 if (!(flags & OPTION_N)) {
155 int ret;
156 loff_t offset = erase.start;
157
158 ret = ioctl(fd, MEMGETBADBLOCK, &offset);
159 if (ret > 0) {
160 if (!(flags & OPTION_Q))
161 printf("\nSkipping bad block at 0x%08x\n", erase.start);
162 continue;
163 }
164 if (ret < 0) {
165
166
167
168 if (errno == EOPNOTSUPP) {
169 flags |= OPTION_N;
170 if (flags & IS_NAND)
171 bb_error_msg_and_die("bad block check not available");
172 } else {
173 bb_perror_msg_and_die("MEMGETBADBLOCK error");
174 }
175 }
176 }
177
178 if (!(flags & OPTION_Q))
179 show_progress(&meminfo, &erase);
180
181 xioctl(fd, MEMERASE, &erase);
182
183
184 if (!(flags & OPTION_J))
185 continue;
186
187
188 if (flags & IS_NAND) {
189 struct mtd_oob_buf oob;
190
191 oob.ptr = (unsigned char *) &cleanmarker;
192 oob.start = erase.start + clmpos;
193 oob.length = clmlen;
194 xioctl(fd, MEMWRITEOOB, &oob);
195 } else {
196 xlseek(fd, erase.start, SEEK_SET);
197
198
199
200
201 xwrite(fd, &cleanmarker, sizeof(cleanmarker));
202
203
204
205
206 }
207 if (!(flags & OPTION_Q))
208 printf(" Cleanmarker written at %x.", erase.start);
209 }
210 if (!(flags & OPTION_Q)) {
211 show_progress(&meminfo, &erase);
212 bb_putchar('\n');
213 }
214
215 if (ENABLE_FEATURE_CLEAN_UP)
216 close(fd);
217 return EXIT_SUCCESS;
218}
219