/* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) oobsel = &mtd->oobinfo;  
int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,			     size_t * retlen, u_char * buf, u_char * oob_buf, 			     struct nand_oobinfo *oobsel, int flags){	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;	struct nand_chip *this = mtd->priv;	u_char *data_poi, *oob_data = oob_buf;	u_char ecc_calc[oobsel->eccbytes];	u_char ecc_code[oobsel->eccbytes];        int eccmode, eccsteps;	int	*oob_config, datidx;	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;	int	eccbytes;	int	compareecc = 1;	int	oobreadlen;	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	if (flags & NAND_GET_DEVICE)		nand_get_device (this, mtd, FL_READING);	/* use userspace supplied oobinfo, if zero */	if (oobsel == NULL)		oobsel = &mtd->oobinfo;		/* Autoplace of oob data ? Use the default placement scheme */	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)		oobsel = this->autooob;			eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;	oob_config = oobsel->eccpos;	/* Select the NAND device */	chipnr = (int)(from >> this->chip_shift);	this->select_chip(mtd, chipnr);	/* First we calculate the starting page */	realpage = (int) (from >> this->page_shift);	page = realpage & this->pagemask;	/* Get raw starting column */	col = from & (mtd->oobblock - 1);	end = mtd->oobblock;	ecc = this->eccsize;	eccbytes = this->eccbytes;		if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))		compareecc = 0;	oobreadlen = mtd->oobsize;	if (this->options & NAND_HWECC_SYNDROME) 		oobreadlen -= oobsel->eccbytes;	/* Loop until all data read */	while (read < len) {				int aligned = (!col && (len - read) >= end);		/* 		 * If the read is not page aligned, we have to read into data buffer		 * due to ecc, else we read into return buffer direct		 */		if (aligned)			data_poi = &buf[read];		else 			data_poi = this->data_buf;				/* Check, if we have this page in the buffer 		 *		 * FIXME: Make it work when we must provide oob data too,		 * check the usage of data_buf oob field		 */		if (realpage == this->pagebuf && !oob_buf) {			/* aligned read ? */			if (aligned)				memcpy (data_poi, this->data_buf, end);			goto readdata;		}		/* Check, if we must send the read command */		if (sndcmd) {			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);			sndcmd = 0;		}			/* get oob area, if we have no oob buffer from fs-driver */		if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)			oob_data = &this->data_buf[end];		eccsteps = this->eccsteps;				switch (eccmode) {		case NAND_ECC_NONE: {	/* No ECC, Read in a page */			static unsigned long lastwhinge = 0;			if ((lastwhinge / HZ) != (jiffies / HZ)) {				printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");				lastwhinge = jiffies;			}			this->read_buf(mtd, data_poi, end);			break;		}					case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */			this->read_buf(mtd, data_poi, end);			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 				this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);			break;			default:			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {				this->enable_hwecc(mtd, NAND_ECC_READ);				this->read_buf(mtd, &data_poi[datidx], ecc);				/* HW ecc with syndrome calculation must read the				 * syndrome from flash immidiately after the data */				if (!compareecc) {					/* Some hw ecc generators need to know when the					 * syndrome is read from flash */					this->enable_hwecc(mtd, NAND_ECC_READSYN);					this->read_buf(mtd, &oob_data[i], eccbytes);					/* We calc error correction directly, it checks the hw					 * generator for an error, reads back the syndrome and					 * does the error correction on the fly */					ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);					if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {						DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 							"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);						ecc_failed++;					}				} else {					this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);				}				}			break;								}		/* read oobdata */		this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);		/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */		if (!compareecc)			goto readoob;					/* Pick the ECC bytes out of the oob data */		for (j = 0; j < oobsel->eccbytes; j++)			ecc_code[j] = oob_data[oob_config[j]];		/* correct data, if neccecary */		for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {			ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);						/* Get next chunk of ecc bytes */			j += eccbytes;						/* Check, if we have a fs supplied oob-buffer, 			 * This is the legacy mode. Used by YAFFS1			 * Should go away some day			 */			if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 				int *p = (int *)(&oob_data[mtd->oobsize]);				p[i] = ecc_status;			}						if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {					DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);				ecc_failed++;			}		}			readoob:		/* check, if we have a fs supplied oob-buffer */		if (oob_buf) {			/* without autoplace. Legacy mode used by YAFFS1 */			switch(oobsel->useecc) {			case MTD_NANDECC_AUTOPLACE:				/* Walk through the autoplace chunks */				for (i = 0, j = 0; j < mtd->oobavail; i++) {					int from = oobsel->oobfree[i][0];					int num = oobsel->oobfree[i][1];					memcpy(&oob_buf[oob], &oob_data[from], num);					j+= num;				}				oob += mtd->oobavail;				break;			case MTD_NANDECC_PLACE:				/* YAFFS1 legacy mode */				oob_data += this->eccsteps * sizeof (int);			default:				oob_data += mtd->oobsize;			}		}	readdata:		/* Partial page read, transfer data into fs buffer */		if (!aligned) { 			for (j = col; j < end && read < len; j++)				buf[read++] = data_poi[j];			this->pagebuf = realpage;			} else					read += mtd->oobblock;		/* Apply delay or wait for ready/busy pin 		 * Do this before the AUTOINCR check, so no problems		 * arise if a chip which does auto increment		 * is marked as NOAUTOINCR by the board driver.		*/		if (!this->dev_ready) 			udelay (this->chip_delay);		else			nand_wait_ready(mtd);					if (read == len)			break;			/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		realpage++;		page = realpage & this->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			this->select_chip(mtd, -1);			this->select_chip(mtd, chipnr);		}		/* Check, if the chip supports auto page increment 		 * or if we have hit a block boundary. 		*/ 		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))			sndcmd = 1;					}	/* Deselect and wake up anyone waiting on the device */	if (flags & NAND_GET_DEVICE)		nand_release_device(mtd);	/*	 * Return success, if no ECC failures, else -EBADMSG	 * fs driver will take care of that, because	 * retlen == desired len and result == -EBADMSG	 */	*retlen = read;	return ecc_failed ? -EBADMSG : 0;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/bb75ba4c442c6aa73797c35651a697b0a8006bd6/nand_base.c/clean/drivers/mtd/nand/nand_base.c