busybox/miscutils/flash_eraseall.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/* eraseall.c -- erase the whole of a MTD device
   3 *
   4 * Ported to busybox from mtd-utils.
   5 *
   6 * Copyright (C) 2000 Arcom Control System Ltd
   7 *
   8 * Renamed to flash_eraseall.c
   9 *
  10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  11 */
  12
  13//usage:#define flash_eraseall_trivial_usage
  14//usage:       "[-jq] MTD_DEVICE"
  15//usage:#define flash_eraseall_full_usage "\n\n"
  16//usage:       "Erase an MTD device\n"
  17//usage:     "\n        -j      Format the device for jffs2"
  18//usage:     "\n        -q      Don't display progress messages"
  19
  20#include "libbb.h"
  21#include <mtd/mtd-user.h>
  22#include <linux/jffs2.h>
  23
  24#define OPTION_J  (1 << 0)
  25#define OPTION_Q  (1 << 1)
  26#define IS_NAND   (1 << 2)
  27#define BBTEST    (1 << 3)
  28
  29/* mtd/jffs2-user.h used to have this atrocity:
  30extern int target_endian;
  31
  32#define t16(x) ({ __u16 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
  33#define t32(x) ({ __u32 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
  34
  35#define cpu_to_je16(x) ((jint16_t){t16(x)})
  36#define cpu_to_je32(x) ((jint32_t){t32(x)})
  37#define cpu_to_jemode(x) ((jmode_t){t32(x)})
  38
  39#define je16_to_cpu(x) (t16((x).v16))
  40#define je32_to_cpu(x) (t32((x).v32))
  41#define jemode_to_cpu(x) (t32((x).m))
  42
  43but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore)
  44*/
  45
  46/* We always use native endianness */
  47#undef cpu_to_je16
  48#undef cpu_to_je32
  49#define cpu_to_je16(v) ((jint16_t){(v)})
  50#define cpu_to_je32(v) ((jint32_t){(v)})
  51
  52static void show_progress(mtd_info_t *meminfo, erase_info_t *erase)
  53{
  54        printf("\rErasing %u Kibyte @ %x - %2u%% complete.",
  55                (unsigned)meminfo->erasesize / 1024,
  56                erase->start,
  57                (unsigned) ((unsigned long long) erase->start * 100 / meminfo->size)
  58        );
  59        fflush_all();
  60}
  61
  62int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  63int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
  64{
  65        struct jffs2_unknown_node cleanmarker;
  66        mtd_info_t meminfo;
  67        int fd, clmpos, clmlen;
  68        erase_info_t erase;
  69        struct stat st;
  70        unsigned int flags;
  71        char *mtd_name;
  72
  73        opt_complementary = "=1";
  74        flags = BBTEST | getopt32(argv, "jq");
  75
  76        mtd_name = argv[optind];
  77        fd = xopen(mtd_name, O_RDWR);
  78        fstat(fd, &st);
  79        if (!S_ISCHR(st.st_mode))
  80                bb_error_msg_and_die("%s: not a char device", mtd_name);
  81
  82        xioctl(fd, MEMGETINFO, &meminfo);
  83        erase.length = meminfo.erasesize;
  84        if (meminfo.type == MTD_NANDFLASH)
  85                flags |= IS_NAND;
  86
  87        clmpos = 0;
  88        clmlen = 8;
  89        if (flags & OPTION_J) {
  90                uint32_t *crc32_table;
  91
  92                crc32_table = crc32_filltable(NULL, 0);
  93
  94                cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
  95                cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
  96                if (!(flags & IS_NAND))
  97                        cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node));
  98                else {
  99                        struct nand_oobinfo oobinfo;
 100
 101                        xioctl(fd, MEMGETOOBSEL, &oobinfo);
 102
 103                        /* Check for autoplacement */
 104                        if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
 105                                /* Get the position of the free bytes */
 106                                clmpos = oobinfo.oobfree[0][0];
 107                                clmlen = oobinfo.oobfree[0][1];
 108                                if (clmlen > 8)
 109                                        clmlen = 8;
 110                                if (clmlen == 0)
 111                                        bb_error_msg_and_die("autoplacement selected and no empty space in oob");
 112                        } else {
 113                                /* Legacy mode */
 114                                switch (meminfo.oobsize) {
 115                                case 8:
 116                                        clmpos = 6;
 117                                        clmlen = 2;
 118                                        break;
 119                                case 16:
 120                                        clmpos = 8;
 121                                        /*clmlen = 8;*/
 122                                        break;
 123                                case 64:
 124                                        clmpos = 16;
 125                                        /*clmlen = 8;*/
 126                                        break;
 127                                }
 128                        }
 129                        cleanmarker.totlen = cpu_to_je32(8);
 130                }
 131
 132                cleanmarker.hdr_crc = cpu_to_je32(
 133                        crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table)
 134                );
 135        }
 136
 137        /* Don't want to destroy progress indicator by bb_error_msg's */
 138        applet_name = xasprintf("\n%s: %s", applet_name, mtd_name);
 139
 140        for (erase.start = 0; erase.start < meminfo.size;
 141             erase.start += meminfo.erasesize) {
 142                if (flags & BBTEST) {
 143                        int ret;
 144                        loff_t offset = erase.start;
 145
 146                        ret = ioctl(fd, MEMGETBADBLOCK, &offset);
 147                        if (ret > 0) {
 148                                if (!(flags & OPTION_Q))
 149                                        bb_info_msg("\nSkipping bad block at 0x%08x", erase.start);
 150                                continue;
 151                        }
 152                        if (ret < 0) {
 153                                /* Black block table is not available on certain flash
 154                                 * types e.g. NOR
 155                                 */
 156                                if (errno == EOPNOTSUPP) {
 157                                        flags &= ~BBTEST;
 158                                        if (flags & IS_NAND)
 159                                                bb_error_msg_and_die("bad block check not available");
 160                                } else {
 161                                        bb_perror_msg_and_die("MEMGETBADBLOCK error");
 162                                }
 163                        }
 164                }
 165
 166                if (!(flags & OPTION_Q))
 167                        show_progress(&meminfo, &erase);
 168
 169                xioctl(fd, MEMERASE, &erase);
 170
 171                /* format for JFFS2 ? */
 172                if (!(flags & OPTION_J))
 173                        continue;
 174
 175                /* write cleanmarker */
 176                if (flags & IS_NAND) {
 177                        struct mtd_oob_buf oob;
 178
 179                        oob.ptr = (unsigned char *) &cleanmarker;
 180                        oob.start = erase.start + clmpos;
 181                        oob.length = clmlen;
 182                        xioctl(fd, MEMWRITEOOB, &oob);
 183                } else {
 184                        xlseek(fd, erase.start, SEEK_SET);
 185                        /* if (lseek(fd, erase.start, SEEK_SET) < 0) {
 186                                bb_perror_msg("MTD %s failure", "seek");
 187                                continue;
 188                        } */
 189                        xwrite(fd, &cleanmarker, sizeof(cleanmarker));
 190                        /* if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) {
 191                                bb_perror_msg("MTD %s failure", "write");
 192                                continue;
 193                        } */
 194                }
 195                if (!(flags & OPTION_Q))
 196                        printf(" Cleanmarker written at %x.", erase.start);
 197        }
 198        if (!(flags & OPTION_Q)) {
 199                show_progress(&meminfo, &erase);
 200                bb_putchar('\n');
 201        }
 202
 203        if (ENABLE_FEATURE_CLEAN_UP)
 204                close(fd);
 205        return EXIT_SUCCESS;
 206}
 207