* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
- * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/mutex.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
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_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
- 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_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
{
volatile char dummy;
int i;
-
+
for (i = 0; i < cycles; i++) {
if (DoC_is_Millennium(doc))
dummy = ReadDOC(doc->virtadr, NOP);
else
dummy = ReadDOC(doc->virtadr, DOCStatus);
}
-
+
}
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
-static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+static int DoC_Command(struct DiskOnChip *doc, unsigned char command,
unsigned char xtraflags)
{
void __iomem *docptr = doc->virtadr;
WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */
-
- /* FIXME: The SlowIO's for millennium could be replaced by
+
+ /* FIXME: The SlowIO's for millennium could be replaced by
a single WritePipeTerm here. mf. */
/* Lower the ALE line */
if (mfr == 0xff || mfr == 0)
return 0;
- /* Check it's the same as the first chip we identified.
+ /* Check it's the same as the first chip we identified.
* M-Systems say that any given DiskOnChip device should only
- * contain _one_ type of flash part, although that's not a
+ * contain _one_ type of flash part, although that's not a
* hardware restriction. */
if (doc->mfr) {
if (doc->mfr == mfr && doc->id == id)
for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
if (nand_manuf_ids[j].id == mfr)
break;
- }
+ }
printk(KERN_INFO
"Flash chip found: Manufacturer ID: %2.2X, "
"Chip ID: %2.2X (%s:%s)\n", mfr, id,
if (!doc->mfr) {
doc->mfr = mfr;
doc->id = id;
- doc->chipshift =
+ doc->chipshift =
ffs((nand_flash_ids[i].chipsize << 20)) - 1;
doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
ret = 0;
- /* 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; floor < MAX_FLOORS; floor++) {
for (chip = 0; chip < numchips[floor]; chip++) {
return retval;
}
-static const char im_name[] = "DoC2k_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 DoC2k_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 DoC2k_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
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;
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
- mtd->read_ecc = doc_read_ecc;
- mtd->write_ecc = doc_write_ecc;
- mtd->writev_ecc = doc_writev_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
this->curfloor = -1;
this->curchip = -1;
- init_MUTEX(&this->lock);
+ mutex_init(&this->lock);
/* Ident all the chips present. */
DoC_ScanChips(this, maxchips);
return;
}
}
+EXPORT_SYMBOL_GPL(DoC2k_init);
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
if (from >= this->totlen)
return -EINVAL;
- down(&this->lock);
+ mutex_lock(&this->lock);
*retlen = 0;
while (left) {
(long)from, eccbuf[0], eccbuf[1], eccbuf[2],
eccbuf[3], eccbuf[4], eccbuf[5]);
#endif
-
+
/* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
}
- /* according to 11.4.1, we need to wait for the busy line
+ /* according to 11.4.1, we need to wait for the busy line
* drop if we read to the end of the page. */
if(0 == ((from + len) & 0x1ff))
{
buf += len;
}
- up(&this->lock);
+ mutex_unlock(&this->lock);
return ret;
}
if (to >= this->totlen)
return -EINVAL;
- down(&this->lock);
+ mutex_lock(&this->lock);
*retlen = 0;
while (left) {
printk(KERN_ERR "Error programming flash\n");
/* Error in programming */
*retlen = 0;
- up(&this->lock);
+ mutex_unlock(&this->lock);
return -EIO;
}
printk(KERN_ERR "Error programming flash\n");
/* Error in programming */
*retlen = 0;
- up(&this->lock);
+ mutex_unlock(&this->lock);
return -EIO;
}
/* Let the caller know we completed it */
*retlen += len;
-
+
if (eccbuf) {
unsigned char x[8];
size_t dummy;
/* Write the ECC data to flash */
for (di=0; di<6; di++)
x[di] = eccbuf[di];
-
+
x[6]=0x55;
x[7]=0x55;
-
+
ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
if (ret) {
- up(&this->lock);
+ mutex_unlock(&this->lock);
return ret;
}
}
buf += len;
}
- up(&this->lock);
+ mutex_unlock(&this->lock);
return 0;
}
-static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
- u_char *eccbuf, struct nand_oobinfo *oobsel)
-{
- static char static_buf[512];
- static DECLARE_MUTEX(writev_buf_sem);
-
- size_t totretlen = 0;
- size_t thisvecofs = 0;
- int ret= 0;
-
- down(&writev_buf_sem);
-
- while(count) {
- size_t thislen, thisretlen;
- unsigned char *buf;
-
- buf = vecs->iov_base + thisvecofs;
- thislen = vecs->iov_len - thisvecofs;
-
-
- if (thislen >= 512) {
- thislen = thislen & ~(512-1);
- thisvecofs += thislen;
- } else {
- /* Not enough to fill a page. Copy into buf */
- memcpy(static_buf, buf, thislen);
- buf = &static_buf[thislen];
-
- while(count && thislen < 512) {
- vecs++;
- count--;
- thisvecofs = min((512-thislen), vecs->iov_len);
- memcpy(buf, vecs->iov_base, thisvecofs);
- thislen += thisvecofs;
- buf += thisvecofs;
- }
- buf = static_buf;
- }
- if (count && thisvecofs == vecs->iov_len) {
- thisvecofs = 0;
- vecs++;
- count--;
- }
- ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
-
- totretlen += thisretlen;
-
- if (ret || thisretlen != thislen)
- break;
-
- to += thislen;
- }
-
- up(&writev_buf_sem);
- *retlen = totretlen;
- 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)
{
struct DiskOnChip *this = mtd->priv;
int len256 = 0, ret;
struct Nand *mychip;
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
- down(&this->lock);
+ mutex_lock(&this->lock);
mychip = &this->chips[ofs >> this->chipshift];
DoC_ReadBuf(this, &buf[len256], len - len256);
- *retlen = len;
+ ops->retlen = len;
/* Reading the full OOB data drops us off of the end of the page,
* causing the flash device to go into busy mode, so we need
* to wait until ready 11.4.1 and Toshiba TC58256FT docs */
-
+
ret = DoC_WaitReady(this);
- up(&this->lock);
+ mutex_unlock(&this->lock);
return ret;
}
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)
{
- struct DiskOnChip *this = mtd->priv;
- int ret;
+ struct DiskOnChip *this = mtd->priv;
+ int ret;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
- down(&this->lock);
- ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf);
+ mutex_lock(&this->lock);
+ ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len,
+ &ops->retlen, ops->oobbuf);
- up(&this->lock);
- return ret;
+ mutex_unlock(&this->lock);
+ return ret;
}
static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
struct Nand *mychip;
int status;
- down(&this->lock);
+ mutex_lock(&this->lock);
if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) {
- up(&this->lock);
+ mutex_unlock(&this->lock);
return -EINVAL;
}
instr->state = MTD_ERASING;
-
+
/* FIXME: Do this in the background. Use timers or schedule_task() */
while(len) {
mychip = &this->chips[ofs >> this->chipshift];
callback:
mtd_erase_callback(instr);
- up(&this->lock);
+ mutex_unlock(&this->lock);
return 0;
}
*
****************************************************************************/
-static int __init init_doc2000(void)
-{
- inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
- return 0;
-}
-
static void __exit cleanup_doc2000(void)
{
struct mtd_info *mtd;
kfree(this->chips);
kfree(mtd);
}
- inter_module_unregister(im_name);
}
module_exit(cleanup_doc2000);
-module_init(init_doc2000);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");