int onenand_scan()

in nand/onenand/onenand_base.c [3813:3979]


int onenand_scan(struct mtd_info *mtd, int maxchips)
{
	int i, ret;
	struct onenand_chip *this = mtd->priv;

	if (!this->read_word)
		this->read_word = onenand_readw;
	if (!this->write_word)
		this->write_word = onenand_writew;

	if (!this->command)
		this->command = onenand_command;
	if (!this->wait)
		onenand_setup_wait(mtd);
	if (!this->bbt_wait)
		this->bbt_wait = onenand_bbt_wait;
	if (!this->unlock_all)
		this->unlock_all = onenand_unlock_all;

	if (!this->chip_probe)
		this->chip_probe = onenand_chip_probe;

	if (!this->read_bufferram)
		this->read_bufferram = onenand_read_bufferram;
	if (!this->write_bufferram)
		this->write_bufferram = onenand_write_bufferram;

	if (!this->block_markbad)
		this->block_markbad = onenand_default_block_markbad;
	if (!this->scan_bbt)
		this->scan_bbt = onenand_default_bbt;

	if (onenand_probe(mtd))
		return -ENXIO;

	/* Set Sync. Burst Read after probing */
	if (this->mmcontrol) {
		printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
		this->read_bufferram = onenand_sync_read_bufferram;
	}

	/* Allocate buffers, if necessary */
	if (!this->page_buf) {
		this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
		if (!this->page_buf)
			return -ENOMEM;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
		this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
		if (!this->verify_buf) {
			kfree(this->page_buf);
			return -ENOMEM;
		}
#endif
		this->options |= ONENAND_PAGEBUF_ALLOC;
	}
	if (!this->oob_buf) {
		this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
		if (!this->oob_buf) {
			if (this->options & ONENAND_PAGEBUF_ALLOC) {
				this->options &= ~ONENAND_PAGEBUF_ALLOC;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
				kfree(this->verify_buf);
#endif
				kfree(this->page_buf);
			}
			return -ENOMEM;
		}
		this->options |= ONENAND_OOBBUF_ALLOC;
	}

	this->state = FL_READY;
	init_waitqueue_head(&this->wq);
	spin_lock_init(&this->chip_lock);

	/*
	 * Allow subpage writes up to oobsize.
	 */
	switch (mtd->oobsize) {
	case 128:
		if (FLEXONENAND(this)) {
			mtd_set_ooblayout(mtd, &flexonenand_ooblayout_ops);
			mtd->subpage_sft = 0;
		} else {
			mtd_set_ooblayout(mtd, &onenand_oob_128_ooblayout_ops);
			mtd->subpage_sft = 2;
		}
		if (ONENAND_IS_NOP_1(this))
			mtd->subpage_sft = 0;
		break;
	case 64:
		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
		mtd->subpage_sft = 2;
		break;

	case 32:
		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
		mtd->subpage_sft = 1;
		break;

	default:
		printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
			__func__, mtd->oobsize);
		mtd->subpage_sft = 0;
		/* To prevent kernel oops */
		mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
		break;
	}

	this->subpagesize = mtd->writesize >> mtd->subpage_sft;

	/*
	 * The number of bytes available for a client to place data into
	 * the out of band area
	 */
	ret = mtd_ooblayout_count_freebytes(mtd);
	if (ret < 0)
		ret = 0;

	mtd->oobavail = ret;

	mtd->ecc_strength = 1;

	/* Fill in remaining MTD driver data */
	mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
	mtd->flags = MTD_CAP_NANDFLASH;
	mtd->_erase = onenand_erase;
	mtd->_point = NULL;
	mtd->_unpoint = NULL;
	mtd->_read_oob = onenand_read_oob;
	mtd->_write_oob = onenand_write_oob;
	mtd->_panic_write = onenand_panic_write;
#ifdef CONFIG_MTD_ONENAND_OTP
	mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
	mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
	mtd->_get_user_prot_info = onenand_get_user_prot_info;
	mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
	mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
	mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
#endif
	mtd->_sync = onenand_sync;
	mtd->_lock = onenand_lock;
	mtd->_unlock = onenand_unlock;
	mtd->_suspend = onenand_suspend;
	mtd->_resume = onenand_resume;
	mtd->_block_isbad = onenand_block_isbad;
	mtd->_block_markbad = onenand_block_markbad;
	mtd->owner = THIS_MODULE;
	mtd->writebufsize = mtd->writesize;

	/* Unlock whole block */
	if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
		this->unlock_all(mtd);

	/* Set the bad block marker position */
	this->badblockpos = ONENAND_BADBLOCK_POS;

	ret = this->scan_bbt(mtd);
	if ((!FLEXONENAND(this)) || ret)
		return ret;

	/* Change Flex-OneNAND boundaries if required */
	for (i = 0; i < MAX_DIES; i++)
		flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
						 flex_bdry[(2 * i) + 1]);

	return 0;
}