161 lines
3.3 KiB
C
161 lines
3.3 KiB
C
/*
|
|
* 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 PROGRAM_NAME "rfdformat"
|
|
#define VERSION "$Revision 1.0 $"
|
|
|
|
#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>
|
|
|
|
void display_help(void)
|
|
{
|
|
printf("Usage: %s [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",
|
|
PROGRAM_NAME);
|
|
exit(0);
|
|
}
|
|
|
|
void display_version(void)
|
|
{
|
|
printf("%s " 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",
|
|
PROGRAM_NAME);
|
|
|
|
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;
|
|
}
|