[MTD] Use mutex instead of semaphore in dataflash driver
[linux-2.6.git] / drivers / mtd / devices / doc2001plus.c
index ed47baf..2b30b58 100644 (file)
@@ -6,7 +6,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $
  *
  * Released under GPL
  */
 #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/types.h>
 #include <linux/bitops.h>
@@ -41,16 +39,10 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf);
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char *buf, u_char *eccbuf,
-               struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-               size_t *retlen, const u_char *buf, u_char *eccbuf,
-               struct nand_oobinfo *oobsel);
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-               size_t *retlen, u_char *buf);
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-               size_t *retlen, const u_char *buf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+                       struct mtd_oob_ops *ops);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+                        struct mtd_oob_ops *ops);
 static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
 
 static struct mtd_info *docmilpluslist = NULL;
@@ -118,7 +110,7 @@ static inline void DoC_CheckASIC(void __iomem * docptr)
 /* DoC_Command: Send a flash command to the flash chip through the Flash
  * command register. Need 2 Write Pipeline Terminates to complete send.
  */
-static inline void DoC_Command(void __iomem * docptr, unsigned char command,
+static void DoC_Command(void __iomem * docptr, unsigned char command,
                               unsigned char xtraflags)
 {
        WriteDOC(command, docptr, Mplus_FlashCmd);
@@ -293,10 +285,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        DoC_Command(docptr, NAND_CMD_RESET, 0);
        DoC_WaitReady(docptr);
 
-       /* Read the NAND chip ID: 1. Send ReadID command */ 
+       /* Read the NAND chip ID: 1. Send ReadID command */
        DoC_Command(docptr, NAND_CMD_READID, 0);
 
-       /* Read the NAND chip ID: 2. Send address byte zero */ 
+       /* Read the NAND chip ID: 2. Send address byte zero */
        DoC_Address(doc, 1, 0x00, 0, 0x00);
 
        WriteDOC(0, docptr, Mplus_FlashControl);
@@ -365,7 +357,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                this->interleave = 1;
 
        /* Check the ASIC agrees */
-       if ( (this->interleave << 2) != 
+       if ( (this->interleave << 2) !=
             (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
                u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
                printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
@@ -398,7 +390,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                return;
        }
 
-       /* Fill out the chip array with {floor, chipno} for each 
+       /* Fill out the chip array with {floor, chipno} for each
         * detected chip in the device. */
        for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
                for (chip = 0 ; chip < numchips[floor] ; chip++) {
@@ -432,7 +424,7 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
        if (tmp1 != tmp2)
                return 0;
-       
+
        WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
        if (tmp2 == (tmp1+1) % 0xff)
@@ -447,16 +439,9 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        return retval;
 }
 
-static const char im_name[] = "DoCMilPlus_init";
-
-/* This routine is made available to other mtd code via
- * inter_module_register.  It must only be accessed through
- * inter_module_get which will bump the use count of this module.  The
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoCMilPlus_init(struct mtd_info *mtd)
+/* This routine is found from the docprobe code by symbol_get(),
+ * which will bump the use count of this module. */
+void DoCMilPlus_init(struct mtd_info *mtd)
 {
        struct DiskOnChip *this = mtd->priv;
        struct DiskOnChip *old = NULL;
@@ -486,11 +471,10 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
 
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
-       mtd->ecctype = MTD_ECC_RS_DiskOnChip;
        mtd->size = 0;
 
        mtd->erasesize = 0;
-       mtd->oobblock = 512;
+       mtd->writesize = 512;
        mtd->oobsize = 16;
        mtd->owner = THIS_MODULE;
        mtd->erase = doc_erase;
@@ -498,8 +482,6 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
        mtd->unpoint = NULL;
        mtd->read = doc_read;
        mtd->write = doc_write;
-       mtd->read_ecc = doc_read_ecc;
-       mtd->write_ecc = doc_write_ecc;
        mtd->read_oob = doc_read_oob;
        mtd->write_oob = doc_write_oob;
        mtd->sync = NULL;
@@ -524,6 +506,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
                return;
        }
 }
+EXPORT_SYMBOL_GPL(DoCMilPlus_init);
 
 #if 0
 static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
@@ -603,18 +586,10 @@ static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
 static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
                    size_t *retlen, u_char *buf)
 {
-       /* Just a special case of doc_read_ecc */
-       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *oobsel)
-{
        int ret, i;
        volatile char dummy;
        loff_t fofs;
-       unsigned char syndrome[6];
+       unsigned char syndrome[6], eccbuf[6];
        struct DiskOnChip *this = mtd->priv;
        void __iomem * docptr = this->virtadr;
        struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -624,7 +599,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                return -EINVAL;
 
        /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ((from | 0x1ff) + 1)) 
+       if (from + len > ((from | 0x1ff) + 1))
                len = ((from | 0x1ff) + 1) - from;
 
        DoC_CheckASIC(docptr);
@@ -652,56 +627,51 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
        WriteDOC(0, docptr, Mplus_FlashControl);
        DoC_WaitReady(docptr);
 
-       if (eccbuf) {
-               /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-               WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-               WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-       } else {
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-       }
+       /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+       WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+       WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
 
        /* Let the caller know we completed it */
        *retlen = len;
-        ret = 0;
+       ret = 0;
 
        ReadDOC(docptr, Mplus_ReadPipeInit);
        ReadDOC(docptr, Mplus_ReadPipeInit);
 
-       if (eccbuf) {
-               /* Read the data via the internal pipeline through CDSN IO
-                  register, see Pipelined Read Operations 11.3 */
-               MemReadDOC(docptr, buf, len);
+       /* Read the data via the internal pipeline through CDSN IO
+          register, see Pipelined Read Operations 11.3 */
+       MemReadDOC(docptr, buf, len);
 
-               /* Read the ECC data following raw data */
-               MemReadDOC(docptr, eccbuf, 4);
-               eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
-               eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
+       /* Read the ECC data following raw data */
+       MemReadDOC(docptr, eccbuf, 4);
+       eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
+       eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
 
-               /* Flush the pipeline */
-               dummy = ReadDOC(docptr, Mplus_ECCConf);
-               dummy = ReadDOC(docptr, Mplus_ECCConf);
+       /* Flush the pipeline */
+       dummy = ReadDOC(docptr, Mplus_ECCConf);
+       dummy = ReadDOC(docptr, Mplus_ECCConf);
 
-               /* Check the ECC Status */
-               if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
-                        int nb_errors;
-                       /* There was an ECC error */
+       /* Check the ECC Status */
+       if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
+               int nb_errors;
+               /* There was an ECC error */
 #ifdef ECC_DEBUG
-                       printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+               printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
-                          These syndrome will be all ZERO when there is no error */
-                       for (i = 0; i < 6; i++)
-                               syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+               /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                  These syndrome will be all ZERO when there is no error */
+               for (i = 0; i < 6; i++)
+                       syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
 
-                        nb_errors = doc_decode_ecc(buf, syndrome);
+               nb_errors = doc_decode_ecc(buf, syndrome);
 #ifdef ECC_DEBUG
-                       printk("ECC Errors corrected: %x\n", nb_errors);
+               printk("ECC Errors corrected: %x\n", nb_errors);
 #endif
-                        if (nb_errors < 0) {
-                               /* We return error, but have actually done the read. Not that
-                                  this can be told to user-space, via sys_read(), but at least
-                                  MTD-aware stuff can know about it by checking *retlen */
+               if (nb_errors < 0) {
+                       /* We return error, but have actually done the
+                          read. Not that this can be told to user-space, via
+                          sys_read(), but at least MTD-aware stuff can know
+                          about it by checking *retlen */
 #ifdef ECC_DEBUG
                        printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
                                __FILE__, __LINE__, (int)from);
@@ -715,24 +685,16 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                                eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
                                ret = -EIO;
-                        }
                }
+       }
 
 #ifdef PSYCHO_DEBUG
-               printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                      (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-                      eccbuf[4], eccbuf[5]);
+       printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+              (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+              eccbuf[4], eccbuf[5]);
 #endif
-
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
-       } else {
-               /* Read the data via the internal pipeline through CDSN IO
-                  register, see Pipelined Read Operations 11.3 */
-               MemReadDOC(docptr, buf, len-2);
-               buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
-               buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
-       }
+       /* disable the ECC engine */
+       WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
 
        /* Disable flash internally */
        WriteDOC(0, docptr, Mplus_FlashSelect);
@@ -743,17 +705,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t *retlen, const u_char *buf)
 {
-       char eccbuf[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                        size_t *retlen, const u_char *buf, u_char *eccbuf,
-                        struct nand_oobinfo *oobsel)
-{
        int i, before, ret = 0;
        loff_t fto;
        volatile char dummy;
+       char eccbuf[6];
        struct DiskOnChip *this = mtd->priv;
        void __iomem * docptr = this->virtadr;
        struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@@ -803,46 +758,42 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
        /* Disable the ECC engine */
        WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
 
-       if (eccbuf) {
-               if (before) {
-                       /* Write the block status BLOCK_USED (0x5555) */
-                       WriteDOC(0x55, docptr, Mil_CDSN_IO);
-                       WriteDOC(0x55, docptr, Mil_CDSN_IO);
-               }
-
-               /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+       if (before) {
+               /* Write the block status BLOCK_USED (0x5555) */
+               WriteDOC(0x55, docptr, Mil_CDSN_IO);
+               WriteDOC(0x55, docptr, Mil_CDSN_IO);
        }
 
+       /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+       WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+
        MemWriteDOC(docptr, (unsigned char *) buf, len);
 
-       if (eccbuf) {
-               /* Write ECC data to flash, the ECC info is generated by
-                  the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
-               DoC_Delay(docptr, 3);
+       /* Write ECC data to flash, the ECC info is generated by
+          the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
+       DoC_Delay(docptr, 3);
 
-               /* Read the ECC data through the DiskOnChip ECC logic */
-               for (i = 0; i < 6; i++)
-                       eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+       /* Read the ECC data through the DiskOnChip ECC logic */
+       for (i = 0; i < 6; i++)
+               eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
 
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+       /* disable the ECC engine */
+       WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
 
-               /* Write the ECC data to flash */
-               MemWriteDOC(docptr, eccbuf, 6);
+       /* Write the ECC data to flash */
+       MemWriteDOC(docptr, eccbuf, 6);
 
-               if (!before) {
-                       /* Write the block status BLOCK_USED (0x5555) */
-                       WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
-                       WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
-               }
+       if (!before) {
+               /* Write the block status BLOCK_USED (0x5555) */
+               WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
+               WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
+       }
 
 #ifdef PSYCHO_DEBUG
-               printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                      (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-                      eccbuf[4], eccbuf[5]);
+       printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+              (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+              eccbuf[4], eccbuf[5]);
 #endif
-       }
 
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
@@ -876,14 +827,20 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
        return ret;
 }
 
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-                       size_t *retlen, u_char *buf)
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+                       struct mtd_oob_ops *ops)
 {
        loff_t fofs, base;
        struct DiskOnChip *this = mtd->priv;
        void __iomem * docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
        size_t i, size, got, want;
+       uint8_t *buf = ops->oobbuf;
+       size_t len = ops->len;
+
+       BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+       ofs += ops->ooboffs;
 
        DoC_CheckASIC(docptr);
 
@@ -949,12 +906,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        /* Disable flash internally */
        WriteDOC(0, docptr, Mplus_FlashSelect);
 
-       *retlen = len;
+       ops->retlen = len;
        return 0;
 }
 
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-                        size_t *retlen, const u_char *buf)
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+                        struct mtd_oob_ops *ops)
 {
        volatile char dummy;
        loff_t fofs, base;
@@ -963,6 +920,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
        size_t i, size, got, want;
        int ret = 0;
+       uint8_t *buf = ops->oobbuf;
+       size_t len = ops->len;
+
+       BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+       ofs += ops->ooboffs;
 
        DoC_CheckASIC(docptr);
 
@@ -1038,7 +1001,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        printk("MTD: Error 0x%x programming oob at 0x%x\n",
                                dummy, (int)ofs);
                        /* FIXME: implement Bad Block Replacement */
-                       *retlen = 0;
+                       ops->retlen = 0;
                        ret = -EIO;
                }
                dummy = ReadDOC(docptr, Mplus_LastDataRead);
@@ -1051,7 +1014,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        /* Disable flash internally */
        WriteDOC(0, docptr, Mplus_FlashSelect);
 
-       *retlen = len;
+       ops->retlen = len;
        return ret;
 }
 
@@ -1066,7 +1029,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
 
        DoC_CheckASIC(docptr);
 
-       if (len != mtd->erasesize) 
+       if (len != mtd->erasesize)
                printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
                       len, mtd->erasesize);
 
@@ -1122,12 +1085,6 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
  *
  ****************************************************************************/
 
-static int __init init_doc2001plus(void)
-{
-       inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
-       return 0;
-}
-
 static void __exit cleanup_doc2001plus(void)
 {
        struct mtd_info *mtd;
@@ -1136,18 +1093,16 @@ static void __exit cleanup_doc2001plus(void)
        while ((mtd=docmilpluslist)) {
                this = mtd->priv;
                docmilpluslist = this->nextdoc;
-                       
+
                del_mtd_device(mtd);
-                       
+
                iounmap(this->virtadr);
                kfree(this->chips);
                kfree(mtd);
        }
-       inter_module_unregister(im_name);
 }
 
 module_exit(cleanup_doc2001plus);
-module_init(init_doc2001plus);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");