📄 nandsim.c
字号:
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 voidns_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; } /* * Chip might still be in STATE_DATAOUT * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or * STATE_DATAOUT_STATUS_M state. If so, switch state. */ if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M || ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT)) switch_state(ns); /* 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)); } /* Check that the command byte is correct */ if (check_command(byte)) { NS_ERR("write_byte: unknown command %#x\n", (uint)byte); return; } 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 intns_device_ready(struct mtd_info *mtd){ NS_DBG("device_ready\n"); return 1;}static uint16_tns_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 voidns_nand_write_word(struct mtd_info *mtd, uint16_t word){ struct nand_chip *chip = (struct nand_chip *)mtd->priv; NS_DBG("write_word\n"); chip->write_byte(mtd, word & 0xFF); chip->write_byte(mtd, word >> 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 */int __init ns_init_module(void){ struct nand_chip *chip; struct nandsim *nand; int retval = -ENOMEM; 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 = kmalloc(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; } memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct nandsim)); chip = (struct nand_chip *)(nsmtd + 1); nsmtd->priv = (void *)chip; nand = (struct nandsim *)(chip + 1); chip->priv = (void *)nand; /* * Register simulator's callbacks. */ chip->hwcontrol = ns_hwcontrol; chip->read_byte = ns_nand_read_byte; chip->dev_ready = ns_device_ready; chip->write_byte = ns_nand_write_byte; chip->write_buf = ns_nand_write_buf; chip->read_buf = ns_nand_read_buf; chip->verify_buf = ns_nand_verify_buf; chip->write_word = ns_nand_write_word; chip->read_word = ns_nand_read_word; chip->eccmode = NAND_ECC_SOFT; 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; } if ((retval = nand_scan(nsmtd, 1)) != 0) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) retval = -ENXIO; goto error; } if ((retval = init_nandsim(nsmtd)) != 0) { NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); goto error; } if ((retval = nand_default_bbt(nsmtd)) != 0) { free_nandsim(nand); goto error; } /* Register NAND as one big partition */ add_mtd_partitions(nsmtd, &nand->part, 1); return 0;error: kfree(nsmtd); 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); free_nandsim(ns); /* Free nandsim private resources */ nand_release(nsmtd); /* Unregisterd drived */ kfree(nsmtd); /* Free other structures */}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 + -