summaryrefslogtreecommitdiff
path: root/nandwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'nandwrite.c')
-rw-r--r--nandwrite.c144
1 files changed, 49 insertions, 95 deletions
diff --git a/nandwrite.c b/nandwrite.c
index 066ef55..a42f7c9 100644
--- a/nandwrite.c
+++ b/nandwrite.c
@@ -49,12 +49,12 @@ static void display_help(void)
"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
"Writes to the specified MTD device.\n"
"\n"
+" -a, --autoplace Use auto OOB layout\n"
" -m, --markbad Mark blocks bad if write fails\n"
" -n, --noecc Write without ecc\n"
" -N, --noskipbad Write without bad block skipping\n"
" -o, --oob Image contains oob data\n"
" -O, --onlyoob Image contains oob data and only write the oob part\n"
-" -r, --raw Image contains the raw oob data dumped by nanddump\n"
" -s addr, --start=addr Set start address (default is 0)\n"
" -p, --pad Pad to page size\n"
" -b, --blockalign=1|2|4 Set multiple of eraseblocks to align to\n"
@@ -86,10 +86,10 @@ static const char *mtd_device, *img;
static long long mtdoffset = 0;
static bool quiet = false;
static bool writeoob = false;
-static bool rawoob = false;
static bool onlyoob = false;
static bool markbad = false;
static bool noecc = false;
+static bool autoplace = false;
static bool noskipbad = false;
static bool pad = false;
static int blockalign = 1; /* default to using actual block size */
@@ -100,7 +100,7 @@ static void process_options(int argc, char * const argv[])
for (;;) {
int option_index = 0;
- static const char *short_options = "b:mnNoOpqrs:";
+ static const char *short_options = "b:mnNoOpqs:a";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
@@ -112,8 +112,8 @@ static void process_options(int argc, char * const argv[])
{"onlyoob", no_argument, 0, 'O'},
{"pad", no_argument, 0, 'p'},
{"quiet", no_argument, 0, 'q'},
- {"raw", no_argument, 0, 'r'},
{"start", required_argument, 0, 's'},
+ {"autoplace", no_argument, 0, 'a'},
{0, 0, 0, 0},
};
@@ -156,16 +156,15 @@ static void process_options(int argc, char * const argv[])
case 'p':
pad = true;
break;
- case 'r':
- rawoob = true;
- writeoob = true;
- break;
case 's':
mtdoffset = simple_strtoll(optarg, &error);
break;
case 'b':
blockalign = atoi(optarg);
break;
+ case 'a':
+ autoplace = true;
+ break;
case '?':
error++;
break;
@@ -180,6 +179,12 @@ static void process_options(int argc, char * const argv[])
errmsg_die("Can't specify negative blockalign with option -b:"
" %d", blockalign);
+ if (autoplace && noecc)
+ errmsg_die("Autoplacement and no-ECC are mutually exclusive");
+
+ if (!onlyoob && (pad && writeoob))
+ errmsg_die("Can't pad when oob data is present");
+
argc -= optind;
argv += optind;
@@ -233,30 +238,23 @@ int main(int argc, char * const argv[])
/* points to the current page inside filebuf */
unsigned char *writebuf = NULL;
/* points to the OOB for the current page in filebuf */
- unsigned char *oobreadbuf = NULL;
unsigned char *oobbuf = NULL;
libmtd_t mtd_desc;
int ebsize_aligned;
+ uint8_t write_mode;
process_options(argc, argv);
- if (!onlyoob && (pad && writeoob)) {
- fprintf(stderr, "Can't pad when oob data is present.\n");
- exit(EXIT_FAILURE);
- }
-
/* Open the device */
- if ((fd = open(mtd_device, O_RDWR)) == -1) {
- perror(mtd_device);
- exit(EXIT_FAILURE);
- }
+ if ((fd = open(mtd_device, O_RDWR)) == -1)
+ sys_errmsg_die("%s", mtd_device);
mtd_desc = libmtd_open();
if (!mtd_desc)
- return errmsg("can't initialize libmtd");
+ errmsg_die("can't initialize libmtd");
/* Fill in MTD device capability structure */
if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
- return errmsg("mtd_get_dev_info failed");
+ errmsg_die("mtd_get_dev_info failed");
/*
* Pretend erasesize is specified number of blocks - to match jffs2
@@ -265,24 +263,27 @@ int main(int argc, char * const argv[])
*/
ebsize_aligned = mtd.eb_size * blockalign;
- if (mtdoffset & (mtd.min_io_size - 1)) {
- fprintf(stderr, "The start address is not page-aligned !\n"
- "The pagesize of this NAND Flash is 0x%x.\n",
- mtd.min_io_size);
- close(fd);
- exit(EXIT_FAILURE);
- }
+ if (mtdoffset & (mtd.min_io_size - 1))
+ errmsg_die("The start address is not page-aligned !\n"
+ "The pagesize of this NAND Flash is 0x%x.\n",
+ mtd.min_io_size);
+
+ /* Select OOB write mode */
+ if (noecc)
+ write_mode = MTD_OPS_RAW;
+ else if (autoplace)
+ write_mode = MTD_OPS_AUTO_OOB;
+ else
+ write_mode = MTD_OPS_PLACE_OOB;
if (noecc) {
- ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
+ ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
if (ret) {
switch (errno) {
case ENOTTY:
errmsg_die("ioctl MTDFILEMODE is missing");
default:
- perror("MTDFILEMODE");
- close(fd);
- exit(EXIT_FAILURE);
+ sys_errmsg_die("MTDFILEMODE");
}
}
}
@@ -331,7 +332,7 @@ int main(int argc, char * const argv[])
fprintf(stderr, "Image %d bytes, NAND page %d bytes, OOB area %d"
" bytes, device size %lld bytes\n",
imglen, pagelen, mtd.oob_size, mtd.size);
- perror("Input file does not fit into device");
+ sys_errmsg("Input file does not fit into device");
goto closeall;
}
@@ -345,9 +346,6 @@ int main(int argc, char * const argv[])
filebuf = xmalloc(filebuf_max);
erase_buffer(filebuf, filebuf_max);
- oobbuf = xmalloc(mtd.oob_size);
- erase_buffer(oobbuf, mtd.oob_size);
-
/*
* Get data from input and write to the device while there is
* still input to read and we are still within the device
@@ -460,16 +458,16 @@ int main(int argc, char * const argv[])
}
if (writeoob) {
- oobreadbuf = writebuf + mtd.min_io_size;
+ oobbuf = writebuf + mtd.min_io_size;
/* Read more data for the OOB from the input if there isn't enough in the buffer */
- if ((oobreadbuf + mtd.oob_size) > (filebuf + filebuf_len)) {
+ if ((oobbuf + mtd.oob_size) > (filebuf + filebuf_len)) {
int readlen = mtd.oob_size;
- int alreadyread = (filebuf + filebuf_len) - oobreadbuf;
+ int alreadyread = (filebuf + filebuf_len) - oobbuf;
int tinycnt = alreadyread;
while (tinycnt < readlen) {
- cnt = read(ifd, oobreadbuf + tinycnt, readlen - tinycnt);
+ cnt = read(ifd, oobbuf + tinycnt, readlen - tinycnt);
if (cnt == 0) { /* EOF */
break;
} else if (cnt < 0) {
@@ -494,57 +492,17 @@ int main(int argc, char * const argv[])
imglen = 0;
}
}
-
- if (!noecc) {
- int start, len;
- struct nand_oobinfo old_oobinfo;
-
- /* Read the current oob info */
- if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
- perror("MEMGETOOBSEL");
- close(fd);
- exit(EXIT_FAILURE);
- }
-
- /*
- * We use autoplacement and have the oobinfo with the autoplacement
- * information from the kernel available
- *
- * Modified to support out of order oobfree segments,
- * such as the layout used by diskonchip.c
- */
- if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
- int i, tags_pos = 0, tmp_ofs;
- for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
- /* Set the reserved bytes to 0xff */
- start = old_oobinfo.oobfree[i][0];
- len = old_oobinfo.oobfree[i][1];
- tmp_ofs = rawoob ? start : tags_pos;
- memcpy(oobbuf + start, oobreadbuf + tmp_ofs, len);
- tags_pos += len;
- }
- } else {
- /* Set at least the ecc byte positions to 0xff */
- start = old_oobinfo.eccbytes;
- len = mtd.oob_size - start;
- memcpy(oobbuf + start,
- oobreadbuf + start,
- len);
- }
- } else {
- memcpy(oobbuf, oobreadbuf, mtd.oob_size);
- }
- /* Write OOB data first, as ecc will be placed in there */
- if (mtd_write_oob(mtd_desc, &mtd, fd, mtdoffset,
- mtd.oob_size, oobbuf)) {
- sys_errmsg("%s: MTD writeoob failure", mtd_device);
- goto closeall;
- }
}
- /* Write out the Page data */
- if (!onlyoob && mtd_write(&mtd, fd, mtdoffset / mtd.eb_size, mtdoffset % mtd.eb_size,
- writebuf, mtd.min_io_size)) {
+ /* Write out data */
+ ret = mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size,
+ mtdoffset % mtd.eb_size,
+ onlyoob ? NULL : writebuf,
+ onlyoob ? 0 : mtd.min_io_size,
+ writeoob ? oobbuf : NULL,
+ writeoob ? mtd.oob_size : 0,
+ write_mode);
+ if (ret) {
int i;
if (errno != EIO) {
sys_errmsg("%s: MTD write failure", mtd_device);
@@ -588,15 +546,11 @@ closeall:
close(ifd);
libmtd_close(mtd_desc);
free(filebuf);
- free(oobbuf);
close(fd);
- if (failed
- || ((ifd != STDIN_FILENO) && (imglen > 0))
- || (writebuf < (filebuf + filebuf_len))) {
- perror("Data was only partially written due to error\n");
- exit(EXIT_FAILURE);
- }
+ if (failed || ((ifd != STDIN_FILENO) && (imglen > 0))
+ || (writebuf < (filebuf + filebuf_len)))
+ sys_errmsg_die("Data was only partially written due to error");
/* Return happy */
return EXIT_SUCCESS;