2 * An image maker that creates a file that creates a Yaffs2 image file
3 * can be programmed into NAND.
4 * This assumes that the device has the following properties:
7 * * Yaffs is using inband tags.
9 * Note that this utility first generates a "working file" which is
10 * a simulation of the NAND. It then generates an output file which
11 * can be programmed into flash.
18 #include <sys/types.h>
27 #undef CONFIG_YAFFS_PROVIDE_DEFS
28 #undef CONFIG_YAFFSFS_PROVIDE_VALUES
33 #include "yaffs_flexible_file_sim.h"
34 #include "yaffs_guts.h"
35 #include "yaffs_trace.h"
36 #include "yaffs_packedtags2.h"
40 * These are the sizes in the simulator file.
43 #define MAX_BLOCKS 3000
44 #define PAGES_PER_BLOCK_DEFAULT 64
45 #define PAGE_DATA_SIZE_DEFAULT 2048
46 #define PAGE_SPARE_SIZE 64
47 #define FULL_PAGE_SIZE (chunk_size + PAGE_SPARE_SIZE)
50 /* Some stub definitions to get building to work. */
51 int simulate_power_failure = 0;
54 static char *input_dir;
55 static char *output_file;
56 static char *working_file;
57 static char endian = 'l';
58 static int no_tags_ecc = 0;
59 static int inband_tags = 0;
62 static int record_size;
63 static int total_written;
64 static int chunk_size = PAGE_DATA_SIZE_DEFAULT;
65 static int chunks_per_block = PAGES_PER_BLOCK_DEFAULT;
67 static void usage(const char *prog_name)
69 printf("Usage: %s options\n", prog_name);
70 printf("\t-i name input_directory\n");
71 printf("\t-o name output_file\n");
72 printf("\t-w name working_file\n");
73 printf("\t-b big endian output\n");
74 printf("\t-I store tags in flash data area (inband_tags)\n");
75 printf("\t-N do not apply ECC to tags in OOB area (no_tags_ecc)\n");
76 printf("\t-c val chunk size in bytes (default %d)\n", PAGE_DATA_SIZE_DEFAULT);
77 printf("\t-B val chunks per block(default %d)\n", PAGES_PER_BLOCK_DEFAULT);
81 static void parse_args(int argc, char *argv[])
86 while ((c = getopt(argc, argv, "bi:c:B:o:w:hIN")) != -1) {
89 case 'h': usage(argv[0]); break;
90 case 'i': input_dir = strdup(optarg); break;
91 case 'o': output_file = strdup(optarg); break;
92 case 'w': working_file = strdup(optarg); break;
93 case 'b': endian = 'b'; break;
94 case 'c': chunk_size = atoi(optarg); break;
95 case 'B': chunks_per_block = atoi(optarg); break;
96 case 'I': inband_tags = 1; break;
97 case 'N': no_tags_ecc = 1; break;
103 static int process_file(const char *from_path, const char *to_path, unsigned mode)
107 unsigned char buffer[8000];
113 hin = open(from_path, O_RDONLY);
115 perror ("opening input file");
118 hout = yaffs_open(to_path, O_CREAT | O_TRUNC | O_RDWR, 0666);
121 printf("failed to create yaffs file %s\n", to_path);
125 while ((nread = read(hin, buffer, sizeof(buffer))) > 0) {
126 nwritten = yaffs_write(hout, buffer, nread);
128 if (nwritten != nread) {
129 printf("Only wrote %d bytes out of %d\n", nwritten, nread);
135 ret = yaffs_fdatasync(hout);
137 printf("data sytnc failed\n");
141 ret = yaffs_fchmod(hout, mode);
143 printf("chmod failed\n");
147 ret = yaffs_close(hout);
149 printf("close failed\n");
156 static int process_directory(const char *from_dir, const char *to_dir)
161 struct dirent *entry;
163 printf("Processing directory %s into %s\n", from_dir, to_dir);
165 dir = opendir(from_dir);
167 printf("opendir failed on %s", from_dir);
171 while((entry = readdir(dir)) != NULL && error >= 0) {
178 //printf("Got entry %s\n", entry->d_name);
180 /* Ignore . and .. */
181 if(strcmp(entry->d_name, ".") == 0 ||
182 strcmp(entry->d_name, "..") == 0)
185 if (snprintf(from_path, sizeof(from_path),
186 "%s/%s", from_dir,entry->d_name) >= (int)sizeof(from_path)) {
187 printf("path too long for %s/%s\n", from_dir, entry->d_name);
191 if (snprintf(to_path, sizeof(to_path),
192 "%s/%s",to_dir,entry->d_name) >= (int)sizeof(to_path)) {
193 printf("path too long for %s/%s\n",to_dir,entry->d_name);
198 if (lstat(from_path,&stats) < 0)
205 mode = stats.st_mode & 0777;
207 if (S_ISDIR(stats.st_mode)) {
208 printf("Directory create %s, mode %03o\n", to_path, mode);
209 ret = yaffs_mkdir(to_path, mode);
210 printf("Directory create %s, mode %03o : result %d\n",
214 printf("directory creation failed\n");
217 process_directory(from_path, to_path);
218 } else if (S_ISREG(stats.st_mode)) {
219 ret = process_file(from_path, to_path, mode);
220 printf("Copy file %s to %s, mode %03o : result %d\n",
221 from_path, to_path, mode, ret);
223 printf("file copy failed\n");
228 printf("Unhandled object type %d\n", stats.st_mode);
238 int is_all_ff(unsigned char *buffer, int n)
251 * Write the data to output, skipping over the spare bytes.
252 * Stop writing when we get to blank flash.
254 int generate_output_file(const char *working_file, const char *output_file)
256 unsigned char *buffer;
262 buffer = malloc(FULL_PAGE_SIZE);
264 inh = open(working_file, O_RDONLY);
265 outh = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
267 while ((nread = read(inh, buffer, FULL_PAGE_SIZE)) > 0) {
268 if (nread != FULL_PAGE_SIZE) {
269 printf("working file not properly sized\n");
273 if(is_all_ff(buffer, chunk_size)) {
274 printf("End of data found\n");
278 /* Write the data part. */
279 nwritten = write(outh, buffer, chunk_size);
281 if (nwritten != chunk_size) {
282 printf("short write\n");
286 total_written += nwritten;
288 /* Now if there are OOB tags then write the OOB tags part too */
290 /* Read the oob bytes. In the simulator these are
291 * stored at offset 0 in the 64-byte spare area.
292 * We must therefore copy them from this location to
295 nwritten = write(outh, buffer + chunk_size, tags_size);
297 if (nwritten != tags_size) {
298 printf("short write\n");
302 total_written += nwritten;
309 return total_written;
313 int main(int argc, char *argv[])
315 struct yaffs_dev * dev;
318 yaffs_trace_mask = 0;
320 parse_args(argc, argv);
322 if (!input_dir || !output_file || !working_file) {
323 printf("Need input directory , output file and working file\n");
327 printf("Generating image from %s into file %s using working file %s\n",
328 input_dir, output_file, working_file);
329 printf("Output file is in %s endian\n",
330 (endian == 'l') ? "little" : "big");
333 * Determine oob tags_size.
337 else if (no_tags_ecc)
338 tags_size = sizeof(struct yaffs_packed_tags2_tags_only);
340 tags_size = sizeof(struct yaffs_packed_tags2);
342 record_size = chunk_size + tags_size;
346 * Create the Yaffs working file using the simulator.
348 unlink(working_file);
350 dev = yaffs_flexible_file_sim_create(
360 printf("Failed to create yaffs working file\n");
365 * Disable checkpointing to create an image without checkpoint data.
367 dev->param.skip_checkpt_rd = 1;
368 dev->param.skip_checkpt_wr = 1;
371 * Set up stored endian: 1 = little endian, 2 = big endian.
374 dev->param.stored_endian = (endian == 'l') ? 1 : 2;
375 dev->param.no_tags_ecc = no_tags_ecc;
377 dev->param.inband_tags = inband_tags;
379 ret = yaffs_mount("yroot");
381 printf("yaffs_mount returned %d\n", ret);
384 printf("Mounting yaffs simulator failed - cannot continue\n");
388 process_directory(input_dir, "yroot");
390 yaffs_unmount("yroot");
393 printf("Generating output file: %s\n", output_file);
395 ret = generate_output_file(working_file, output_file);
398 printf("Wrote %d bytes (%d pages of %d bytes each) to output file.\n",
399 total_written, total_written/record_size, record_size);
400 printf("This images has %d bytes per chunk, %d chunks per block.\n",
401 chunk_size, chunks_per_block);
403 printf("The image has inband tags.\n");
404 printf("This means it is structured a records of %d bytes per page\n", record_size);
405 printf("This should be written to the data portion of the page\n");
407 printf("The image has out of band tags with%s ECC on the tags\n",
408 no_tags_ecc ? " NO" : "");
409 printf("This means it has %d tags bytes per record to be written in the oob area\n", tags_size);
410 printf("Each record is %d bytes.\n"
411 "The first %d bytes are data for the data datea and\n"
412 "the last %d bytes are tags for the oob (spare) area\n",
413 record_size, chunk_size, tags_size);