/*
* Linux driver for Disk-On-Chip 2000 and Millennium
* (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 $
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
#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>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/doc2000.h>
#define DOC_SUPPORT_2000
#define DOC_SUPPORT_2000TSOP
#define DOC_SUPPORT_MILLENNIUM
#ifdef DOC_SUPPORT_2000
#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
#else
#define DoC_is_2000(doc) (0)
#endif
#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
#else
#define DoC_is_Millennium(doc) (0)
#endif
/* #define ECC_DEBUG */
/* I have no idea why some DoC chips can not use memcpy_from|to_io().
* This may be due to the different revisions of the ASIC controller built-in or
* simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
* this:
#undef USE_MEMCPY
*/
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_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_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t