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

📄 diskonchip.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	case NAND_ECC_READ:		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);		break;	case NAND_ECC_WRITE:		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);		break;	}}/* This code is only called on write */static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	void __iomem *docptr = doc->virtadr;	int i;	int emptymatch = 1;	/* flush the pipeline */	if (DoC_is_2000(doc)) {		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);		WriteDOC(0, docptr, 2k_CDSN_IO);		WriteDOC(0, docptr, 2k_CDSN_IO);		WriteDOC(0, docptr, 2k_CDSN_IO);		WriteDOC(doc->CDSNControl, docptr, CDSNControl);	} else if (DoC_is_MillenniumPlus(doc)) {		WriteDOC(0, docptr, Mplus_NOP);		WriteDOC(0, docptr, Mplus_NOP);		WriteDOC(0, docptr, Mplus_NOP);	} else {		WriteDOC(0, docptr, NOP);		WriteDOC(0, docptr, NOP);		WriteDOC(0, docptr, NOP);	}	for (i = 0; i < 6; i++) {		if (DoC_is_MillenniumPlus(doc))			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);		else			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);		if (ecc_code[i] != empty_write_ecc[i])			emptymatch = 0;	}	if (DoC_is_MillenniumPlus(doc))		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);	else		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);#if 0	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */	if (emptymatch) {		/* Note: this somewhat expensive test should not be triggered		   often.  It could be optimized away by examining the data in		   the writebuf routine, and remembering the result. */		for (i = 0; i < 512; i++) {			if (dat[i] == 0xff)				continue;			emptymatch = 0;			break;		}	}	/* If emptymatch still =1, we do have an all-0xff data buffer.	   Return all-0xff ecc value instead of the computed one, so	   it'll look just like a freshly-erased page. */	if (emptymatch)		memset(ecc_code, 0xff, 6);#endif	return 0;}static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,				u_char *read_ecc, u_char *isnull){	int i, ret = 0;	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	void __iomem *docptr = doc->virtadr;	uint8_t calc_ecc[6];	volatile u_char dummy;	int emptymatch = 1;	/* flush the pipeline */	if (DoC_is_2000(doc)) {		dummy = ReadDOC(docptr, 2k_ECCStatus);		dummy = ReadDOC(docptr, 2k_ECCStatus);		dummy = ReadDOC(docptr, 2k_ECCStatus);	} else if (DoC_is_MillenniumPlus(doc)) {		dummy = ReadDOC(docptr, Mplus_ECCConf);		dummy = ReadDOC(docptr, Mplus_ECCConf);		dummy = ReadDOC(docptr, Mplus_ECCConf);	} else {		dummy = ReadDOC(docptr, ECCConf);		dummy = ReadDOC(docptr, ECCConf);		dummy = ReadDOC(docptr, ECCConf);	}	/* Error occured ? */	if (dummy & 0x80) {		for (i = 0; i < 6; i++) {			if (DoC_is_MillenniumPlus(doc))				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);			else				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);			if (calc_ecc[i] != empty_read_syndrome[i])				emptymatch = 0;		}		/* If emptymatch=1, the read syndrome is consistent with an		   all-0xff data and stored ecc block.  Check the stored ecc. */		if (emptymatch) {			for (i = 0; i < 6; i++) {				if (read_ecc[i] == 0xff)					continue;				emptymatch = 0;				break;			}		}		/* If emptymatch still =1, check the data block. */		if (emptymatch) {			/* Note: this somewhat expensive test should not be triggered			   often.  It could be optimized away by examining the data in			   the readbuf routine, and remembering the result. */			for (i = 0; i < 512; i++) {				if (dat[i] == 0xff)					continue;				emptymatch = 0;				break;			}		}		/* If emptymatch still =1, this is almost certainly a freshly-		   erased block, in which case the ECC will not come out right.		   We'll suppress the error and tell the caller everything's		   OK.  Because it is. */		if (!emptymatch)			ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);		if (ret > 0)			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);	}	if (DoC_is_MillenniumPlus(doc))		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);	else		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);	if (no_ecc_failures && (ret == -EBADMSG)) {		printk(KERN_ERR "suppressing ECC failure\n");		ret = 0;	}	return ret;}//u_char mydatabuf[528];/* The strange out-of-order .oobfree list below is a (possibly unneeded) * attempt to retain compatibility.  It used to read: * 	.oobfree = { {8, 8} } * Since that leaves two bytes unusable, it was changed.  But the following * scheme might affect existing jffs2 installs by moving the cleanmarker: * 	.oobfree = { {6, 10} } * jffs2 seems to handle the above gracefully, but the current scheme seems * safer.  The only problem with it is that any code that parses oobfree must * be able to handle out-of-order segments. */static struct nand_ecclayout doc200x_oobinfo = {	.eccbytes = 6,	.eccpos = {0, 1, 2, 3, 4, 5},	.oobfree = {{8, 8}, {6, 2}}};/* Find the (I)NFTL Media Header, and optionally also the mirror media header.   On sucessful return, buf will contain a copy of the media header for   further processing.  id is the string to scan for, and will presumably be   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media   header.  The page #s of the found media headers are placed in mh0_page and   mh1_page in the DOC private structure. */static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	unsigned offs;	int ret;	size_t retlen;	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {		ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);		if (retlen != mtd->writesize)			continue;		if (ret) {			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);		}		if (memcmp(buf, id, 6))			continue;		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);		if (doc->mh0_page == -1) {			doc->mh0_page = offs >> this->page_shift;			if (!findmirror)				return 1;			continue;		}		doc->mh1_page = offs >> this->page_shift;		return 2;	}	if (doc->mh0_page == -1) {		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);		return 0;	}	/* Only one mediaheader was found.  We want buf to contain a	   mediaheader on return, so we'll have to re-read the one we found. */	offs = doc->mh0_page << this->page_shift;	ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);	if (retlen != mtd->writesize) {		/* Insanity.  Give up. */		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");		return 0;	}	return 1;}static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	int ret = 0;	u_char *buf;	struct NFTLMediaHeader *mh;	const unsigned psize = 1 << this->page_shift;	int numparts = 0;	unsigned blocks, maxblocks;	int offs, numheaders;	buf = kmalloc(mtd->writesize, GFP_KERNEL);	if (!buf) {		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");		return 0;	}	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))		goto out;	mh = (struct NFTLMediaHeader *)buf;	le16_to_cpus(&mh->NumEraseUnits);	le16_to_cpus(&mh->FirstPhysicalEUN);	le32_to_cpus(&mh->FormattedSize);	printk(KERN_INFO "    DataOrgID        = %s\n"			 "    NumEraseUnits    = %d\n"			 "    FirstPhysicalEUN = %d\n"			 "    FormattedSize    = %d\n"			 "    UnitSizeFactor   = %d\n",		mh->DataOrgID, mh->NumEraseUnits,		mh->FirstPhysicalEUN, mh->FormattedSize,		mh->UnitSizeFactor);	blocks = mtd->size >> this->phys_erase_shift;	maxblocks = min(32768U, mtd->erasesize - psize);	if (mh->UnitSizeFactor == 0x00) {		/* Auto-determine UnitSizeFactor.  The constraints are:		   - There can be at most 32768 virtual blocks.		   - There can be at most (virtual block size - page size)		   virtual blocks (because MediaHeader+BBT must fit in 1).		 */		mh->UnitSizeFactor = 0xff;		while (blocks > maxblocks) {			blocks >>= 1;			maxblocks = min(32768U, (maxblocks << 1) + psize);			mh->UnitSizeFactor--;		}		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);	}	/* NOTE: The lines below modify internal variables of the NAND and MTD	   layers; variables with have already been configured by nand_scan.	   Unfortunately, we didn't know before this point what these values	   should be.  Thus, this code is somewhat dependant on the exact	   implementation of the NAND layer.  */	if (mh->UnitSizeFactor != 0xff) {		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);		blocks = mtd->size >> this->bbt_erase_shift;		maxblocks = min(32768U, mtd->erasesize - psize);	}	if (blocks > maxblocks) {		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);		goto out;	}	/* Skip past the media headers. */	offs = max(doc->mh0_page, doc->mh1_page);	offs <<= this->page_shift;	offs += mtd->erasesize;	if (show_firmware_partition == 1) {		parts[0].name = " DiskOnChip Firmware / Media Header partition";		parts[0].offset = 0;		parts[0].size = offs;		numparts = 1;	}	parts[numparts].name = " DiskOnChip BDTL partition";	parts[numparts].offset = offs;	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;	offs += parts[numparts].size;	numparts++;	if (offs < mtd->size) {		parts[numparts].name = " DiskOnChip Remainder partition";		parts[numparts].offset = offs;		parts[numparts].size = mtd->size - offs;		numparts++;	}	ret = numparts; out:	kfree(buf);	return ret;}/* This is a stripped-down copy of the code in inftlmount.c */static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts){	struct nand_chip *this = mtd->priv;	struct doc_priv *doc = this->priv;	int ret = 0;	u_char *buf;	struct INFTLMediaHeader *mh;	struct INFTLPartition *ip;	int numparts = 0;	int blocks;	int vshift, lastvunit = 0;	int i;	int end = mtd->size;	if (inftl_bbt_write)		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);	buf = kmalloc(mtd->writesize, GFP_KERNEL);	if (!buf) {		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");		return 0;	}	if (!find_media_headers(mtd, buf, "BNAND", 0))		goto out;	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);	mh = (struct INFTLMediaHeader *)buf;	le32_to_cpus(&mh->NoOfBootImageBlocks);	le32_to_cpus(&mh->NoOfBinaryPartitions);	le32_to_cpus(&mh->NoOfBDTLPartitions);	le32_to_cpus(&mh->BlockMultiplierBits);	le32_to_cpus(&mh->FormatFlags);	le32_to_cpus(&mh->PercentUsed);	printk(KERN_INFO "    bootRecordID          = %s\n"			 "    NoOfBootImageBlocks   = %d\n"			 "    NoOfBinaryPartitions  = %d\n"			 "    NoOfBDTLPartitions    = %d\n"			 "    BlockMultiplerBits    = %d\n"			 "    FormatFlgs            = %d\n"			 "    OsakVersion           = %d.%d.%d.%d\n"			 "    PercentUsed           = %d\n",		mh->bootRecordID, mh->NoOfBootImageBlocks,		mh->NoOfBinaryPartitions,		mh->NoOfBDTLPartitions,		mh->BlockMultiplierBits, mh->FormatFlags,		((unsigned char *) &mh->OsakVersion)[0] & 0xf,		((unsigned char *) &mh->OsakVersion)[1] & 0xf,		((unsigned char *) &mh->OsakVersion)[2] & 0xf,		((unsigned char *) &mh->OsakVersion)[3] & 0xf,		mh->PercentUsed);	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;	blocks = mtd->size >> vshift;	if (blocks > 32768) {		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);		goto out;	}	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);	if (inftl_bbt_write && (blocks > mtd->erasesize)) {		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");		goto out;	}	/* Scan the partitions */	for (i = 0; (i < 4); i++) {		ip = &(mh->Partitions[i]);		le32_to_cpus(&ip->virtualUnits);		le32_to_cpus(&ip->firstUnit);		le32_to_cpus(&ip->lastUnit);		le32_to_cpus(&ip->flags);		le32_to_cpus(&ip->spareUnits);		le32_to_cpus(&ip->Reserved0);		printk(KERN_INFO	"    PARTITION[%d] ->\n"			"        virtualUnits    = %d\n"			"        firstUnit       = %d\n"			"        lastUnit        = %d\n"			"        flags           = 0x%x\n"			"        spareUnits      = %d\n",			i, ip->virtualUnits, ip->firstUnit,			ip->lastUnit, ip->flags,			ip->spareUnits);		if ((show_firmware_partition == 1) &&		    (i == 0) && (ip->firstUnit > 0)) {			parts[0].name = " DiskOnChip IPL / Media Header partition";			parts[0].offset = 0;			parts[0].size = mtd->erasesize * ip->firstUnit;			numparts = 1;		}		if (ip->flags & INFTL_BINARY)			parts[numparts].name = " DiskOnChip BDK partition";		else			parts[numparts].name = " DiskOnChip BDTL partition";		parts[numparts].offset = ip->firstUnit << vshift;		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;		numparts++;		if (ip->lastUnit > lastvunit)			lastvunit = ip->lastUnit;		if (ip->flags & INFTL_LAST)			break;	}	lastvunit++;	if ((lastvunit << vshift) < end) {		parts[numparts].name = " DiskOnChip Remainder partition";		parts[numparts].offset = lastvunit << vshift;		parts[numparts].size = end - parts[numparts].offset;		numparts++;	}	ret = numparts; out:	kfree(buf);	return ret;}static int __init nftl_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[2];

⌨️ 快捷键说明

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