diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2006-04-11 19:09:16 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2006-04-11 19:09:16 -0400 |
commit | 72212c137c574b564723327af751c4054c7cfca6 (patch) | |
tree | 13be2da9d4be695002d6ea9c396660c986e5fa5c /flash_eraseall.c |
Initial commit
Diffstat (limited to 'flash_eraseall.c')
-rw-r--r-- | flash_eraseall.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/flash_eraseall.c b/flash_eraseall.c new file mode 100644 index 0000000..d88246b --- /dev/null +++ b/flash_eraseall.c @@ -0,0 +1,308 @@ +/* eraseall.c -- erase the whole of a MTD device + + Copyright (C) 2000 Arcom Control System Ltd + + Renamed to flash_eraseall.c + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + + $Id: flash_eraseall.c,v 1.24 2005/11/07 11:15:10 gleixner Exp $ +*/ +#include <sys/types.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdarg.h> +#include <stdint.h> +#include <libgen.h> +#include <ctype.h> +#include <time.h> +#include <getopt.h> +#include <sys/ioctl.h> +#include <sys/mount.h> +#include "crc32.h" + +#include <mtd/mtd-user.h> +#include <mtd/jffs2-user.h> + +#define PROGRAM "flash_eraseall" +#define VERSION "$Revision: 1.24 $" + +static const char *exe_name; +static const char *mtd_device; +static int quiet; /* true -- don't output progress */ +static int jffs2; // format for jffs2 usage + +static void process_options (int argc, char *argv[]); +static void display_help (void); +static void display_version (void); +static struct jffs2_raw_ebh ebh; +int target_endian = __BYTE_ORDER; + +int main (int argc, char *argv[]) +{ + mtd_info_t meminfo; + int fd, ebhpos = 0, ebhlen = 0; + erase_info_t erase; + int isNAND, bbtest = 1; + uint32_t pages_per_eraseblock, available_oob_space; + + process_options(argc, argv); + + + if ((fd = open(mtd_device, O_RDWR)) < 0) { + fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno)); + exit(1); + } + + + if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { + fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device); + exit(1); + } + + erase.length = meminfo.erasesize; + isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0; + + if (jffs2) { + ebh.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); + ebh.nodetype = cpu_to_je16 (JFFS2_NODETYPE_ERASEBLOCK_HEADER); + ebh.totlen = cpu_to_je32(sizeof(struct jffs2_raw_ebh)); + ebh.hdr_crc = cpu_to_je32 (crc32 (0, &ebh, sizeof (struct jffs2_unknown_node) - 4)); + ebh.reserved = 0; + ebh.compat_fset = JFFS2_EBH_COMPAT_FSET; + ebh.incompat_fset = JFFS2_EBH_INCOMPAT_FSET; + ebh.rocompat_fset = JFFS2_EBH_ROCOMPAT_FSET; + ebh.erase_count = cpu_to_je32(0); + ebh.node_crc = cpu_to_je32(crc32(0, (unsigned char *)&ebh + sizeof(struct jffs2_unknown_node) + 4, + sizeof(struct jffs2_raw_ebh) - sizeof(struct jffs2_unknown_node) - 4)); + + if (isNAND) { + struct nand_oobinfo oobinfo; + + if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) { + fprintf(stderr, "%s: %s: unable to get NAND oobinfo\n", exe_name, mtd_device); + exit(1); + } + + /* Check for autoplacement */ + if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { + /* Get the position of the free bytes */ + if (!oobinfo.oobfree[0][1]) { + fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n"); + exit(1); + } + ebhpos = oobinfo.oobfree[0][0]; + ebhlen = oobinfo.oobfree[0][1]; + } else { + /* Legacy mode */ + switch (meminfo.oobsize) { + case 8: + ebhpos = 6; + ebhlen = 2; + break; + case 16: + ebhpos = 8; + ebhlen = 8; + break; + case 64: + ebhpos = 16; + ebhlen = 8; + break; + } + } + pages_per_eraseblock = meminfo.erasesize/meminfo.oobblock; + available_oob_space = ebhlen * pages_per_eraseblock; + if (available_oob_space < sizeof(struct jffs2_raw_ebh)) { + fprintf(stderr, "The OOB area(%d) is not big enough to hold eraseblock_header(%d)", available_oob_space, sizeof(struct jffs2_raw_ebh)); + exit(1); + } + } + } + + for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { + if (bbtest) { + loff_t offset = erase.start; + int ret = ioctl(fd, MEMGETBADBLOCK, &offset); + if (ret > 0) { + if (!quiet) + printf ("\nSkipping bad block at 0x%08x\n", erase.start); + continue; + } else if (ret < 0) { + if (errno == EOPNOTSUPP) { + bbtest = 0; + if (isNAND) { + fprintf(stderr, "%s: %s: Bad block check not available\n", exe_name, mtd_device); + exit(1); + } + } else { + fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno)); + exit(1); + } + } + } + + if (!quiet) { + printf + ("\rErasing %d Kibyte @ %x -- %2llu %% complete.", + meminfo.erasesize / 1024, erase.start, + (unsigned long long) + erase.start * 100 / meminfo.size); + } + fflush(stdout); + + if (ioctl(fd, MEMERASE, &erase) != 0) { + fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno)); + continue; + } + + /* format for JFFS2 ? */ + if (!jffs2) + continue; + + /* write cleanmarker */ + if (isNAND) { + struct mtd_oob_buf oob; + uint32_t i = 0, written = 0; + + while (written < sizeof(struct jffs2_raw_ebh)) { + oob.ptr = (unsigned char *) &ebh + written; + oob.start = erase.start + meminfo.oobblock*i + ebhpos; + oob.length = (sizeof(struct jffs2_raw_ebh) - written) < ebhlen ? (sizeof(struct jffs2_raw_ebh) - written) : ebhlen; + if (ioctl (fd, MEMWRITEOOB, &oob) != 0) { + fprintf(stderr, "\n%s: %s: MTD writeoob failure: %s\n", exe_name, mtd_device, strerror(errno)); + break; + } + i++; + written += oob.length; + } + if (written < sizeof(struct jffs2_raw_ebh)) { + continue; + } + } else { + if (lseek (fd, erase.start, SEEK_SET) < 0) { + fprintf(stderr, "\n%s: %s: MTD lseek failure: %s\n", exe_name, mtd_device, strerror(errno)); + continue; + } + if (write (fd , &ebh, sizeof (ebh)) != sizeof (ebh)) { + fprintf(stderr, "\n%s: %s: MTD write failure: %s\n", exe_name, mtd_device, strerror(errno)); + continue; + } + } + if (!quiet) + printf (" Cleanmarker written at %x.", erase.start); + } + if (!quiet) + printf("\n"); + + return 0; +} + + +void process_options (int argc, char *argv[]) +{ + int error = 0; + + exe_name = argv[0]; + + for (;;) { + int option_index = 0; + static const char *short_options = "jq"; + static const struct option long_options[] = { + {"help", no_argument, 0, 0}, + {"version", no_argument, 0, 0}, + {"jffs2", no_argument, 0, 'j'}, + {"quiet", no_argument, 0, 'q'}, + {"silent", no_argument, 0, 'q'}, + + {0, 0, 0, 0}, + }; + + int c = getopt_long(argc, argv, short_options, + long_options, &option_index); + if (c == EOF) { + break; + } + + switch (c) { + case 0: + switch (option_index) { + case 0: + display_help(); + break; + case 1: + display_version(); + break; + } + break; + case 'q': + quiet = 1; + break; + case 'j': + jffs2 = 1; + break; + case '?': + error = 1; + break; + } + } + if (optind == argc) { + fprintf(stderr, "%s: no MTD device specified\n", exe_name); + error = 1; + } + if (error) { + fprintf(stderr, "Try `%s --help' for more information.\n", + exe_name); + exit(1); + } + + mtd_device = argv[optind]; +} + + +void display_help (void) +{ + printf("Usage: %s [OPTION] MTD_DEVICE\n" + "Erases all of the specified MTD device.\n" + "\n" + " -j, --jffs2 format the device for jffs2\n" + " -q, --quiet don't display progress messages\n" + " --silent same as --quiet\n" + " --help display this help and exit\n" + " --version output version information and exit\n", + exe_name); + exit(0); +} + + +void display_version (void) +{ + printf(PROGRAM " " VERSION "\n" + "\n" + "Copyright (C) 2000 Arcom Control Systems Ltd\n" + "\n" + PROGRAM " comes with NO WARRANTY\n" + "to the extent permitted by law.\n" + "\n" + "You may redistribute copies of " PROGRAM "\n" + "under the terms of the GNU General Public Licence.\n" + "See the file `COPYING' for more information.\n"); + exit(0); +} |