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

📄 diskonchip.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	memset((char *)parts, 0, sizeof(parts));	/* On NFTL, we have to find the media headers before we can read the	   BBTs, since they're stored in the media header eraseblocks. */	numparts = nftl_partscan(mtd, parts);	if (!numparts)		return -EIO;	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |				NAND_BBT_VERSION;	this->bbt_td->veroffs = 7;	this->bbt_td->pages[0] = doc->mh0_page + 1;	if (doc->mh1_page != -1) {		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |					NAND_BBT_VERSION;		this->bbt_md->veroffs = 7;		this->bbt_md->pages[0] = doc->mh1_page + 1;	} else {		this->bbt_md = NULL;	}	/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.	   At least as nand_bbt.c is currently written. */	if ((ret = nand_scan_bbt(mtd, NULL)))		return ret;	add_mtd_device(mtd);#ifdef CONFIG_MTD_PARTITIONS	if (!no_autopart)		add_mtd_partitions(mtd, parts, numparts);#endif	return 0;}static int __init inftl_scan_bbt(struct mtd_info *mtd){	int ret, numparts;	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	struct mtd_partition parts[5];	if (this->numchips > doc->chips_per_floor) {		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");		return -EIO;	}	if (DoC_is_MillenniumPlus(doc)) {		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;		if (inftl_bbt_write)			this->bbt_td->options |= NAND_BBT_WRITE;		this->bbt_td->pages[0] = 2;		this->bbt_md = NULL;	} else {		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;		if (inftl_bbt_write)			this->bbt_td->options |= NAND_BBT_WRITE;		this->bbt_td->offs = 8;		this->bbt_td->len = 8;		this->bbt_td->veroffs = 7;		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;		this->bbt_td->reserved_block_code = 0x01;		this->bbt_td->pattern = "MSYS_BBT";		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;		if (inftl_bbt_write)			this->bbt_md->options |= NAND_BBT_WRITE;		this->bbt_md->offs = 8;		this->bbt_md->len = 8;		this->bbt_md->veroffs = 7;		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;		this->bbt_md->reserved_block_code = 0x01;		this->bbt_md->pattern = "TBB_SYSM";	}	/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.	   At least as nand_bbt.c is currently written. */	if ((ret = nand_scan_bbt(mtd, NULL)))		return ret;	memset((char *)parts, 0, sizeof(parts));	numparts = inftl_partscan(mtd, parts);	/* At least for now, require the INFTL Media Header.  We could probably	   do without it for non-INFTL use, since all it gives us is	   autopartitioning, but I want to give it more thought. */	if (!numparts)		return -EIO;	add_mtd_device(mtd);#ifdef CONFIG_MTD_PARTITIONS	if (!no_autopart)		add_mtd_partitions(mtd, parts, numparts);#endif	return 0;}static inline int __init doc2000_init(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	this->read_byte = doc2000_read_byte;	this->write_buf = doc2000_writebuf;	this->read_buf = doc2000_readbuf;	this->verify_buf = doc2000_verifybuf;	this->scan_bbt = nftl_scan_bbt;	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;	doc2000_count_chips(mtd);	mtd->name = "DiskOnChip 2000 (NFTL Model)";	return (4 * doc->chips_per_floor);}static inline int __init doc2001_init(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	this->read_byte = doc2001_read_byte;	this->write_buf = doc2001_writebuf;	this->read_buf = doc2001_readbuf;	this->verify_buf = doc2001_verifybuf;	ReadDOC(doc->virtadr, ChipID);	ReadDOC(doc->virtadr, ChipID);	ReadDOC(doc->virtadr, ChipID);	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {		/* It's not a Millennium; it's one of the newer		   DiskOnChip 2000 units with a similar ASIC.		   Treat it like a Millennium, except that it		   can have multiple chips. */		doc2000_count_chips(mtd);		mtd->name = "DiskOnChip 2000 (INFTL Model)";		this->scan_bbt = inftl_scan_bbt;		return (4 * doc->chips_per_floor);	} else {		/* Bog-standard Millennium */		doc->chips_per_floor = 1;		mtd->name = "DiskOnChip Millennium";		this->scan_bbt = nftl_scan_bbt;		return 1;	}}static inline int __init doc2001plus_init(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	this->read_byte = doc2001plus_read_byte;	this->write_buf = doc2001plus_writebuf;	this->read_buf = doc2001plus_readbuf;	this->verify_buf = doc2001plus_verifybuf;	this->scan_bbt = inftl_scan_bbt;	this->cmd_ctrl = NULL;	this->select_chip = doc2001plus_select_chip;	this->cmdfunc = doc2001plus_command;	this->ecc.hwctl = doc2001plus_enable_hwecc;	doc->chips_per_floor = 1;	mtd->name = "DiskOnChip Millennium Plus";	return 1;}static int __init doc_probe(unsigned long physadr){	unsigned char ChipID;	struct mtd_info *mtd;	struct nand_chip *nand;	struct doc_priv *doc;	void __iomem *virtadr;	unsigned char save_control;	unsigned char tmp, tmpb, tmpc;	int reg, len, numchips;	int ret = 0;	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);	if (!virtadr) {		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);		return -EIO;	}	/* It's not possible to cleanly detect the DiskOnChip - the	 * bootup procedure will put the device into reset mode, and	 * it's not possible to talk to it without actually writing	 * to the DOCControl register. So we store the current contents	 * of the DOCControl register's location, in case we later decide	 * that it's not a DiskOnChip, and want to put it back how we	 * found it.	 */	save_control = ReadDOC(virtadr, DOCControl);	/* Reset the DiskOnChip ASIC */	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);	/* Enable the DiskOnChip ASIC */	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);	ChipID = ReadDOC(virtadr, ChipID);	switch (ChipID) {	case DOC_ChipID_Doc2k:		reg = DoC_2k_ECCStatus;		break;	case DOC_ChipID_DocMil:		reg = DoC_ECCConf;		break;	case DOC_ChipID_DocMilPlus16:	case DOC_ChipID_DocMilPlus32:	case 0:		/* Possible Millennium Plus, need to do more checks */		/* Possibly release from power down mode */		for (tmp = 0; (tmp < 4); tmp++)			ReadDOC(virtadr, Mplus_Power);		/* Reset the Millennium Plus ASIC */		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;		WriteDOC(tmp, virtadr, Mplus_DOCControl);		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);		mdelay(1);		/* Enable the Millennium Plus ASIC */		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;		WriteDOC(tmp, virtadr, Mplus_DOCControl);		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);		mdelay(1);		ChipID = ReadDOC(virtadr, ChipID);		switch (ChipID) {		case DOC_ChipID_DocMilPlus16:			reg = DoC_Mplus_Toggle;			break;		case DOC_ChipID_DocMilPlus32:			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");		default:			ret = -ENODEV;			goto notfound;		}		break;	default:		ret = -ENODEV;		goto notfound;	}	/* Check the TOGGLE bit in the ECC register */	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;	if ((tmp == tmpb) || (tmp != tmpc)) {		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);		ret = -ENODEV;		goto notfound;	}	for (mtd = doclist; mtd; mtd = doc->nextdoc) {		unsigned char oldval;		unsigned char newval;		nand = mtd->priv;		doc = nand->priv;		/* Use the alias resolution register to determine if this is		   in fact the same DOC aliased to a new address.  If writes		   to one chip's alias resolution register change the value on		   the other chip, they're the same chip. */		if (ChipID == DOC_ChipID_DocMilPlus16) {			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);			newval = ReadDOC(virtadr, Mplus_AliasResolution);		} else {			oldval = ReadDOC(doc->virtadr, AliasResolution);			newval = ReadDOC(virtadr, AliasResolution);		}		if (oldval != newval)			continue;		if (ChipID == DOC_ChipID_DocMilPlus16) {			WriteDOC(~newval, virtadr, Mplus_AliasResolution);			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it		} else {			WriteDOC(~newval, virtadr, AliasResolution);			oldval = ReadDOC(doc->virtadr, AliasResolution);			WriteDOC(newval, virtadr, AliasResolution);	// restore it		}		newval = ~newval;		if (oldval == newval) {			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);			goto notfound;		}	}	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);	len = sizeof(struct mtd_info) +	    sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));	mtd = kzalloc(len, GFP_KERNEL);	if (!mtd) {		printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);		ret = -ENOMEM;		goto fail;	}	nand			= (struct nand_chip *) (mtd + 1);	doc			= (struct doc_priv *) (nand + 1);	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);	nand->bbt_md		= nand->bbt_td + 1;	mtd->priv		= nand;	mtd->owner		= THIS_MODULE;	nand->priv		= doc;	nand->select_chip	= doc200x_select_chip;	nand->cmd_ctrl		= doc200x_hwcontrol;	nand->dev_ready		= doc200x_dev_ready;	nand->waitfunc		= doc200x_wait;	nand->block_bad		= doc200x_block_bad;	nand->ecc.hwctl		= doc200x_enable_hwecc;	nand->ecc.calculate	= doc200x_calculate_ecc;	nand->ecc.correct	= doc200x_correct_data;	nand->ecc.layout	= &doc200x_oobinfo;	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;	nand->ecc.size		= 512;	nand->ecc.bytes		= 6;	nand->options		= NAND_USE_FLASH_BBT;	doc->physadr		= physadr;	doc->virtadr		= virtadr;	doc->ChipID		= ChipID;	doc->curfloor		= -1;	doc->curchip		= -1;	doc->mh0_page		= -1;	doc->mh1_page		= -1;	doc->nextdoc		= doclist;	if (ChipID == DOC_ChipID_Doc2k)		numchips = doc2000_init(mtd);	else if (ChipID == DOC_ChipID_DocMilPlus16)		numchips = doc2001plus_init(mtd);	else		numchips = doc2001_init(mtd);	if ((ret = nand_scan(mtd, numchips))) {		/* DBB note: i believe nand_release is necessary here, as		   buffers may have been allocated in nand_base.  Check with		   Thomas. FIX ME! */		/* nand_release will call del_mtd_device, but we haven't yet		   added it.  This is handled without incident by		   del_mtd_device, as far as I can tell. */		nand_release(mtd);		kfree(mtd);		goto fail;	}	/* Success! */	doclist = mtd;	return 0; notfound:	/* Put back the contents of the DOCControl register, in case it's not	   actually a DiskOnChip.  */	WriteDOC(save_control, virtadr, DOCControl); fail:	iounmap(virtadr);	return ret;}static void release_nanddoc(void){	struct mtd_info *mtd, *nextmtd;	struct nand_chip *nand;	struct doc_priv *doc;	for (mtd = doclist; mtd; mtd = nextmtd) {		nand = mtd->priv;		doc = nand->priv;		nextmtd = doc->nextdoc;		nand_release(mtd);		iounmap(doc->virtadr);		kfree(mtd);	}}static int __init init_nanddoc(void){	int i, ret = 0;	/* We could create the decoder on demand, if memory is a concern.	 * This way we have it handy, if an error happens	 *	 * Symbolsize is 10 (bits)	 * Primitve polynomial is x^10+x^3+1	 * first consecutive root is 510	 * primitve element to generate roots = 1	 * generator polinomial degree = 4	 */	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);	if (!rs_decoder) {		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");		return -ENOMEM;	}	if (doc_config_location) {		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);		ret = doc_probe(doc_config_location);		if (ret < 0)			goto outerr;	} else {		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {			doc_probe(doc_locations[i]);		}	}	/* No banner message any more. Print a message if no DiskOnChip	   found, so the user knows we at least tried. */	if (!doclist) {		printk(KERN_INFO "No valid DiskOnChip devices found\n");		ret = -ENODEV;		goto outerr;	}	return 0; outerr:	free_rs(rs_decoder);	return ret;}static void __exit cleanup_nanddoc(void){	/* Cleanup the nand/DoC resources */	release_nanddoc();	/* Free the reed solomon resources */	if (rs_decoder) {		free_rs(rs_decoder);	}}module_init(init_nanddoc);module_exit(cleanup_nanddoc);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -