📄 nandsim.c
字号:
ns->options |= OPT_PAGE512_8BIT; } else if (ns->geom.pgsz == 2048) { ns->options |= OPT_PAGE2048; } else { NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz); return -EIO; } if (ns->options & OPT_SMALLPAGE) { if (ns->geom.totsz < (64 << 20)) { ns->geom.pgaddrbytes = 3; ns->geom.secaddrbytes = 2; } else { ns->geom.pgaddrbytes = 4; ns->geom.secaddrbytes = 3; } } else { if (ns->geom.totsz <= (128 << 20)) { ns->geom.pgaddrbytes = 4; ns->geom.secaddrbytes = 2; } else { ns->geom.pgaddrbytes = 5; ns->geom.secaddrbytes = 3; } } /* Detect how many ID bytes the NAND chip outputs */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (second_id_byte != nand_flash_ids[i].id) continue; if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR)) ns->options |= OPT_AUTOINCR; } if (ns->busw == 16) NS_WARN("16-bit flashes support wasn't tested\n"); printk("flash size: %u MiB\n", ns->geom.totsz >> 20); printk("page size: %u bytes\n", ns->geom.pgsz); printk("OOB area size: %u bytes\n", ns->geom.oobsz); printk("sector size: %u KiB\n", ns->geom.secsz >> 10); printk("pages number: %u\n", ns->geom.pgnum); printk("pages per sector: %u\n", ns->geom.pgsec); printk("bus width: %u\n", ns->busw); printk("bits in sector size: %u\n", ns->geom.secshift); printk("bits in page size: %u\n", ns->geom.pgshift); printk("bits in OOB size: %u\n", ns->geom.oobshift); printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); printk("page address bytes: %u\n", ns->geom.pgaddrbytes); printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); /* Map / allocate and initialize the flash image */#ifdef CONFIG_NS_ABS_POS ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); if (!ns->mem.byte) { NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", (void *)CONFIG_NS_ABS_POS); return -ENOMEM; }#else ns->mem.byte = vmalloc(ns->geom.totszoob); if (!ns->mem.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n", ns->geom.totszoob); return -ENOMEM; } memset(ns->mem.byte, 0xFF, ns->geom.totszoob);#endif /* Allocate / initialize the internal buffer */ ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); if (!ns->buf.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", ns->geom.pgszoob); goto error; } memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); /* Fill the partition_info structure */ ns->part.name = "NAND simulator partition"; ns->part.offset = 0; ns->part.size = ns->geom.totsz; return 0;error:#ifdef CONFIG_NS_ABS_POS iounmap(ns->mem.byte);#else vfree(ns->mem.byte);#endif return -ENOMEM;}/* * Free the nandsim structure. */static voidfree_nandsim(struct nandsim *ns){ kfree(ns->buf.byte);#ifdef CONFIG_NS_ABS_POS iounmap(ns->mem.byte);#else vfree(ns->mem.byte);#endif return;}/* * Returns the string representation of 'state' state. */static char *get_state_name(uint32_t state){ switch (NS_STATE(state)) { case STATE_CMD_READ0: return "STATE_CMD_READ0"; case STATE_CMD_READ1: return "STATE_CMD_READ1"; case STATE_CMD_PAGEPROG: return "STATE_CMD_PAGEPROG"; case STATE_CMD_READOOB: return "STATE_CMD_READOOB"; case STATE_CMD_READSTART: return "STATE_CMD_READSTART"; case STATE_CMD_ERASE1: return "STATE_CMD_ERASE1"; case STATE_CMD_STATUS: return "STATE_CMD_STATUS"; case STATE_CMD_STATUS_M: return "STATE_CMD_STATUS_M"; case STATE_CMD_SEQIN: return "STATE_CMD_SEQIN"; case STATE_CMD_READID: return "STATE_CMD_READID"; case STATE_CMD_ERASE2: return "STATE_CMD_ERASE2"; case STATE_CMD_RESET: return "STATE_CMD_RESET"; case STATE_ADDR_PAGE: return "STATE_ADDR_PAGE"; case STATE_ADDR_SEC: return "STATE_ADDR_SEC"; case STATE_ADDR_ZERO: return "STATE_ADDR_ZERO"; case STATE_DATAIN: return "STATE_DATAIN"; case STATE_DATAOUT: return "STATE_DATAOUT"; case STATE_DATAOUT_ID: return "STATE_DATAOUT_ID"; case STATE_DATAOUT_STATUS: return "STATE_DATAOUT_STATUS"; case STATE_DATAOUT_STATUS_M: return "STATE_DATAOUT_STATUS_M"; case STATE_READY: return "STATE_READY"; case STATE_UNKNOWN: return "STATE_UNKNOWN"; } NS_ERR("get_state_name: unknown state, BUG\n"); return NULL;}/* * Check if command is valid. * * RETURNS: 1 if wrong command, 0 if right. */static intcheck_command(int cmd){ switch (cmd) { case NAND_CMD_READ0: case NAND_CMD_READSTART: case NAND_CMD_PAGEPROG: case NAND_CMD_READOOB: case NAND_CMD_ERASE1: case NAND_CMD_STATUS: case NAND_CMD_SEQIN: case NAND_CMD_READID: case NAND_CMD_ERASE2: case NAND_CMD_RESET: case NAND_CMD_READ1: return 0; case NAND_CMD_STATUS_MULTI: default: return 1; }}/* * Returns state after command is accepted by command number. */static uint32_tget_state_by_command(unsigned command){ switch (command) { case NAND_CMD_READ0: return STATE_CMD_READ0; case NAND_CMD_READ1: return STATE_CMD_READ1; case NAND_CMD_PAGEPROG: return STATE_CMD_PAGEPROG; case NAND_CMD_READSTART: return STATE_CMD_READSTART; case NAND_CMD_READOOB: return STATE_CMD_READOOB; case NAND_CMD_ERASE1: return STATE_CMD_ERASE1; case NAND_CMD_STATUS: return STATE_CMD_STATUS; case NAND_CMD_STATUS_MULTI: return STATE_CMD_STATUS_M; case NAND_CMD_SEQIN: return STATE_CMD_SEQIN; case NAND_CMD_READID: return STATE_CMD_READID; case NAND_CMD_ERASE2: return STATE_CMD_ERASE2; case NAND_CMD_RESET: return STATE_CMD_RESET; } NS_ERR("get_state_by_command: unknown command, BUG\n"); return 0;}/* * Move an address byte to the correspondent internal register. */static inline voidaccept_addr_byte(struct nandsim *ns, u_char bt){ uint byte = (uint)bt; if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) ns->regs.column |= (byte << 8 * ns->regs.count); else { ns->regs.row |= (byte << 8 * (ns->regs.count - ns->geom.pgaddrbytes + ns->geom.secaddrbytes)); } return;} /* * Switch to STATE_READY state. */static inline void switch_to_ready_state(struct nandsim *ns, u_char status){ NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); ns->state = STATE_READY; ns->nxstate = STATE_UNKNOWN; ns->op = NULL; ns->npstates = 0; ns->stateidx = 0; ns->regs.num = 0; ns->regs.count = 0; ns->regs.off = 0; ns->regs.row = 0; ns->regs.column = 0; ns->regs.status = status;}/* * If the operation isn't known yet, try to find it in the global array * of supported operations. * * Operation can be unknown because of the following. * 1. New command was accepted and this is the firs call to find the * correspondent states chain. In this case ns->npstates = 0; * 2. There is several operations which begin with the same command(s) * (for example program from the second half and read from the * second half operations both begin with the READ1 command). In this * case the ns->pstates[] array contains previous states. * * Thus, the function tries to find operation containing the following * states (if the 'flag' parameter is 0): * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state * * If (one and only one) matching operation is found, it is accepted ( * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is * zeroed). * * If there are several maches, the current state is pushed to the * ns->pstates. * * The operation can be unknown only while commands are input to the chip. * As soon as address command is accepted, the operation must be known. * In such situation the function is called with 'flag' != 0, and the * operation is searched using the following pattern: * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> * * It is supposed that this pattern must either match one operation on * none. There can't be ambiguity in that case. * * If no matches found, the functions does the following: * 1. if there are saved states present, try to ignore them and search * again only using the last command. If nothing was found, switch * to the STATE_READY state. * 2. if there are no saved states, switch to the STATE_READY state. * * RETURNS: -2 - no matched operations found. * -1 - several matches. * 0 - operation is found. */static intfind_operation(struct nandsim *ns, uint32_t flag){ int opsfound = 0; int i, j, idx = 0; for (i = 0; i < NS_OPER_NUM; i++) { int found = 1; if (!(ns->options & ops[i].reqopts)) /* Ignore operations we can't perform */ continue; if (flag) { if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) continue; } else { if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates])) continue; } for (j = 0; j < ns->npstates; j++) if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) && (ns->options & ops[idx].reqopts)) { found = 0; break; } if (found) { idx = i; opsfound += 1; } } if (opsfound == 1) { /* Exact match */ ns->op = &ops[idx].states[0]; if (flag) { /* * In this case the find_operation function was * called when address has just began input. But it isn't * yet fully input and the current state must * not be one of STATE_ADDR_*, but the STATE_ADDR_* * state must be the next state (ns->nxstate). */ ns->stateidx = ns->npstates - 1; } else { ns->stateidx = ns->npstates; } ns->npstates = 0; ns->state = ns->op[ns->stateidx]; ns->nxstate = ns->op[ns->stateidx + 1]; NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n", idx, get_state_name(ns->state), get_state_name(ns->nxstate)); return 0; } if (opsfound == 0) { /* Nothing was found. Try to ignore previous commands (if any) and search again */ if (ns->npstates != 0) { NS_DBG("find_operation: no operation found, try again with state %s\n", get_state_name(ns->state)); ns->npstates = 0; return find_operation(ns, 0); } NS_DBG("find_operation: no operations found\n"); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return -2; } if (flag) { /* This shouldn't happen */ NS_DBG("find_operation: BUG, operation must be known if address is input\n"); return -2; } NS_DBG("find_operation: there is still ambiguity\n"); ns->pstates[ns->npstates++] = ns->state; return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -