📄 nandsim.c
字号:
/* * If the next state is address input, set the internal * register to the number of expected address bytes */ ns->regs.count = 0; switch (NS_STATE(ns->nxstate)) { case STATE_ADDR_PAGE: ns->regs.num = ns->geom.pgaddrbytes; break; case STATE_ADDR_SEC: ns->regs.num = ns->geom.secaddrbytes; break; case STATE_ADDR_ZERO: ns->regs.num = 1; break; case STATE_ADDR_COLUMN: /* Column address is always 2 bytes */ ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes; break; default: NS_ERR("switch_state: BUG! unknown address state\n"); } } else { /* * Just reset internal counters. */ ns->regs.num = 0; ns->regs.count = 0; }}static u_char ns_nand_read_byte(struct mtd_info *mtd){ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; u_char outb = 0x00; /* Sanity and correctness checks */ if (!ns->lines.ce) { NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb); return outb; } if (ns->lines.ale || ns->lines.cle) { NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb); return outb; } if (!(ns->state & STATE_DATAOUT_MASK)) { NS_WARN("read_byte: unexpected data output cycle, state is %s " "return %#x\n", get_state_name(ns->state), (uint)outb); return outb; } /* Status register may be read as many times as it is wanted */ if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) { NS_DBG("read_byte: return %#x status\n", ns->regs.status); return ns->regs.status; } /* Check if there is any data in the internal buffer which may be read */ if (ns->regs.count == ns->regs.num) { NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb); return outb; } switch (NS_STATE(ns->state)) { case STATE_DATAOUT: if (ns->busw == 8) { outb = ns->buf.byte[ns->regs.count]; ns->regs.count += 1; } else { outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]); ns->regs.count += 2; } break; case STATE_DATAOUT_ID: NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num); outb = ns->ids[ns->regs.count]; ns->regs.count += 1; break; default: BUG(); } if (ns->regs.count == ns->regs.num) { NS_DBG("read_byte: all bytes were read\n"); /* * The OPT_AUTOINCR allows to read next conseqitive pages without * new read operation cycle. */ if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { ns->regs.count = 0; if (ns->regs.row + 1 < ns->geom.pgnum) ns->regs.row += 1; NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row); do_state_action(ns, ACTION_CPY); } else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); } return outb;}static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte){ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; /* Sanity and correctness checks */ if (!ns->lines.ce) { NS_ERR("write_byte: chip is disabled, ignore write\n"); return; } if (ns->lines.ale && ns->lines.cle) { NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); return; } if (ns->lines.cle == 1) { /* * The byte written is a command. */ if (byte == NAND_CMD_RESET) { NS_LOG("reset chip\n"); switch_to_ready_state(ns, NS_STATUS_OK(ns)); return; } /* Check that the command byte is correct */ if (check_command(byte)) { NS_ERR("write_byte: unknown command %#x\n", (uint)byte); return; } if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M || NS_STATE(ns->state) == STATE_DATAOUT) { int row = ns->regs.row; switch_state(ns); if (byte == NAND_CMD_RNDOUT) ns->regs.row = row; } /* Check if chip is expecting command */ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { /* * We are in situation when something else (not command) * was expected but command was input. In this case ignore * previous command(s)/state(s) and accept the last one. */ NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } NS_DBG("command byte corresponding to %s state accepted\n", get_state_name(get_state_by_command(byte))); ns->regs.command = byte; switch_state(ns); } else if (ns->lines.ale == 1) { /* * The byte written is an address. */ if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) { NS_DBG("write_byte: operation isn't known yet, identify it\n"); if (find_operation(ns, 1) < 0) return; if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } ns->regs.count = 0; switch (NS_STATE(ns->nxstate)) { case STATE_ADDR_PAGE: ns->regs.num = ns->geom.pgaddrbytes; break; case STATE_ADDR_SEC: ns->regs.num = ns->geom.secaddrbytes; break; case STATE_ADDR_ZERO: ns->regs.num = 1; break; default: BUG(); } } /* Check that chip is expecting address */ if (!(ns->nxstate & STATE_ADDR_MASK)) { NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, " "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate)); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } /* Check if this is expected byte */ if (ns->regs.count == ns->regs.num) { NS_ERR("write_byte: no more address bytes expected\n"); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } accept_addr_byte(ns, byte); ns->regs.count += 1; NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n", (uint)byte, ns->regs.count, ns->regs.num); if (ns->regs.count == ns->regs.num) { NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); switch_state(ns); } } else { /* * The byte written is an input data. */ /* Check that chip is expecting data input */ if (!(ns->state & STATE_DATAIN_MASK)) { NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " "switch to %s\n", (uint)byte, get_state_name(ns->state), get_state_name(STATE_READY)); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } /* Check if this is expected byte */ if (ns->regs.count == ns->regs.num) { NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n", ns->regs.num); return; } if (ns->busw == 8) { ns->buf.byte[ns->regs.count] = byte; ns->regs.count += 1; } else { ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte); ns->regs.count += 2; } } return;}static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask){ struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv; ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; ns->lines.ale = bitmask & NAND_ALE ? 1 : 0; ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; if (cmd != NAND_CMD_NONE) ns_nand_write_byte(mtd, cmd);}static int ns_device_ready(struct mtd_info *mtd){ NS_DBG("device_ready\n"); return 1;}static uint16_t ns_nand_read_word(struct mtd_info *mtd){ struct nand_chip *chip = (struct nand_chip *)mtd->priv; NS_DBG("read_word\n"); return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);}static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len){ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; /* Check that chip is expecting data input */ if (!(ns->state & STATE_DATAIN_MASK)) { NS_ERR("write_buf: data input isn't expected, state is %s, " "switch to STATE_READY\n", get_state_name(ns->state)); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } /* Check if these are expected bytes */ if (ns->regs.count + len > ns->regs.num) { NS_ERR("write_buf: too many input bytes\n"); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } memcpy(ns->buf.byte + ns->regs.count, buf, len); ns->regs.count += len; if (ns->regs.count == ns->regs.num) { NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); }}static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){ struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; /* Sanity and correctness checks */ if (!ns->lines.ce) { NS_ERR("read_buf: chip is disabled\n"); return; } if (ns->lines.ale || ns->lines.cle) { NS_ERR("read_buf: ALE or CLE pin is high\n"); return; } if (!(ns->state & STATE_DATAOUT_MASK)) { NS_WARN("read_buf: unexpected data output cycle, current state is %s\n", get_state_name(ns->state)); return; } if (NS_STATE(ns->state) != STATE_DATAOUT) { int i; for (i = 0; i < len; i++) buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd); return; } /* Check if these are expected bytes */ if (ns->regs.count + len > ns->regs.num) { NS_ERR("read_buf: too many bytes to read\n"); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } memcpy(buf, ns->buf.byte + ns->regs.count, len); ns->regs.count += len; if (ns->regs.count == ns->regs.num) { if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { ns->regs.count = 0; if (ns->regs.row + 1 < ns->geom.pgnum) ns->regs.row += 1; NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row); do_state_action(ns, ACTION_CPY); } else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); } return;}static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){ ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); if (!memcmp(buf, &ns_verify_buf[0], len)) { NS_DBG("verify_buf: the buffer is OK\n"); return 0; } else { NS_DBG("verify_buf: the buffer is wrong\n"); return -EFAULT; }}/* * Module initialization function */static int __init ns_init_module(void){ struct nand_chip *chip; struct nandsim *nand; int retval = -ENOMEM, i; if (bus_width != 8 && bus_width != 16) { NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); return -EINVAL; } /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct nandsim), GFP_KERNEL); if (!nsmtd) { NS_ERR("unable to allocate core structures.\n"); return -ENOMEM; } chip = (struct nand_chip *)(nsmtd + 1); nsmtd->priv = (void *)chip; nand = (struct nandsim *)(chip + 1); chip->priv = (void *)nand; /* * Register simulator's callbacks. */ chip->cmd_ctrl = ns_hwcontrol; chip->read_byte = ns_nand_read_byte; chip->dev_ready = ns_device_ready; chip->write_buf = ns_nand_write_buf; chip->read_buf = ns_nand_read_buf; chip->verify_buf = ns_nand_verify_buf; chip->read_word = ns_nand_read_word; chip->ecc.mode = NAND_ECC_SOFT; /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ /* and 'badblocks' parameters to work */ chip->options |= NAND_SKIP_BBTSCAN; /* * Perform minimum nandsim structure initialization to handle * the initial ID read command correctly */ if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) nand->geom.idbytes = 4; else nand->geom.idbytes = 2; nand->regs.status = NS_STATUS_OK(nand); nand->nxstate = STATE_UNKNOWN; nand->options |= OPT_PAGE256; /* temporary value */ nand->ids[0] = first_id_byte; nand->ids[1] = second_id_byte; nand->ids[2] = third_id_byte; nand->ids[3] = fourth_id_byte; if (bus_width == 16) { nand->busw = 16; chip->options |= NAND_BUSWIDTH_16; } nsmtd->owner = THIS_MODULE; if ((retval = parse_weakblocks()) != 0) goto error; if ((retval = parse_weakpages()) != 0) goto error; if ((retval = parse_gravepages()) != 0) goto error; if ((retval = nand_scan(nsmtd, 1)) != 0) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) retval = -ENXIO; goto error; } if (overridesize) { u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); goto err_exit; } /* N.B. This relies on nand_scan not doing anything with the size before we change it */ nsmtd->size = new_size; chip->chipsize = new_size; chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; } if ((retval = setup_wear_reporting(nsmtd)) != 0) goto err_exit; if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; if ((retval = parse_badblocks(nand, nsmtd)) != 0) goto err_exit; if ((retval = nand_default_bbt(nsmtd)) != 0) goto err_exit; /* Register NAND partitions */ if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) goto err_exit; return 0;err_exit: free_nandsim(nand); nand_release(nsmtd); for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) kfree(nand->partitions[i].name);error: kfree(nsmtd); free_lists(); return retval;}module_init(ns_init_module);/* * Module clean-up function */static void __exit ns_cleanup_module(void){ struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); int i; free_nandsim(ns); /* Free nandsim private resources */ nand_release(nsmtd); /* Unregister driver */ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) kfree(ns->partitions[i].name); kfree(nsmtd); /* Free other structures */ free_lists();}module_exit(ns_cleanup_module);MODULE_LICENSE ("GPL");MODULE_AUTHOR ("Artem B. Bityuckiy");MODULE_DESCRIPTION ("The NAND flash simulator");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -