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

📄 inftlmount.c

📁 linux下的MTD设备驱动源代码,配合jffs2 yaffss2文件系统.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * inftlmount.c -- INFTL mount code with extensive checks. * * Author: Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) * * Based heavily on the nftlmount.c code which is: * Author: Fabrice Bellard (fabrice.bellard@netgem.com)  * Copyright (C) 2000 Netgem S.A. * * $Id: inftlmount.c,v 1.12 2003/06/26 07:31:36 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/kernel.h>#include <linux/module.h>#include <asm/errno.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/miscdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nftl.h>#include <linux/mtd/inftl.h>#include <linux/mtd/compatmac.h>char inftlmountrev[]="$Revision: 1.12 $";/* * find_boot_record: Find the INFTL Media Header and its Spare copy which *	contains the various device information of the INFTL partition and *	Bad Unit Table. Update the PUtable[] table according to the Bad *	Unit Table. PUtable[] is used for management of Erase Unit in *	other routines in inftlcore.c and inftlmount.c. */static int find_boot_record(struct INFTLrecord *inftl){	struct inftl_unittail h1;	//struct inftl_oob oob;	unsigned int i, block, boot_record_count = 0;	u8 buf[SECTORSIZE];	struct INFTLMediaHeader *mh = &inftl->MediaHdr;	struct INFTLPartition *ip;	int retlen;	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n",		(int)inftl);        /*	 * Assume logical EraseSize == physical erasesize for starting the	 * scan. We'll sort it out later if we find a MediaHeader which says	 * otherwise.	 */	inftl->EraseSize = inftl->mbd.mtd->erasesize;        inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;	inftl->MediaUnit = BLOCK_NIL;	inftl->SpareMediaUnit = BLOCK_NIL;	/* Search for a valid boot record */	for (block = 0; block < inftl->nb_blocks; block++) {		int ret;		/*		 * Check for BNAND header first. Then whinge if it's found		 * but later checks fail.		 */		if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,		    SECTORSIZE, &retlen, buf))) {			static int warncount = 5;			if (warncount) {				printk(KERN_WARNING "INFTL: block read at 0x%x "					"of mtd%d failed: %d\n",					block * inftl->EraseSize,					inftl->mbd.mtd->index, ret);				if (!--warncount)					printk(KERN_WARNING "INFTL: further "						"failures for this block will "						"not be printed\n");			}			continue;		}		if (retlen < 6 || memcmp(buf, "BNAND", 6)) {			/* BNAND\0 not found. Continue */			continue;		}		/* To be safer with BIOS, also use erase mark as discriminant */		if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +		    SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {			printk(KERN_WARNING "INFTL: ANAND header found at "				"0x%x in mtd%d, but OOB data read failed "				"(err %d)\n", block * inftl->EraseSize,				inftl->mbd.mtd->index, ret);			continue;		}		if (boot_record_count) {			/*			 * We've already processed one. So we just check if			 * this one is the same as the first one we found.			 */			if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {				printk(KERN_WARNING "INFTL: Media Headers at "					"0x%x and 0x%x disagree.\n",					inftl->MediaUnit * inftl->EraseSize,					block * inftl->EraseSize);				return -1;			}			if (boot_record_count == 1)				inftl->SpareMediaUnit = block;			/*			 * Mark this boot record (INFTL MediaHeader) block as			 * reserved.			 */			inftl->PUtable[block] = BLOCK_RESERVED;			boot_record_count++;			continue;		}		/*		 * This is the first we've seen.		 * Copy the media header structure into place.		 */		memcpy(mh, buf, sizeof(struct INFTLMediaHeader));		mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);		mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);		mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);		mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);		mh->FormatFlags = le32_to_cpu(mh->FormatFlags);		mh->PercentUsed = le32_to_cpu(mh->PercentUsed);#ifdef CONFIG_MTD_DEBUG_VERBOSE		if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {			printk("INFTL: Media Header ->\n"				"    bootRecordID          = %s\n"				"    NoOfBootImageBlocks   = %d\n"				"    NoOfBinaryPartitions  = %d\n"				"    NoOfBDTLPartitions    = %d\n"				"    BlockMultiplerBits    = %d\n"				"    FormatFlgs            = %d\n"				"    OsakVersion           = 0x%x\n"				"    PercentUsed           = %d\n",				mh->bootRecordID, mh->NoOfBootImageBlocks,				mh->NoOfBinaryPartitions,				mh->NoOfBDTLPartitions,				mh->BlockMultiplierBits, mh->FormatFlags,				mh->OsakVersion, mh->PercentUsed);		}#endif		if (mh->NoOfBDTLPartitions == 0) {			printk(KERN_WARNING "INFTL: Media Header sanity check "				"failed: NoOfBDTLPartitions (%d) == 0, "				"must be at least 1\n", mh->NoOfBDTLPartitions);			return -1;		}		if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {			printk(KERN_WARNING "INFTL: Media Header sanity check "				"failed: Total Partitions (%d) > 4, "				"BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +				mh->NoOfBinaryPartitions,				mh->NoOfBDTLPartitions,				mh->NoOfBinaryPartitions);			return -1;		}		if (mh->BlockMultiplierBits > 1) {			printk(KERN_WARNING "INFTL: sorry, we don't support "				"UnitSizeFactor 0x%02x\n",				mh->BlockMultiplierBits);			return -1;		} else if (mh->BlockMultiplierBits == 1) {			printk(KERN_WARNING "INFTL: support for INFTL with "				"UnitSizeFactor 0x%02x is experimental\n",				mh->BlockMultiplierBits);			inftl->EraseSize = inftl->mbd.mtd->erasesize <<				(0xff - mh->BlockMultiplierBits);			inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;		}		/* Scan the partitions */		for (i = 0; (i < 4); i++) {			ip = &mh->Partitions[i];			ip->virtualUnits = le32_to_cpu(ip->virtualUnits);			ip->firstUnit = le32_to_cpu(ip->firstUnit);			ip->lastUnit = le32_to_cpu(ip->lastUnit);			ip->flags = le32_to_cpu(ip->flags);			ip->spareUnits = le32_to_cpu(ip->spareUnits);			ip->Reserved0 = le32_to_cpu(ip->Reserved0);#ifdef CONFIG_MTD_DEBUG_VERBOSE			if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {				printk("    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);			}#endif			if (ip->Reserved0 != ip->firstUnit) {				struct erase_info *instr = &inftl->instr;				/*				 * 	Most likely this is using the				 * 	undocumented qiuck mount feature.				 * 	We don't support that, we will need				 * 	to erase the hidden block for full				 * 	compatibility.				 */				instr->addr = ip->Reserved0 * inftl->EraseSize;				instr->len = inftl->EraseSize;				MTD_ERASE(inftl->mbd.mtd, instr);			}			if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {				printk(KERN_WARNING "INFTL: Media Header "					"Partition %d sanity check failed\n"					"    firstUnit %d : lastUnit %d  >  "					"virtualUnits %d\n", i, ip->lastUnit,					ip->firstUnit, ip->Reserved0);				return -1;			}			if (ip->Reserved1 != 0) {				printk(KERN_WARNING "INFTL: Media Header "					"Partition %d sanity check failed: "					"Reserved1 %d != 0\n",					i, ip->Reserved1);				return -1;			}			if (ip->flags & INFTL_BDTL)				break;		}		if (i >= 4) {			printk(KERN_WARNING "INFTL: Media Header Partition "				"sanity check failed:\n       No partition "				"marked as Disk Partition\n");			return -1;		}		inftl->nb_boot_blocks = ip->firstUnit;		inftl->numvunits = ip->virtualUnits;		if (inftl->numvunits > (inftl->nb_blocks -		    inftl->nb_boot_blocks - 2)) {			printk(KERN_WARNING "INFTL: Media Header sanity check "				"failed:\n        numvunits (%d) > nb_blocks "				"(%d) - nb_boot_blocks(%d) - 2\n",				inftl->numvunits, inftl->nb_blocks,				inftl->nb_boot_blocks);			return -1;		}				inftl->mbd.size  = inftl->numvunits *			(inftl->EraseSize / SECTORSIZE);		/*		 * Block count is set to last used EUN (we won't need to keep		 * any meta-data past that point).		 */		inftl->firstEUN = ip->firstUnit;		inftl->lastEUN = ip->lastUnit;		inftl->nb_blocks = ip->lastUnit + 1;		/* Memory alloc */		inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);		if (!inftl->PUtable) {			printk(KERN_WARNING "INFTL: allocation of PUtable "				"failed (%d bytes)\n",				inftl->nb_blocks * sizeof(u16));			return -ENOMEM;		}		inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);		if (!inftl->VUtable) {			kfree(inftl->PUtable);			printk(KERN_WARNING "INFTL: allocation of VUtable "				"failed (%d bytes)\n",				inftl->nb_blocks * sizeof(u16));			return -ENOMEM;		}				/* Mark the blocks before INFTL MediaHeader as reserved */		for (i = 0; i < inftl->nb_boot_blocks; i++)			inftl->PUtable[i] = BLOCK_RESERVED;		/* Mark all remaining blocks as potentially containing data */		for (; i < inftl->nb_blocks; i++)			inftl->PUtable[i] = BLOCK_NOTEXPLORED;		/* Mark this boot record (NFTL MediaHeader) block as reserved */		inftl->PUtable[block] = BLOCK_RESERVED;#if 0		/* Read Bad Erase Unit Table and modify PUtable[] accordingly */		for (i = 0; i < inftl->nb_blocks; i++) {			if ((i & (SECTORSIZE - 1)) == 0) {				/* read one sector for every SECTORSIZE of blocks */				if ((ret = MTD_READECC(inftl->mbd.mtd,				    block * inftl->EraseSize + i + SECTORSIZE,				    SECTORSIZE, &retlen, buf,				    (char *)&oob, NULL)) < 0) {					printk(KERN_WARNING "INFTL: read of "						"bad sector table failed "						"(err %d)\n", ret);					kfree(inftl->VUtable);					kfree(inftl->PUtable);					return -1;				}			}			/* Mark the Bad Erase Unit as RESERVED in PUtable */			if (buf[i & (SECTORSIZE - 1)] != 0xff)				inftl->PUtable[i] = BLOCK_RESERVED;		}#endif		inftl->MediaUnit = block;		boot_record_count++;	}			return boot_record_count ? 0 : -1;}static int memcmpb(void *a, int c, int n){	int i;	for (i = 0; i < n; i++) {		if (c != ((unsigned char *)a)[i])			return 1;	}	return 0;}/* * check_free_sector: check if a free sector is actually FREE, *	i.e. All 0xff in data and oob area. */static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,	int len, int check_oob){	int i, retlen;	u8 buf[SECTORSIZE];	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"		"address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,		address, len, check_oob);	for (i = 0; i < len; i += SECTORSIZE) {		/*		 * We want to read the sector without ECC check here since a		 * free sector does not have ECC syndrome on it yet.		 */		if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)			return -1;		if (memcmpb(buf, 0xff, SECTORSIZE) != 0)			return -1;		if (check_oob) {			if (MTD_READOOB(inftl->mbd.mtd, address,			    inftl->mbd.mtd->oobsize, &retlen, buf) < 0)				return -1;			if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)				return -1;		}		address += SECTORSIZE;	}	return 0;}/* * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase *		 Unit and Update INFTL metadata. Each erase operation is *		 checked with check_free_sectors. * * Return: 0 when succeed, -1 on error. * * ToDo: 1. Is it neceressary to check_free_sector after erasing ??  *       2. UnitSizeFactor != 0xFF */int INFTL_formatblock(struct INFTLrecord *inftl, int block){	int retlen;

⌨️ 快捷键说明

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