Chinaunix首页 | 论坛 | 博客
  • 博客访问: 467246
  • 博文数量: 100
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 955
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-21 09:30
文章分类

全部博文(100)

文章存档

2017年(1)

2016年(16)

2015年(83)

我的朋友

分类: 嵌入式

2015-06-27 11:12:20


点击(此处)折叠或打开

  1. yaoff = nandoff/0x800 * 0x840
  2. nandoff = ya_off/0x840 * 0x800
  3. *cmdtp即cmd_tb_t的位置,执行命令时会一直往下传递(可能传递给下一个命令),万一出错会根据cmdtp打印执行最早的命令的帮助信息。

  4. static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  5. {
  6.     int i, ret = 0;
  7.     ulong addr;
  8.     loff_t off, size, maxsize;
  9.     char *cmd, *s;
  10.     nand_info_t *nand;
  11. #ifdef CONFIG_SYS_NAND_QUIET
  12.     int quiet = CONFIG_SYS_NAND_QUIET;
  13. #else
  14.     int quiet = 0;
  15. #endif /* CONFIG_SYS_NAND_QUIET */
  16.     const char *quiet_str = getenv("quiet");
  17.     int dev = nand_curr_device;
  18.     int repeat = flag & CMD_FLAG_REPEAT;

  19.     /* at least two arguments please */
  20.     if (argc < 2)
  21.         goto usage;

  22.     if (quiet_str)
  23.         quiet = simple_strtoul(quiet_str, NULL, 0) != 0;

  24.     cmd = argv[1];

  25.     /* Only "dump" is repeatable. */
  26.     if (repeat && strcmp(cmd, "dump"))
  27.         return 0;

  28.     if (strcmp(cmd, "info") == 0) {

  29.         putc('\n');
  30.         for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
  31.             if (nand_info[i].name)
  32.                 nand_print_and_set_info(i);
  33.         }
  34.         return 0;
  35.     }

  36.     if (strcmp(cmd, "device") == 0) {
  37.         if (argc < 3) {
  38.             putc('\n');
  39.             if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
  40.                 puts("no devices available\n");
  41.             else
  42.                 nand_print_and_set_info(dev);
  43.             return 0;
  44.         }

  45.         dev = (int)simple_strtoul(argv[2], NULL, 10);
  46.         set_dev(dev);

  47.         return 0;
  48.     }

  49. #ifdef CONFIG_ENV_OFFSET_OOB
  50.     /* this command operates only on the first nand device */
  51.     if (strcmp(cmd, "env.oob") == 0)
  52.         return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
  53. #endif /* CONFIG_ENV_OFFSET_OOB */

  54.     /* The following commands operate on the current device, unless
  55.      * overridden by a partition specifier. Note that if somehow the
  56.      * current device is invalid, it will have to be changed to a valid
  57.      * one before these commands can run, even if a partition specifier
  58.      * for another device is to be used.
  59.      */
  60.     if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
  61.      !nand_info[dev].name) {
  62.         puts("\nno devices available\n");
  63.         return 1;
  64.     }
  65.     nand = &nand_info[dev];

  66.     if (strcmp(cmd, "bad") == 0) {
  67.         printf("\nDevice %d bad blocks:\n", dev);
  68.         for (off = 0; off < nand->size; off += nand->erasesize)
  69.             if (nand_block_isbad(nand, off))
  70.                 printf(" %08llx\n", (unsigned long long)off);
  71.         return 0;
  72.     }

  73.     /*
  74.      * Syntax is:
  75.      * 0 1 2 3 4
  76.      * nand erase [clean] [off size]
  77.      */
  78.     if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
  79.         nand_erase_options_t opts;
  80.         /* "clean" at index 2 means request to write cleanmarker */
  81.         int clean = argc > 2 && !strcmp("clean", argv[2]);
  82.         int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
  83.         int o = (clean || scrub_yes) ? 3 : 2;
  84.         int scrub = !strncmp(cmd, "scrub", 5);
  85.         int spread = 0;
  86.         int args = 2;
  87.         const char *scrub_warn =
  88.             "Warning: "
  89.             "scrub option will erase all factory set bad blocks!\n"
  90.             " "
  91.             "There is no reliable way to recover them.\n"
  92.             " "
  93.             "Use this command only for testing purposes if you\n"
  94.             " "
  95.             "are sure of what you are doing!\n"
  96.             "\nReally scrub this NAND flash? <y/N>\n";

  97.         if (cmd[5] != 0) {
  98.             if (!strcmp(&cmd[5], ".spread")) {
  99.                 spread = 1;
  100.             } else if (!strcmp(&cmd[5], ".part")) {
  101.                 args = 1;
  102.             } else if (!strcmp(&cmd[5], ".chip")) {
  103.                 args = 0;
  104.             } else {
  105.                 goto usage;
  106.             }
  107.         }

  108.         /*
  109.          * Don't allow missing arguments to cause full chip/partition
  110.          * erases -- easy to do accidentally, e.g. with a misspelled
  111.          * variable name.
  112.          */
  113.         if (argc != o + args)
  114.             goto usage;

  115.         printf("\nNAND %s: ", cmd);
  116.         /* skip first two or three arguments, look for offset and size */
  117.         if (arg_off_size(argc - o, argv + o, &dev, &off, &size,
  118.                  &maxsize) != 0)
  119.             return 1;

  120.         nand = &nand_info[dev];


  121. //擦除初始化
  122.         memset(&opts, 0, sizeof(opts));
  123.         opts.offset = off;
  124.         opts.length = size;
  125.         opts.jffs2 = clean;//jffs2专用
  126.         opts.quiet = quiet;
  127.         opts.spread = spread;// 遇到坏块是否要忽略,总擦除长度 = length + 坏块

  128.         if (scrub) {
  129.             if (!scrub_yes)
  130.                 puts(scrub_warn);

  131.             if (scrub_yes)
  132.                 opts.scrub = 1;
  133.             else if (getc() == 'y') {
  134.                 puts("y");
  135.                 if (getc() == '\r')
  136.                     opts.scrub = 1;
  137.                 else {
  138.                     puts("scrub aborted\n");
  139.                     return 1;
  140.                 }
  141.             } else {
  142.                 puts("scrub aborted\n");
  143.                 return 1;
  144.             }
  145.         }
  146.         ret = nand_erase_opts(nand, &opts);//开始擦除
  147.         printf("%s\n", ret ? "ERROR" : "OK");

  148.         return ret == 0 ? 0 : 1;
  149.     }

  150.     if (strncmp(cmd, "dump", 4) == 0) {
  151.         if (argc < 3)
  152.             goto usage;

  153.         off = (int)simple_strtoul(argv[2], NULL, 16);
  154.         ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);

  155.         return ret == 0 ? 1 : 0;
  156.     }

  157. //读写命令从这里开始,cmd = argv[1]
  158.     if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
  159. //比较前4个是否等于"read""write"
  160.         size_t rwsize;
  161.         ulong pagecount = 1;
  162.         int read;
  163.         int raw = 0;

  164.         if (argc < 4)//读写命令的参数至少是4个。
  165.             goto usage;

  166.         addr = (ulong)simple_strtoul(argv[2], NULL, 16);//十六进制字符串转地址(十进制),addr是内存地址

  167.         read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
  168.         printf("\nNAND %s: ", read ? "read" : "write");

  169.         nand = &nand_info[dev];//获得当前nand设备对象,dev = nand_curr_device
  170.         s = strchr(cmd, '.');//移动指针到 '.'

  171.         if (s && !strcmp(s, ".raw")) { //如果搜raw格式的读写
  172.             raw = 1;

  173.             if (arg_off(argv[3], &dev, &off, &size, &maxsize))//调用arg_off从参数获取off size maxsize等参数
  174.                 return 1;

  175.             if (argc > 4 && !str2long(argv[4], &pagecount)) {
  176.                 printf("'%s' is not a number\n", argv[4]);
  177.                 return 1;
  178.             }

  179.             if (pagecount * nand->writesize > size) {
  180.                 puts("Size exceeds partition or device limit\n");
  181.                 return -1;
  182.             }

  183.             rwsize = pagecount * (nand->writesize + nand->oobsize);
  184.         } else {// 如果找不到 '.',则说明命令格式为 nand read add off [size]或者 nand write addr off [size]
  185.         
  186.         //从argv[3]获得十进制off,size maxsize。如果不是分区名,默认size = maxsize(off后面的所有空间)
  187.         //如果argc=5,则有size参数,argc-3 = 2,argv + 3 = offset
  188.         if (arg_off_size(argc - 3, argv + 3, &dev,
  189.                         &off, &size, &maxsize) != 0)    
  190.                 return 1;

  191.             if (argc < 5)////如果参数没有指定size,说明offset是分区名
  192.             //我们需要调整size和maxsize忽略坏块,以免读写超出分区边界
  193.                 adjust_size_for_badblocks(&size, off, dev);
  194.             rwsize = size;//得到读写长度
  195.         }

  196. //如果read或write不带.参数、或者.jffs2 .e .i
  197.         if (!s || !strcmp(s, ".jffs2") ||
  198.          !strcmp(s, ".e") || !strcmp(s, ".i")) {
  199.             if (read)
  200.                 ret = nand_read_skip_bad(nand, off, &rwsize,
  201.                              NULL, maxsize,
  202.                              (u_char *)addr);
  203.             else
  204.                 ret = nand_write_skip_bad(nand, off, &rwsize,
  205.                              NULL, maxsize,
  206.                              (u_char *)addr, flag);
  207. #ifdef CONFIG_CMD_NAND_TRIMFFS
  208.         } else if (!strcmp(s, ".trimffs")) {
  209.             if (read) {
  210.                 printf("Unknown nand command suffix '%s'\n", s);
  211.                 return 1;
  212.             }
  213.             ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
  214.                         maxsize, (u_char *)addr,
  215.                         WITH_DROP_FFS);
  216. #endif
  217. #ifdef CONFIG_CMD_NAND_YAFFS
  218.         } else if (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs2")) {
  219.             if (read) {
  220.                 printf("Unknown nand command suffix '%s'.\n", s);
  221.                 return 1;
  222.             }
  223.             ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
  224.                         maxsize, (u_char *)addr,
  225.                         flag | WITH_YAFFS_OOB);
  226. #endif /* CONFIG_CMD_NAND_YAFFS */
  227.         } else if (!strcmp(s, ".oob")) {
  228.             /* out-of-band data */
  229.             mtd_oob_ops_t ops = {
  230.                 .oobbuf = (u8 *)addr,
  231.                 .ooblen = rwsize,
  232.                 .mode = MTD_OPS_RAW
  233.             };

  234.             if (read)
  235.                 ret = mtd_read_oob(nand, off, &ops);
  236.             else
  237.                 ret = mtd_write_oob(nand, off, &ops);
  238.         } else if (raw) {
  239.             ret = raw_access(nand, addr, off, pagecount, read);
  240.         } else {
  241.             printf("Unknown nand command suffix '%s'.\n", s);
  242.             return 1;
  243.         }

  244.         printf(" %zu bytes %s: %s\n", rwsize,
  245.          read ? "read" : "written", ret ? "ERROR" : "OK");

  246.         return ret == 0 ? 0 : 1;
  247.     }

  248. #ifdef CONFIG_CMD_NAND_TORTURE
  249.     if (strcmp(cmd, "torture") == 0) {
  250.         if (argc < 3)
  251.             goto usage;

  252.         if (!str2off(argv[2], &off)) {
  253.             puts("Offset is not a valid number\n");
  254.             return 1;
  255.         }

  256.         printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n",
  257.             dev, off, nand->erasesize);
  258.         ret = nand_torture(nand, off);
  259.         printf(" %s\n", ret ? "Failed" : "Passed");

  260.         return ret == 0 ? 0 : 1;
  261.     }
  262. #endif /* CONFIG_CMD_NAND_TORTURE */

  263.     if (strcmp(cmd, "markbad") == 0) {
  264.         argc -= 2;
  265.         argv += 2;

  266.         if (argc <= 0)
  267.             goto usage;

  268.         while (argc > 0) {
  269.             addr = simple_strtoul(*argv, NULL, 16);

  270.             if (mtd_block_markbad(nand, addr)) {
  271.                 printf("block 0x%08lx NOT marked "
  272.                     "as bad! ERROR %d\n",
  273.                     addr, ret);
  274.                 ret = 1;
  275.             } else {
  276.                 printf("block 0x%08lx successfully "
  277.                     "marked as bad\n",
  278.                     addr);
  279.             }
  280.             --argc;
  281.             ++argv;
  282.         }
  283.         return ret;
  284.     }

  285.     if (strcmp(cmd, "biterr") == 0) {
  286.         /* todo */
  287.         return 1;
  288.     }

  289. #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
  290.     if (strcmp(cmd, "lock") == 0) {
  291.         int tight = 0;
  292.         int status = 0;
  293.         if (argc == 3) {
  294.             if (!strcmp("tight", argv[2]))
  295.                 tight = 1;
  296.             if (!strcmp("status", argv[2]))
  297.                 status = 1;
  298.         }
  299.         if (status) {
  300.             do_nand_status(nand);
  301.         } else {
  302.             if (!nand_lock(nand, tight)) {
  303.                 puts("NAND flash successfully locked\n");
  304.             } else {
  305.                 puts("Error locking NAND flash\n");
  306.                 return 1;
  307.             }
  308.         }
  309.         return 0;
  310.     }

  311.     if (strncmp(cmd, "unlock", 5) == 0) {
  312.         int allexcept = 0;

  313.         s = strchr(cmd, '.');

  314.         if (s && !strcmp(s, ".allexcept"))
  315.             allexcept = 1;

  316.         if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
  317.                  &maxsize) < 0)
  318.             return 1;

  319.         if (!nand_unlock(&nand_info[dev], off, size, allexcept)) {
  320.             puts("NAND flash successfully unlocked\n");
  321.         } else {
  322.             puts("Error unlocking NAND flash, "
  323.              "write and erase will probably fail\n");
  324.             return 1;
  325.         }
  326.         return 0;
  327.     }
  328. #endif /* CONFIG_CMD_NAND_LOCK_UNLOCK */

  329. usage:
  330.     return CMD_RET_USAGE;
  331. }

  332. //字符串转为偏移地址,如果是分区名同时得到size,最大可写长度
  333. static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
  334.         loff_t *maxsize)
  335. {
  336.     if (!str2off(arg, off))//字符串转换为偏移地址,参数可以是分区名,失败则认为参数是分区名,调用get_part得到off size 和maxsize,return
  337.         return get_part(arg, idx, off, size, maxsize);

  338.     if (*off >= nand_info[*idx].size) { //如果偏移地址超过nand容量则报错
  339.         puts("Offset exceeds device limit\n");
  340.         return -1;
  341.     }

  342.     *maxsize = nand_info[*idx].size - *off;//如果off不是分区名,得到最大可写长度 = size -off
  343.     *size = *maxsize;//写入尺寸等于最大可写长度,后面会修改
  344.     return 0;
  345. }

  346. //封装arg_off函数
  347. int arg_off_size(int argc, char *const argv[], int *idx,
  348.             loff_t *off, loff_t *size, loff_t *maxsize)
  349. {
  350.     int ret;

  351.     if (argc == 0) {
  352.         *off = 0;
  353.         *size = nand_info[*idx].size;//如果没有参数,则写长度为whole chip,size和maxsize默认最大值
  354.         *maxsize = *size;
  355.         goto print;
  356.     }

  357.     ret = arg_off(argv[0], idx, off, size, maxsize);
  358.     //字符串转为偏移地址,如果是分区名则得到写长度size和最大可写长度,立即return,否则size和maxsize默认最大值
  359.     if (ret)
  360.         return ret;

  361.     if (argc == 1)
  362.         goto print;

  363.     if (!str2off(argv[1], size)) {//从argv[1]转为size
  364.         printf("'%s' is not a number\n", argv[1]);
  365.         return -1;
  366.     }

  367.     if (*size > *maxsize) {
  368.         puts("Size exceeds partition or device limit\n");
  369.         return -1;
  370.     }

  371. print:
  372.     printf("device %d ", *idx);
  373.     if (*size == nand_info[*idx].size)
  374.         puts("whole chip\n");
  375.     else
  376.         printf("offset 0x%llx, size 0x%llx\n",
  377.          (unsigned long long)*off, (unsigned long long)*size);
  378.     return 0;
  379. }


  380. //如果参数没有指定size,我们需要忽略坏块,调整size和offset(减去坏块长度)
  381. void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
  382. {
  383.     /* We grab the nand info object here fresh because this is usually
  384.      * called after arg_off_size() which can change the value of dev.
  385.      */
  386.     nand_info_t *nand = &nand_info[dev];//获取nand对象
  387.     loff_t maxoffset = offset + *size;//最大偏移,如果指定了分区,则maxoffset为分区边界;如果没有指定分区,则maxoffset为nand边界
  388.     int badblocks = 0;

  389.     /* count badblocks in NAND from offset to offset + size */
  390.     for (; offset < maxoffset; offset += nand->erasesize) {
  391.         if (nand_block_isbad(nand, offset))
  392.             badblocks++;//统计坏块
  393.     }
  394.     /* adjust size if any bad blocks found */
  395.     if (badblocks) {
  396.         *size -= badblocks * nand->erasesize;
  397.         printf("size adjusted to 0x%llx (%d bad blocks)\n",
  398.          (unsigned long long)*size, badblocks);//有x个坏块,因此size会减少(x * erasesize)
  399.     }
  400. }

阅读(2316) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~