| /* |
| * rfdformat.c |
| * |
| * Copyright (C) 2005 Sean Young <sean@mess.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This is very easy: just erase all the blocks and put the magic at |
| * the beginning of each block. |
| */ |
| |
| #define _XOPEN_SOURCE 500 /* For pread/pwrite */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <getopt.h> |
| |
| #include <mtd/mtd-user.h> |
| #include <linux/types.h> |
| |
| #define PROGRAM "rfdformat" |
| #define VERSION "$Revision 1.0 $" |
| |
| void display_help(void) |
| { |
| printf("Usage: " PROGRAM " [OPTIONS] MTD-device\n" |
| "Formats NOR flash for resident flash disk\n" |
| "\n" |
| "-h --help display this help and exit\n" |
| "-V --version output version information and exit\n"); |
| exit(0); |
| } |
| |
| void display_version(void) |
| { |
| printf(PROGRAM " " VERSION "\n" |
| "\n" |
| "This is free software; see the source for copying conditions. There is NO\n" |
| "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); |
| |
| exit(0); |
| } |
| |
| void process_options(int argc, char *argv[], const char **mtd_filename) |
| { |
| int error = 0; |
| |
| for (;;) { |
| int option_index = 0; |
| static const char *short_options = "hV"; |
| static const struct option long_options[] = { |
| { "help", no_argument, 0, 'h' }, |
| { "version", no_argument, 0, 'V', }, |
| { NULL, 0, 0, 0 } |
| }; |
| |
| int c = getopt_long(argc, argv, short_options, |
| long_options, &option_index); |
| if (c == EOF) |
| break; |
| |
| switch (c) { |
| case 'h': |
| display_help(); |
| break; |
| case 'V': |
| display_version(); |
| break; |
| case '?': |
| error = 1; |
| break; |
| } |
| } |
| |
| if ((argc - optind) != 1 || error) |
| display_help(); |
| |
| *mtd_filename = argv[optind]; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| static const uint8_t magic[] = { 0x93, 0x91 }; |
| int fd, block_count, i; |
| struct mtd_info_user mtd_info; |
| char buf[512]; |
| const char *mtd_filename; |
| |
| process_options(argc, argv, &mtd_filename); |
| |
| fd = open(mtd_filename, O_RDWR); |
| if (fd == -1) { |
| perror(mtd_filename); |
| return 1; |
| } |
| |
| if (ioctl(fd, MEMGETINFO, &mtd_info)) { |
| perror(mtd_filename); |
| close(fd); |
| return 1; |
| } |
| |
| if (mtd_info.type != MTD_NORFLASH) { |
| fprintf(stderr, "%s: not NOR flash\n", mtd_filename); |
| close(fd); |
| return 2; |
| } |
| |
| if (mtd_info.size > 32*1024*1024) { |
| fprintf(stderr, "%s: flash larger than 32MiB not supported\n", |
| mtd_filename); |
| close(fd); |
| return 2; |
| } |
| |
| block_count = mtd_info.size / mtd_info.erasesize; |
| |
| if (block_count < 2) { |
| fprintf(stderr, "%s: at least two erase units required\n", |
| mtd_filename); |
| close(fd); |
| return 2; |
| } |
| |
| for (i=0; i<block_count; i++) { |
| struct erase_info_user erase_info; |
| |
| erase_info.start = i * mtd_info.erasesize; |
| erase_info.length = mtd_info.erasesize; |
| |
| if (ioctl(fd, MEMERASE, &erase_info) != 0) { |
| snprintf(buf, sizeof(buf), "%s: erase", mtd_filename); |
| perror(buf); |
| close(fd); |
| return 2; |
| } |
| |
| if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize) |
| != sizeof(magic)) { |
| snprintf(buf, sizeof(buf), "%s: write", mtd_filename); |
| perror(buf); |
| close(fd); |
| return 2; |
| } |
| } |
| |
| close(fd); |
| |
| return 0; |
| } |