⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nandsim.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
		/*		 * 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 + -