nandwrite.c

Upload User: allywll
Upload Date: 2007-11-10
Package Size: 1288k
Code Size: 10k
Category: Embeded-SCM Develop
Development Platform: Others
  1. /*
  2.  *  nandwrite.c
  3.  *
  4.  *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  5.  *      2003 Thomas Gleixner (tglx@linutronix.de)
  6.  *
  7.  * $Id: nandwrite.c,v 1.17 2004/10/24 14:57:20 gleixner Exp $
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License version 2 as
  11.  * published by the Free Software Foundation.
  12.  *
  13.  * Overview:
  14.  *   This utility writes a binary image directly to a NAND flash
  15.  *   chip or NAND chips contained in DoC devices. This is the
  16.  *   "inverse operation" of nanddump.
  17.  *
  18.  * tglx: Major rewrite to handle bad blocks, write data with or without ECC
  19.  *  write oob data only on request
  20.  *
  21.  * Bug/ToDo:
  22.  */
  23. #define _GNU_SOURCE
  24. #include <ctype.h>
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <unistd.h>
  31. #include <sys/stat.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/types.h>
  34. #include <getopt.h>
  35. #include <asm/types.h>
  36. #include "mtd/mtd-user.h"
  37. #define PROGRAM "nandwrite"
  38. #define VERSION "1.14"
  39. /*
  40.  * Buffer array used for writing data
  41.  */
  42. unsigned char writebuf[512];
  43. unsigned char oobbuf[16];
  44. // oob layouts to pass into the kernel as default
  45. struct nand_oobinfo none_oobinfo = { 
  46. .useecc = MTD_NANDECC_OFF,
  47. };
  48. struct nand_oobinfo jffs2_oobinfo = { 
  49. .useecc = MTD_NANDECC_PLACE,
  50. .eccbytes = 6,
  51. .eccpos = { 0, 1, 2, 3, 6, 7 }
  52. };
  53. struct nand_oobinfo yaffs_oobinfo = { 
  54. .useecc = MTD_NANDECC_PLACE,
  55. .eccbytes = 6,
  56. .eccpos = { 8, 9, 10, 13, 14, 15}
  57. };
  58. struct nand_oobinfo autoplace_oobinfo = {
  59. .useecc = MTD_NANDECC_AUTOPLACE
  60. };
  61. void display_help (void)
  62. {
  63. printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILEn"
  64.        "Writes to the specified MTD device.n"
  65.        "n"
  66.        "  -a, --autoplace   Use auto oob layoutn"
  67.        "  -j, --jffs2     force jffs2 oob layoutn"
  68.        "  -y, --yaffs     force yaffs oob layoutn"
  69.        "  -n, --noecc write without eccn"
  70.        "  -o, --oob       image contains oob datan"
  71.        "  -s addr, --start=addr set start address (default is 0)n"
  72.        "  -p, --pad             pad to page sizen"
  73.        "  -b, --blockalign=1|2|4 set multiple of eraseblocks to align ton"
  74.        "  -q, --quiet     don't display progress messagesn"
  75.        "      --help      display this help and exitn"
  76.        "      --version   output version information and exitn");
  77. exit(0);
  78. }
  79. void display_version (void)
  80. {
  81. printf(PROGRAM " " VERSION "n"
  82.        "n"
  83.        "Copyright (C) 2003 Thomas Gleixner n"
  84.        "n"
  85.        PROGRAM " comes with NO WARRANTYn"
  86.        "to the extent permitted by law.n"
  87.        "n"
  88.        "You may redistribute copies of " PROGRAM "n"
  89.        "under the terms of the GNU General Public Licence.n"
  90.        "See the file `COPYING' for more information.n");
  91. exit(0);
  92. }
  93. char  *mtd_device, *img;
  94. int  mtdoffset = 0;
  95. int  quiet = 0;
  96. int writeoob = 0;
  97. int autoplace = 0;
  98. int forcejffs2 = 0;
  99. int forceyaffs = 0;
  100. int noecc = 0;
  101. int pad = 0;
  102. int blockalign = 1; /*default to using 16K block size */
  103. void process_options (int argc, char *argv[])
  104. {
  105. int error = 0;
  106. for (;;) {
  107. int option_index = 0;
  108. static const char *short_options = "os:ajynqp";
  109. static const struct option long_options[] = {
  110. {"help", no_argument, 0, 0},
  111. {"version", no_argument, 0, 0},
  112. {"oob", no_argument, 0, 'o'},
  113. {"start", required_argument, 0, 's'},
  114. {"autoplace", no_argument, 0, 'a'},
  115. {"jffs2", no_argument, 0, 'j'},
  116. {"yaffs", no_argument, 0, 'y'},
  117. {"noecc", no_argument, 0, 'n'},
  118. {"quiet", no_argument, 0, 'q'},
  119. {"pad", no_argument, 0, 'p'},
  120.     {"blockalign", required_argument, 0, 'b'},
  121. {0, 0, 0, 0},
  122. };
  123. int c = getopt_long(argc, argv, short_options,
  124.     long_options, &option_index);
  125. if (c == EOF) {
  126. break;
  127. }
  128. switch (c) {
  129. case 0:
  130. switch (option_index) {
  131. case 0:
  132. display_help();
  133. break;
  134. case 1:
  135. display_version();
  136. break;
  137. }
  138. break;
  139. case 'q':
  140. quiet = 1;
  141. break;
  142. case 'a':
  143. autoplace = 1;
  144. break;
  145. case 'j':
  146. forcejffs2 = 1;
  147. break;
  148. case 'y':
  149. forceyaffs = 1;
  150. break;
  151. case 'n':
  152. noecc = 1;
  153. break;
  154. case 'o':
  155. writeoob = 1;
  156. break;
  157. case 'p':
  158. pad = 1;
  159. break;
  160. case 's':
  161. mtdoffset = atoi (optarg);
  162. break;
  163. case 'b':
  164. blockalign = atoi (optarg);
  165. break;
  166. case '?':
  167. error = 1;
  168. break;
  169. }
  170. }
  171. if ((argc - optind) != 2 || error) 
  172. display_help ();
  173. mtd_device = argv[optind++];
  174. img = argv[optind];
  175. }
  176. /*
  177.  * Main program
  178.  */
  179. int main(int argc, char **argv)
  180. {
  181. int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1;
  182. struct mtd_info_user meminfo;
  183. struct mtd_oob_buf oob;
  184. loff_t offs;
  185. int ret, readlen;
  186. int oobinfochanged = 0;
  187. struct nand_oobinfo old_oobinfo;
  188. process_options(argc, argv);
  189. if (pad && writeoob) {
  190. fprintf(stderr, "Can't pad when oob data is present.n");
  191. exit(1);
  192. }
  193. /* Open the device */
  194. if ((fd = open(mtd_device, O_RDWR)) == -1) {
  195. perror("open flash");
  196. exit(1);
  197. }
  198. /* Fill in MTD device capability structure */  
  199. if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
  200. perror("MEMGETINFO");
  201. close(fd);
  202. exit(1);
  203. }
  204.         /* Set erasesize to specified number of blocks - to match jffs2 (virtual) block size */
  205.         meminfo.erasesize *= blockalign;
  206.      
  207. /* Make sure device page sizes are valid */
  208. if (!(meminfo.oobsize == 16 && meminfo.oobblock == 512) &&
  209.     !(meminfo.oobsize == 8 && meminfo.oobblock == 256) && 
  210.     !(meminfo.oobsize == 64 && meminfo.oobblock == 2048)) {
  211. fprintf(stderr, "Unknown flash (not normal NAND)n");
  212. close(fd);
  213. exit(1);
  214. }
  215. /* Read the current oob info */
  216. if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
  217. perror ("MEMGETOOBSEL");
  218. close (fd);
  219. exit (1);
  220. // write without ecc ?
  221. if (noecc) {
  222. if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
  223. perror ("MEMSETOOBSEL");
  224. close (fd);
  225. exit (1);
  226. }
  227. oobinfochanged = 1;
  228. }
  229. // autoplace ECC ?
  230. if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
  231. if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
  232. perror ("MEMSETOOBSEL");
  233. close (fd);
  234. exit (1);
  235. oobinfochanged = 1;
  236. }
  237. // force oob layout for jffs2 or yaffs ?
  238. if (forcejffs2 || forceyaffs) {
  239. struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
  240. if (forceyaffs && meminfo.oobsize == 8) {
  241.      if (forceyaffs) {
  242. fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
  243. goto restoreoob;
  244. }
  245. /* Adjust number of ecc bytes */
  246. jffs2_oobinfo.eccbytes = 3;
  247. }
  248. if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {
  249. perror ("MEMSETOOBSEL");
  250. goto restoreoob;
  251. }
  252. oob.length = meminfo.oobsize;
  253. oob.ptr = oobbuf;
  254. /* Open the input file */
  255. if ((ifd = open(img, O_RDONLY)) == -1) {
  256. perror("open input file");
  257. goto restoreoob;
  258. }
  259. // get image length
  260.     imglen = lseek(ifd, 0, SEEK_END);
  261. lseek (ifd, 0, SEEK_SET);
  262. pagelen = meminfo.oobblock + ((writeoob == 1) ? meminfo.oobsize : 0);
  263. // Check, if file is pagealigned
  264. if ((!pad) && ((imglen % pagelen) != 0)) {
  265. perror ("Input file is not page aligned");
  266. goto closeall;
  267. }
  268. // Check, if length fits into device
  269. if ( ((imglen / pagelen) * meminfo.oobblock) > (meminfo.size - mtdoffset)) {
  270. perror ("Input file does not fit into device");
  271. goto closeall;
  272. }
  273. /* Get data from input and write to the device */
  274. while (imglen && (mtdoffset < meminfo.size)) {
  275. // new eraseblock , check for bad block(s)
  276. // Stay in the loop to be sure if the mtdoffset changes because
  277. // of a bad block, that the next block that will be written to
  278. // is also checked. Thus avoiding errors if the block(s) after the 
  279. // skipped block(s) is also bad (number of blocks depending on 
  280. // the blockalign
  281. while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
  282. blockstart = mtdoffset & (~meminfo.erasesize + 1);
  283. offs = blockstart;
  284.         baderaseblock = 0;
  285. if (!quiet)
  286. fprintf (stdout, "Writing data to block %xn", blockstart);
  287.    
  288.         /* Check all the blocks in an erase block for bad blocks */
  289. do {
  290.     if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
  291. perror("ioctl(MEMGETBADBLOCK)");
  292. goto closeall;
  293. }
  294. if (ret == 1) {
  295. baderaseblock = 1;
  296.     if (!quiet)
  297. fprintf (stderr, "Bad block at %x, %u block(s) from %x will be skippedn", (int) offs, blockalign, blockstart);
  298. }
  299.    
  300. if (baderaseblock) {    
  301. mtdoffset = blockstart + meminfo.erasesize;
  302. }
  303.         offs +=  meminfo.erasesize / blockalign ;
  304. } while ( offs < blockstart + meminfo.erasesize );
  305.  
  306. }
  307. readlen = meminfo.oobblock;
  308. if (pad && (imglen < readlen))
  309. {
  310. readlen = imglen;
  311. memset(writebuf + readlen, 0xff, meminfo.oobblock - readlen);
  312. }
  313. /* Read Page Data from input file */
  314. if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
  315. if (cnt == 0) // EOF
  316. break;
  317. perror ("File I/O error on input file");
  318. goto closeall;
  319. }
  320. if (writeoob) {
  321. /* Read OOB data from input file, exit on failure */
  322. if ((cnt = read(ifd, oobbuf, meminfo.oobsize)) != meminfo.oobsize) {
  323. perror ("File I/O error on input file");
  324. goto closeall;
  325. }
  326. /* Write OOB data first, as ecc will be placed in there*/
  327. oob.start = mtdoffset;
  328. if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
  329. perror ("ioctl(MEMWRITEOOB)");
  330. goto closeall;
  331. }
  332. imglen -= meminfo.oobsize;
  333. }
  334. /* Write out the Page data */
  335. if (pwrite(fd, writebuf, meminfo.oobblock, mtdoffset) != meminfo.oobblock) {
  336. perror ("pwrite");
  337. goto closeall;
  338. }
  339. imglen -= readlen;
  340. mtdoffset += meminfo.oobblock;
  341. }
  342.  closeall:
  343. close(ifd);
  344.  restoreoob:
  345. if (oobinfochanged) {
  346. if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
  347. perror ("MEMSETOOBSEL");
  348. close (fd);
  349. exit (1);
  350. }
  351. close(fd);
  352. if (imglen > 0) {
  353. perror ("Data did not fit into device, due to bad blocksn");
  354. exit (1);
  355. }
  356. /* Return happy */
  357. return 0;
  358. }