[MTD] NAND: Move the NULL check into the calling function
[safe/jmp/linux-2.6] / drivers / mtd / nand / nand_base.c
index 1806ffa..02e58f5 100644 (file)
@@ -59,7 +59,7 @@
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.132 2005/02/09 14:49:56 dedekind Exp $
+ * $Id: nand_base.c,v 1.140 2005/04/04 18:56:29 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -509,6 +509,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i
        return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+/* 
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long   timeo = jiffies + 2;
+
+       /* wait until command is processed or timeout occures */
+       do {
+               if (this->dev_ready(mtd))
+                       return;
+       } while (time_before(jiffies, timeo));  
+}
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd:       MTD device structure
@@ -604,12 +620,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                        return;
                }       
        }
-       
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -720,12 +735,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                        return;
                }       
        }
-       
+
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -815,7 +830,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
-               msleep(1);
+               cond_resched();
        }
        status = (int) this->read_byte(mtd);
        return status;
@@ -840,7 +855,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
        u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
 {
        int     i, status;
-       u_char  ecc_code[32];
+       u_char  ecc_code[oobsel->eccbytes];
        int     eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
        int     *oob_config = oobsel->eccpos;
        int     datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
@@ -946,7 +961,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
        int     i, j, datidx = 0, oobofs = 0, res = -EIO;
        int     eccsteps = this->eccsteps;
        int     hweccbytes; 
-       u_char  oobdata[64];
+       u_char  oobdata[mtd->oobsize];
 
        hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
 
@@ -1011,7 +1026,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* All done, return happy */
                if (!numpages)
@@ -1045,8 +1060,8 @@ out:
  */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
-       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
-}                         
+       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
 
 
 /**
@@ -1064,6 +1079,9 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
 static int nand_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)
 {
+       /* use userspace supplied oobinfo, if zero */
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
        return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
 }
 
@@ -1075,7 +1093,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
  * @len:       number of bytes to read
  * @retlen:    pointer to variable to store the number of read bytes
  * @buf:       the databuffer to put data
- * @oob_buf:   filesystem supplied oob data buffer
+ * @oob_buf:   filesystem supplied oob data buffer (can be NULL)
  * @oobsel:    oob selection structure
  * @flags:     flag to indicate if nand_get_device/nand_release_device should be preformed
  *             and how many corrected error bits are acceptable:
@@ -1088,12 +1106,13 @@ 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[32];
-       u_char ecc_code[32];
+       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;
@@ -1115,10 +1134,6 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        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;
@@ -1302,7 +1317,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                if (read == len)
                        break;  
@@ -1401,7 +1416,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* Read more ? */
                if (i < len) {
@@ -1481,7 +1496,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                /* Check, if the chip supports auto page increment */ 
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -2276,7 +2291,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-       int i, j, nand_maf_id, nand_dev_id, busw;
+       int i, nand_maf_id, nand_dev_id, busw, maf_id;
        struct nand_chip *this = mtd->priv;
 
        /* Get buswidth to select the correct functions*/
@@ -2364,12 +2379,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
                }
 
+               /* Try to identify manufacturer */
+               for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+                       if (nand_manuf_ids[maf_id].id == nand_maf_id)
+                               break;
+               }
+
                /* Check, if buswidth is correct. Hardware drivers should set
                 * this correct ! */
                if (busw != (this->options & NAND_BUSWIDTH_16)) {
                        printk (KERN_INFO "NAND device: Manufacturer ID:"
                                " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                               nand_manuf_ids[i].name , mtd->name);
+                               nand_manuf_ids[maf_id].name , mtd->name);
                        printk (KERN_WARNING 
                                "NAND bus width %d instead %d bit\n", 
                                        (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2408,14 +2429,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
                        this->cmdfunc = nand_command_lp;
                                
-               /* Try to identify manufacturer */
-               for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-                       if (nand_manuf_ids[j].id == nand_maf_id)
-                               break;
-               }
                printk (KERN_INFO "NAND device: Manufacturer ID:"
                        " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                       nand_manuf_ids[j].name , nand_flash_ids[i].name);
+                       nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
                break;
        }
 
@@ -2496,12 +2512,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
-       if (this->options & NAND_BUSWIDTH_16) {
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-               if (this->autooob->eccbytes & 0x01)
-                       mtd->oobavail--;
-       } else
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+       mtd->oobavail = 0;
+       for (i = 0; this->autooob->oobfree[i][1]; i++)
+               mtd->oobavail += this->autooob->oobfree[i][1];
 
        /* 
         * check ECC mode, default to software