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

📄 nand_bbt.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			       chip + 1, this->numchips);			return -EINVAL;		}		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);		startblock = chip * numblocks;		numblocks += startblock;		from = startblock << (this->bbt_erase_shift - 1);	}	for (i = startblock; i < numblocks;) {		int ret;		if (bd->options & NAND_BBT_SCANALLPAGES)			ret = scan_block_full(mtd, bd, from, buf, readlen,					      scanlen, len);		else			ret = scan_block_fast(mtd, bd, from, buf, len);		if (ret < 0)			return ret;		if (ret) {			this->bbt[i >> 3] |= 0x03 << (i & 0x6);			printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",			       i >> 1, (unsigned int)from);			mtd->ecc_stats.badblocks++;		}		i += 2;		from += (1 << this->bbt_erase_shift);	}	return 0;}/** * search_bbt - [GENERIC] scan the device for a specific bad block table * @mtd:	MTD device structure * @buf:	temporary buffer * @td:		descriptor for the bad block table * * Read the bad block table by searching for a given ident pattern. * Search is preformed either from the beginning up or from the end of * the device downwards. The search starts always at the start of a * block. * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. * This is necessary to provide support for certain DOC devices. * * The bbt ident pattern resides in the oob area of the first page * in a block. */static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td){	struct nand_chip *this = mtd->priv;	int i, chips;	int bits, startblock, block, dir;	int scanlen = mtd->writesize + mtd->oobsize;	int bbtblocks;	int blocktopage = this->bbt_erase_shift - this->page_shift;	/* Search direction top -> down ? */	if (td->options & NAND_BBT_LASTBLOCK) {		startblock = (mtd->size >> this->bbt_erase_shift) - 1;		dir = -1;	} else {		startblock = 0;		dir = 1;	}	/* Do we have a bbt per chip ? */	if (td->options & NAND_BBT_PERCHIP) {		chips = this->numchips;		bbtblocks = this->chipsize >> this->bbt_erase_shift;		startblock &= bbtblocks - 1;	} else {		chips = 1;		bbtblocks = mtd->size >> this->bbt_erase_shift;	}	/* Number of bits for each erase block in the bbt */	bits = td->options & NAND_BBT_NRBITS_MSK;	for (i = 0; i < chips; i++) {		/* Reset version information */		td->version[i] = 0;		td->pages[i] = -1;		/* Scan the maximum number of blocks */		for (block = 0; block < td->maxblocks; block++) {			int actblock = startblock + dir * block;			loff_t offs = actblock << this->bbt_erase_shift;			/* Read first page */			scan_read_raw(mtd, buf, offs, mtd->writesize);			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {				td->pages[i] = actblock << blocktopage;				if (td->options & NAND_BBT_VERSION) {					td->version[i] = buf[mtd->writesize + td->veroffs];				}				break;			}		}		startblock += this->chipsize >> this->bbt_erase_shift;	}	/* Check, if we found a bbt for each requested chip */	for (i = 0; i < chips; i++) {		if (td->pages[i] == -1)			printk(KERN_WARNING "Bad block table not found for chip %d\n", i);		else			printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i],			       td->version[i]);	}	return 0;}/** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd:	MTD device structure * @buf:	temporary buffer * @td:		descriptor for the bad block table * @md:		descriptor for the bad block table mirror * * Search and read the bad block table(s)*/static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md){	/* Search the primary table */	search_bbt(mtd, buf, td);	/* Search the mirror table */	if (md)		search_bbt(mtd, buf, md);	/* Force result check */	return 1;}/** * write_bbt - [GENERIC] (Re)write the bad block table * * @mtd:	MTD device structure * @buf:	temporary buffer * @td:		descriptor for the bad block table * @md:		descriptor for the bad block table mirror * @chipsel:	selector for a specific chip, -1 for all * * (Re)write the bad block table **/static int write_bbt(struct mtd_info *mtd, uint8_t *buf,		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,		     int chipsel){	struct nand_chip *this = mtd->priv;	struct erase_info einfo;	int i, j, res, chip = 0;	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;	int nrchips, bbtoffs, pageoffs, ooboffs;	uint8_t msk[4];	uint8_t rcode = td->reserved_block_code;	size_t retlen, len = 0;	loff_t to;	struct mtd_oob_ops ops;	ops.ooblen = mtd->oobsize;	ops.ooboffs = 0;	ops.datbuf = NULL;	ops.mode = MTD_OOB_PLACE;	if (!rcode)		rcode = 0xff;	/* Write bad block table per chip rather than per device ? */	if (td->options & NAND_BBT_PERCHIP) {		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);		/* Full device write or specific chip ? */		if (chipsel == -1) {			nrchips = this->numchips;		} else {			nrchips = chipsel + 1;			chip = chipsel;		}	} else {		numblocks = (int)(mtd->size >> this->bbt_erase_shift);		nrchips = 1;	}	/* Loop through the chips */	for (; chip < nrchips; chip++) {		/* There was already a version of the table, reuse the page		 * This applies for absolute placement too, as we have the		 * page nr. in td->pages.		 */		if (td->pages[chip] != -1) {			page = td->pages[chip];			goto write;		}		/* Automatic placement of the bad block table */		/* Search direction top -> down ? */		if (td->options & NAND_BBT_LASTBLOCK) {			startblock = numblocks * (chip + 1) - 1;			dir = -1;		} else {			startblock = chip * numblocks;			dir = 1;		}		for (i = 0; i < td->maxblocks; i++) {			int block = startblock + dir * i;			/* Check, if the block is bad */			switch ((this->bbt[block >> 2] >>				 (2 * (block & 0x03))) & 0x03) {			case 0x01:			case 0x03:				continue;			}			page = block <<				(this->bbt_erase_shift - this->page_shift);			/* Check, if the block is used by the mirror table */			if (!md || md->pages[chip] != page)				goto write;		}		printk(KERN_ERR "No space left to write bad block table\n");		return -ENOSPC;	write:		/* Set up shift count and masks for the flash table */		bits = td->options & NAND_BBT_NRBITS_MSK;		msk[2] = ~rcode;		switch (bits) {		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;			msk[3] = 0x01;			break;		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;			msk[3] = 0x03;			break;		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;			msk[3] = 0x0f;			break;		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;			msk[3] = 0xff;			break;		default: return -EINVAL;		}		bbtoffs = chip * (numblocks >> 2);		to = ((loff_t) page) << this->page_shift;		/* Must we save the block contents ? */		if (td->options & NAND_BBT_SAVECONTENT) {			/* Make it block aligned */			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));			len = 1 << this->bbt_erase_shift;			res = mtd->read(mtd, to, len, &retlen, buf);			if (res < 0) {				if (retlen != len) {					printk(KERN_INFO "nand_bbt: Error "					       "reading block for writing "					       "the bad block table\n");					return res;				}				printk(KERN_WARNING "nand_bbt: ECC error "				       "while reading block for writing "				       "bad block table\n");			}			/* Read oob data */			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;			ops.oobbuf = &buf[len];			res = mtd->read_oob(mtd, to + mtd->writesize, &ops);			if (res < 0 || ops.oobretlen != ops.ooblen)				goto outerr;			/* Calc the byte offset in the buffer */			pageoffs = page - (int)(to >> this->page_shift);			offs = pageoffs << this->page_shift;			/* Preset the bbt area with 0xff */			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));			ooboffs = len + (pageoffs * mtd->oobsize);		} else {			/* Calc length */			len = (size_t) (numblocks >> sft);			/* Make it page aligned ! */			len = (len + (mtd->writesize - 1)) &				~(mtd->writesize - 1);			/* Preset the buffer with 0xff */			memset(buf, 0xff, len +			       (len >> this->page_shift)* mtd->oobsize);			offs = 0;			ooboffs = len;			/* Pattern is located in oob area of first page */			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);		}		if (td->options & NAND_BBT_VERSION)			buf[ooboffs + td->veroffs] = td->version[chip];		/* walk through the memory table */		for (i = 0; i < numblocks;) {			uint8_t dat;			dat = this->bbt[bbtoffs + (i >> 2)];			for (j = 0; j < 4; j++, i++) {				int sftcnt = (i << (3 - sft)) & sftmsk;				/* Do not store the reserved bbt blocks ! */				buf[offs + (i >> sft)] &=					~(msk[dat & 0x03] << sftcnt);				dat >>= 2;			}		}		memset(&einfo, 0, sizeof(einfo));		einfo.mtd = mtd;		einfo.addr = (unsigned long)to;		einfo.len = 1 << this->bbt_erase_shift;		res = nand_erase_nand(mtd, &einfo, 1);		if (res < 0)			goto outerr;		res = scan_write_bbt(mtd, to, len, buf, &buf[len]);		if (res < 0)			goto outerr;		printk(KERN_DEBUG "Bad block table written to 0x%08x, version "		       "0x%02X\n", (unsigned int)to, td->version[chip]);		/* Mark it as used */		td->pages[chip] = page;	}	return 0; outerr:	printk(KERN_WARNING	       "nand_bbt: Error while writing bad block table %d\n", res);	return res;}/** * nand_memory_bbt - [GENERIC] create a memory based bad block table * @mtd:	MTD device structure * @bd:		descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks*/static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd){	struct nand_chip *this = mtd->priv;	bd->options &= ~NAND_BBT_SCANEMPTY;	return create_bbt(mtd, this->buffers->databuf, bd, -1);}/** * check_create - [GENERIC] create and write bbt(s) if necessary * @mtd:	MTD device structure * @buf:	temporary buffer * @bd:		descriptor for the good/bad block search pattern * * The function checks the results of the previous call to read_bbt * and creates / updates the bbt(s) if necessary * Creation is necessary if no bbt was found for the chip/device * Update is necessary if one of the tables is missing or the * version nr. of one table is less than the other*/static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd){	int i, chips, writeops, chipsel, res;	struct nand_chip *this = mtd->priv;	struct nand_bbt_descr *td = this->bbt_td;	struct nand_bbt_descr *md = this->bbt_md;	struct nand_bbt_descr *rd, *rd2;	/* Do we have a bbt per chip ? */	if (td->options & NAND_BBT_PERCHIP)		chips = this->numchips;	else		chips = 1;	for (i = 0; i < chips; i++) {		writeops = 0;		rd = NULL;		rd2 = NULL;		/* Per chip or per device ? */		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;		/* Mirrored table avilable ? */		if (md) {			if (td->pages[i] == -1 && md->pages[i] == -1) {				writeops = 0x03;				goto create;			}			if (td->pages[i] == -1) {				rd = md;				td->version[i] = md->version[i];				writeops = 1;				goto writecheck;			}			if (md->pages[i] == -1) {				rd = td;				md->version[i] = td->version[i];				writeops = 2;				goto writecheck;			}

⌨️ 快捷键说明

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