static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) { #ifdef CONFIG_CMD_MTDPARTS struct mtd_device *dev; struct part_info *part; u8 pnum; int ret; ret = mtdparts_init(); if (ret) return ret; ret = find_dev_and_part(partname, &dev, &pnum, &part); if (ret) return ret; if (dev->id->type != MTD_DEV_TYPE_NAND) { puts("not a NAND device\n"); return -1; } *off = part->offset; *size = part->size; *idx = dev->id->num; ret = set_dev(*idx); if (ret) return ret; return 0; #else puts("offset is not a number\n"); return -1; #endif }
int sgen_next(sgen **xsg) { sgen *sg = *xsg; int good, done; int i; done = 0; i = sg->dev; do { if (sg->instance) { if (sg->ptable) { do { sg->param += 1; } while (sg->param < sg->max_param && !set_param(sg)); } else { sg->max_param = -1; } if (sg->param < sg->max_param) { done = 1; } else if (!sg->is_instparam) { /* Try instance parameters now */ sg->is_instparam = 1; sg->param = -1; sg->max_param = *DEVices[i]->DEVpublic.numInstanceParms; sg->ptable = DEVices[i]->DEVpublic.instanceParms; } else { sg->is_principle = 0; sg->instance->GENnextInstance = sg->next_instance; sg->instance->GENstate = sg->istate; sg->instance = NULL; } } else if (sg->model) { /* Find the first/next good instance for this model */ for (good = 0; !good && sg->next_instance; good = set_inst(sg)) { sg->instance = sg->next_instance; sg->next_instance = sg->instance->GENnextInstance; } if (good) { sg->is_principle = 0; sg->istate = sg->instance->GENstate; sg->instance->GENnextInstance = NULL; sg->model->GENinstances = sg->instance; if (DEVices[i]->DEVpublic.modelParms) { sg->max_param = *DEVices[i]->DEVpublic. numModelParms; sg->ptable = DEVices[i]->DEVpublic. modelParms; } else { sg->ptable = NULL; } sg->param = -1; sg->is_instparam = 0; } else { /* No good instances of this model */ sg->model->GENinstances = sg->first_instance; sg->model->GENnextModel = sg->next_model; sg->model = NULL; } } else if (i >= 0) { /* Find the first/next good model for this device */ for (good = 0; !good && sg->next_model; good = set_model(sg)) { sg->model = sg->next_model; sg->next_model = sg->model->GENnextModel; } if (good) { sg->model->GENnextModel = NULL; sg->devlist[i] = sg->model; if (DEVices[i]->DEVpublic.modelParms) { sg->max_param = *DEVices[i]->DEVpublic. numModelParms; sg->ptable = DEVices[i]->DEVpublic. modelParms; } else { sg->ptable = NULL; } sg->next_instance = sg->first_instance = sg->model->GENinstances; } else { /* No more good models for this device */ sg->devlist[i] = sg->first_model; i = -1; /* Try the next good device */ } } else if (i < DEVmaxnum && sg->dev < DEVmaxnum) { /* Find the next good device in this circuit */ do sg->dev++; while (sg->dev < DEVmaxnum && sg->devlist[sg->dev] && !set_dev(sg)); i = sg->dev; if (i >= DEVmaxnum) /* PN: Segafult if not = */ done = 1; sg->first_model = sg->next_model = (i<DEVmaxnum) ? sg->devlist[i] : NULL; } else { done = 1; } } while (!done); if (sg->dev >= DEVmaxnum) { FREE(sg); *xsg = NULL; } return 1; }
static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, int read) { int ret = 0; while (count--) { /* Raw access */ mtd_oob_ops_t ops = { .datbuf = (u8 *)addr, .oobbuf = ((u8 *)addr) + nand->writesize, .len = nand->writesize, .ooblen = nand->oobsize, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); if (ret) { printf("%s: error at offset %llx, ret %d\n", __func__, (long long)off, ret); break; } addr += nand->writesize + nand->oobsize; off += nand->writesize; } return ret; } int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; ulong addr; loff_t off, size, maxsize; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); int dev = nand_curr_device; int repeat = flag & CMD_FLAG_REPEAT; /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; /* Only "dump" is repeatable. */ if (repeat && strcmp(cmd, "dump")) return 0; if (strcmp(cmd, "info") == 0) { putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) nand_print_and_set_info(i); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE) puts("no devices available\n"); else nand_print_and_set_info(dev); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); set_dev(dev); return 0; } #ifdef CONFIG_ENV_OFFSET_OOB /* this command operates only on the first nand device */ if (strcmp(cmd, "env.oob") == 0) return do_nand_env_oob(cmdtp, argc - 1, argv + 1); #endif /* The following commands operate on the current device, unless * overridden by a partition specifier. Note that if somehow the * current device is invalid, it will have to be changed to a valid * one before these commands can run, even if a partition specifier * for another device is to be used. */ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) { puts("\nno devices available\n"); return 1; } nand = &nand_info[dev]; if (strcmp(cmd, "bad") == 0) { printf("\nDevice %d bad blocks:\n", dev); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %08llx\n", (unsigned long long)off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int scrub_yes = argc > 2 && !strcmp("-y", argv[2]); int o = (clean || scrub_yes) ? 3 : 2; int scrub = !strncmp(cmd, "scrub", 5); int spread = 0; int args = 2; const char *scrub_warn = "Warning: " "scrub option will erase all factory set bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"; if (cmd[5] != 0) { if (!strcmp(&cmd[5], ".spread")) { spread = 1; } else if (!strcmp(&cmd[5], ".part")) { args = 1; } else if (!strcmp(&cmd[5], ".chip")) { args = 0; } else { goto usage; } } /* * Don't allow missing arguments to cause full chip/partition * erases -- easy to do accidentally, e.g. with a misspelled * variable name. */ if (argc != o + args) goto usage; printf("\nNAND %s: ", cmd); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, &dev, &off, &size, &maxsize) != 0) return 1; nand = &nand_info[dev]; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; opts.spread = spread; if (scrub) { if (!scrub_yes) puts(scrub_warn); if (scrub_yes) opts.scrub = 1; else if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; else { puts("scrub aborted\n"); return -1; } } else { puts("scrub aborted\n"); return -1; } } ret = nand_erase_opts(nand, &opts); printf("%s\n", ret ? "ERROR" : "OK"); return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; off = (int)simple_strtoul(argv[2], NULL, 16); ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { size_t rwsize; ulong pagecount = 1; int read; int raw; if (argc < 4) goto usage; addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); nand = &nand_info[dev]; s = strchr(cmd, '.'); if (s && !strcmp(s, ".raw")) { raw = 1; if (arg_off(argv[3], &dev, &off, &size, &maxsize)) return 1; if (argc > 4 && !str2long(argv[4], &pagecount)) { printf("'%s' is not a number\n", argv[4]); return 1; } if (pagecount * nand->writesize > size) { puts("Size exceeds partition or device limit\n"); return -1; } rwsize = pagecount * (nand->writesize + nand->oobsize); } else { if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size, &maxsize) != 0) return 1; rwsize = size; } if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, 0); #ifdef CONFIG_CMD_NAND_TRIMFFS } else if (!strcmp(s, ".trimffs")) { if (read) { printf("Unknown nand command suffix '%s'\n", s); return 1; } ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, WITH_DROP_FFS); #endif #ifdef CONFIG_CMD_NAND_YAFFS } else if (!strcmp(s, ".yaffs")) { if (read) { printf("Unknown nand command suffix '%s'.\n", s); return 1; } ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, WITH_YAFFS_OOB); #endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = rwsize, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else if (raw) {
int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) { int ret; uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)]; nand_info_t *nand = &nand_info[0]; char *cmd = argv[1]; if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) { puts("no devices available\n"); return 1; } set_dev(0); if (!strcmp(cmd, "get")) { ret = get_nand_env_oob(nand, &nand_env_oob_offset); if (ret) return 1; printf("0x%08lx\n", nand_env_oob_offset); } else if (!strcmp(cmd, "set")) { loff_t addr; loff_t maxsize; struct mtd_oob_ops ops; int idx = 0; if (argc < 3) goto usage; /* We don't care about size, or maxsize. */ if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) { puts("Offset or partition name expected\n"); return 1; } if (idx != 0) { puts("Partition not on first NAND device\n"); return 1; } if (nand->oobavail < ENV_OFFSET_SIZE) { printf("Insufficient available OOB bytes:\n" "%d OOB bytes available but %d required for " "env.oob support\n", nand->oobavail, ENV_OFFSET_SIZE); return 1; } if ((addr & (nand->erasesize - 1)) != 0) { printf("Environment offset must be block-aligned\n"); return 1; } ops.datbuf = NULL; ops.mode = MTD_OOB_AUTO; ops.ooboffs = 0; ops.ooblen = ENV_OFFSET_SIZE; ops.oobbuf = (void *) oob_buf; oob_buf[0] = ENV_OOB_MARKER; oob_buf[1] = addr / nand->erasesize; ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops); if (ret) { printf("Error writing OOB block 0\n"); return ret; } ret = get_nand_env_oob(nand, &nand_env_oob_offset); if (ret) { printf("Error reading env offset in OOB\n"); return ret; } if (addr != nand_env_oob_offset) { printf("Verification of env offset in OOB failed: " "0x%08llx expected but got 0x%08lx\n", (unsigned long long)addr, nand_env_oob_offset); return 1; } } else { goto usage; } return ret; usage: return CMD_RET_USAGE; }
int main(int ac, char *av[]) { int ch, res, rv, nread; size_t b_size = MIN_SIZE; char *buf, chb[READB_LEN]; fd_set fd_s; (void) setlocale(LC_TIME, ""); if (isatty(std_out)) opt_interactive = 1; else opt_interactive = 0; while ((ch = getopt(ac, av, "Wciotnf:")) != -1) switch (ch) { case 'W': opt_write = 1; break; case 'c': opt_reconn_close = 1; break; case 'i': opt_interactive = 1; break; case 'o': opt_reconn_oflow = 1; break; case 't': opt_timestamp = 1; break; case 'n': opt_no_switch = 1; break; case 'f': opt_snpdev = optarg; break; case '?': default: usage(); } if (modfind("snp") == -1) if (kldload("snp") == -1 || modfind("snp") == -1) warn("snp module not available"); signal(SIGINT, cleanup); snp_io = open_snp(); setup_scr(); if (*(av += optind) == NULL) { if (opt_interactive && !opt_no_switch) ask_dev(dev_name, MSG_INIT); else fatal(EX_DATAERR, "no device name given"); } else strncpy(dev_name, *av, DEV_NAME_LEN); set_dev(dev_name); if (!(buf = (char *) malloc(b_size))) fatal(EX_UNAVAILABLE, "malloc failed"); FD_ZERO(&fd_s); while (1) { if (opt_interactive) FD_SET(std_in, &fd_s); FD_SET(snp_io, &fd_s); res = select(snp_io + 1, &fd_s, NULL, NULL, NULL); if (opt_interactive && FD_ISSET(std_in, &fd_s)) { if ((res = ioctl(std_in, FIONREAD, &nread)) != 0) fatal(EX_OSERR, "ioctl(FIONREAD)"); if (nread > READB_LEN) nread = READB_LEN; rv = read(std_in, chb, nread); if (rv == -1 || rv != nread) fatal(EX_IOERR, "read (stdin) failed"); switch (chb[0]) { case CHR_CLEAR: clear(); break; case CHR_SWITCH: if (!opt_no_switch) { detach_snp(); ask_dev(dev_name, MSG_CHANGE); set_dev(dev_name); break; } default: if (opt_write) { rv = write(snp_io, chb, nread); if (rv == -1 || rv != nread) { detach_snp(); if (opt_no_switch) fatal(EX_IOERR, "write failed"); ask_dev(dev_name, MSG_NOWRITE); set_dev(dev_name); } } } } if (!FD_ISSET(snp_io, &fd_s)) continue; if ((res = ioctl(snp_io, FIONREAD, &nread)) != 0) fatal(EX_OSERR, "ioctl(FIONREAD)"); switch (nread) { case SNP_OFLOW: if (opt_reconn_oflow) attach_snp(); else if (opt_interactive && !opt_no_switch) { ask_dev(dev_name, MSG_OFLOW); set_dev(dev_name); } else cleanup(-1); break; case SNP_DETACH: case SNP_TTYCLOSE: if (opt_reconn_close) attach_snp(); else if (opt_interactive && !opt_no_switch) { ask_dev(dev_name, MSG_CLOSED); set_dev(dev_name); } else cleanup(-1); break; default: if (nread < (b_size / 2) && (b_size / 2) > MIN_SIZE) { free(buf); if (!(buf = (char *) malloc(b_size / 2))) fatal(EX_UNAVAILABLE, "malloc failed"); b_size = b_size / 2; } if (nread > b_size) { b_size = (nread % 2) ? (nread + 1) : (nread); free(buf); if (!(buf = (char *) malloc(b_size))) fatal(EX_UNAVAILABLE, "malloc failed"); } rv = read(snp_io, buf, nread); if (rv == -1 || rv != nread) fatal(EX_IOERR, "read failed"); rv = write(std_out, buf, nread); if (rv == -1 || rv != nread) fatal(EX_IOERR, "write failed"); } } /* While */ return(0); }