diff -uNr --exclude CVS mtd-19990810/include/ftl.h mtd-19990817/include/ftl.h --- mtd-19990810/include/ftl.h Fri Jan 8 13:59:35 1999 +++ mtd-19990817/include/ftl.h Thu Jan 1 01:00:00 1970 @@ -1,48 +0,0 @@ -/* - * ftl.h 1.1 1995/05/23 19:52:23 (David Hinds) - */ - -#ifndef _LINUX_FTL_H -#define _LINUX_FTL_H - -typedef struct erase_unit_header_t { - u_char LinkTargetTuple[5]; - u_char DataOrgTuple[10]; - u_char NumTransferUnits; - u_long EraseCount; - u_short LogicalEUN; - u_char BlockSize; - u_char EraseUnitSize; - u_short FirstPhysicalEUN; - u_short NumEraseUnits; - u_long FormattedSize; - u_long FirstVMAddress; - u_short NumVMPages; - u_char Flags; - u_char Code; - u_long SerialNumber; - u_long AltEUHOffset; - u_long BAMOffset; - u_char Reserved[12]; - u_char EndTuple[2]; -} erase_unit_header_t; - -/* Flags in erase_unit_header_t */ -#define HIDDEN_AREA 0x01 -#define REVERSE_POLARITY 0x02 -#define DOUBLE_BAI 0x04 - -/* Definitions for block allocation information */ - -#define BLOCK_FREE(b) ((b) == 0xffffffff) -#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) - -#define BLOCK_TYPE(b) ((b) & 0x7f) -#define BLOCK_ADDRESS(b) ((b) & ~0x7f) -#define BLOCK_NUMBER(b) ((b) >> 9) -#define BLOCK_CONTROL 0x30 -#define BLOCK_DATA 0x40 -#define BLOCK_REPLACEMENT 0x60 -#define BLOCK_BAD 0x70 - -#endif /* _LINUX_FTL_H */ diff -uNr --exclude CVS mtd-19990810/include/iflash.h mtd-19990817/include/iflash.h --- mtd-19990810/include/iflash.h Fri Jan 8 13:59:35 1999 +++ mtd-19990817/include/iflash.h Thu Jan 1 01:00:00 1970 @@ -1,98 +0,0 @@ -/* iflash.h $revision$ $date$ (David Hinds) */ - -#ifndef _LINUX_IFLASH_H -#define _LINUX_IFLASH_H - -/* Extended CIS registers for Series 2 and 2+ cards */ -/* The registers are all offsets from 0x4000 */ -#define CISREG_CSR 0x0100 -#define CISREG_WP 0x0104 -#define CISREG_RDYBSY 0x0140 - -/* Extended CIS registers for Series 2 cards */ -#define CISREG_SLEEP 0x0118 -#define CISREG_RDY_MASK 0x0120 -#define CISREG_RDY_STATUS 0x0130 - -/* Extended CIS registers for Series 2+ cards */ -#define CISREG_VCR 0x010c - -/* Card Status Register */ -#define CSR_SRESET 0x20 /* Soft reset */ -#define CSR_CMWP 0x10 /* Common memory write protect */ -#define CSR_PWRDOWN 0x08 /* Power down status */ -#define CSR_CISWP 0x04 /* Common memory CIS WP */ -#define CSR_WP 0x02 /* Mechanical write protect */ -#define CSR_READY 0x01 /* Ready/busy status */ - -/* Write Protection Register */ -#define WP_BLKEN 0x04 /* Enable block locking */ -#define WP_CMWP 0x02 /* Common memory write protect */ -#define WP_CISWP 0x01 /* Common memory CIS WP */ - -/* Voltage Control Register */ -#define VCR_VCC_LEVEL 0x80 /* 0 = 5V, 1 = 3.3V */ -#define VCR_VPP_VALID 0x02 /* Vpp Valid */ -#define VCR_VPP_GEN 0x01 /* Integrated Vpp generator */ - -/* Ready/Busy Mode Register */ -#define RDYBSY_RACK 0x02 /* Ready acknowledge */ -#define RDYBSY_MODE 0x01 /* 1 = high performance */ - -#define LOW(x) ((x) & 0xff) - -/* 28F008SA-Compatible Command Set */ -#define IF_READ_ARRAY 0xffff -#define IF_INTEL_ID 0x9090 -#define IF_READ_CSR 0x7070 -#define IF_CLEAR_CSR 0x5050 -#define IF_WRITE 0x4040 -#define IF_BLOCK_ERASE 0x2020 -#define IF_ERASE_SUSPEND 0xb0b0 -#define IF_CONFIRM 0xd0d0 - -/* 28F016SA Performance Enhancement Commands */ -#define IF_READ_PAGE 0x7575 -#define IF_PAGE_SWAP 0x7272 -#define IF_SINGLE_LOAD 0x7474 -#define IF_SEQ_LOAD 0xe0e0 -#define IF_PAGE_WRITE 0x0c0c -#define IF_RDY_MODE 0x9696 -#define IF_RDY_LEVEL 0x0101 -#define IF_RDY_PULSE_WRITE 0x0202 -#define IF_RDY_PULSE_ERASE 0x0303 -#define IF_RDY_DISABLE 0x0404 -#define IF_LOCK_BLOCK 0x7777 -#define IF_UPLOAD_STATUS 0x9797 -#define IF_READ_ESR 0x7171 -#define IF_ERASE_UNLOCKED 0xa7a7 -#define IF_SLEEP 0xf0f0 -#define IF_ABORT 0x8080 -#define IF_UPLOAD_DEVINFO 0x9999 - -/* Definitions for Compatible Status Register */ -#define CSR_WR_READY 0x8080 /* Write state machine status */ -#define CSR_ERA_SUSPEND 0x4040 /* Erase suspend status */ -#define CSR_ERA_ERR 0x2020 /* Erase status */ -#define CSR_WR_ERR 0x1010 /* Data write status */ -#define CSR_VPP_LOW 0x0808 /* Vpp status */ - -/* Definitions for Global Status Register */ -#define GSR_WR_READY 0x8080 /* Write state machine status */ -#define GSR_OP_SUSPEND 0x4040 /* Operation suspend status */ -#define GSR_OP_ERR 0x2020 /* Device operation status */ -#define GSR_SLEEP 0x1010 /* Device sleep status */ -#define GSR_QUEUE_FULL 0x0808 /* Queue status */ -#define GSR_PAGE_AVAIL 0x0404 /* Page buffer available status */ -#define GSR_PAGE_READY 0x0202 /* Page buffer status */ -#define GSR_PAGE_SELECT 0x0101 /* Page buffer select status */ - -/* Definitions for Block Status Register */ -#define BSR_READY 0x8080 /* Block status */ -#define BSR_UNLOCK 0x4040 /* Block lock status */ -#define BSR_FAILED 0x2020 /* Block operation status */ -#define BSR_ABORTED 0x1010 /* Operation abort status */ -#define BSR_QUEUE_FULL 0x0808 /* Queue status */ -#define BSR_VPP_LOW 0x0404 /* Vpp status */ - -#endif /* _LINUX_IFLASH_H */ diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/doc2000.h mtd-19990817/include/linux/mtd/doc2000.h --- mtd-19990810/include/linux/mtd/doc2000.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/doc2000.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,110 @@ + +/* Linux driver for Disk-On-Chip 2000 */ +/* (c) 1999 Machine Vision Holdings, Inc. */ +/* Author: David Woodhouse */ +/* $Id: doc2000.h,v 1.1 1999/08/17 16:36:03 dwmw2 Exp $ */ + +#ifndef __MTD_DOC2000_H__ +#define __MTD_DOC2000_H__ + +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 *eecbuf); +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); +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, u_char *buf); + + +#define DoC_M_CDSN_IO 0x800 + +#define DoC_ChipID 0x1000 +#define DoC_DOCStatus 0x1001 +#define DoC_DOCControl 0x1002 +#define DoC_FloorSelect 0x1003 +#define DoC_CSDNControl 0x1004 +#define DoC_CSDNDeviceSelect 0x1005 +#define DoC_ECCConf 0x1006 +#define DoC_2k_ECCStatus 0x1007 + +#define DoC_CSDNSlowIO 0x100d +#define DoC_ECCSyndrome0 0x1010 +#define DoC_ECCSyndrome1 0x1011 +#define DoC_ECCSyndrome2 0x1012 +#define DoC_ECCSyndrome3 0x1013 +#define DoC_ECCSyndrome4 0x1014 +#define DoC_ECCSyndrome5 0x1015 +#define DoC_AliasResolution 0x101b +#define DoC_ConfigInput 0x101c +#define DoC_ReadPipeInit 0x101d +#define DoC_WritePipeTerm 0x101e +#define DoC_LastDataRead 0x101f +#define DoC_NOP 0x1020 + +#define DoC_2k_CSDN_IO 0x1800 + +#ifdef __i386__ /* i386 readb/writeb or the address with 0xc0000000 _every_ + time. We don't need that, so we just reference it. */ +#define ReadDOC(adr, reg) *(((volatile unsigned char *)adr) + DoC_##reg) +#define WriteDOC(d, adr, reg) (*(((volatile unsigned char *)adr) + DoC_##reg) = d) +#else +#define ReadDOC(adr, reg) readb(((unsigned long)adr) + DoC_##reg) +#define WriteDOC(d, adr, reg) writeb(d, ((unsigned long)adr) + DoC_##reg) +#endif + +#define DOC_MODE_RESET 0 +#define DOC_MODE_NORMAL 1 +#define DOC_MODE_RESERVED1 2 +#define DOC_MODE_RESERVED2 3 + +#define DOC_MODE_MDWREN 4 +#define DOC_MODE_CLR_ERR 0x80 + +#define DOC_ChipID_Doc2k 0x20 +#define DOC_ChipID_DocMil 0x30 + +#define CSDN_CTRL_FR_B 0x80 +#define CSDN_CTRL_ECC_IO 0x20 +#define CSDN_CTRL_FLASH_IO 0x10 +#define CSDN_CTRL_WP 8 +#define CSDN_CTRL_ALE 4 +#define CSDN_CTRL_CLE 2 +#define CSDN_CTRL_CE 1 + +#define DOC_ECC_RESET 0 +#define DOC_ECC_ERROR 0x80 +#define DOC_ECC_RW 0x20 +#define DOC_ECC__EN 0x08 +#define DOC_TOGGLE_BIT 0x04 +#define DOC_ECC_RESV 0x02 +/* We have to also set the reserved bit 1 for enable */ +#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) + +struct Nand { + char floor, chip; + unsigned long curadr; + unsigned char curmode; + /* Also some erase/write/pipeline info when we get that far */ +}; + +#define MAX_FLOORS 4 +#define MAX_CHIPS 4 + +struct DiskOnChip { + unsigned long physadr; + unsigned long virtadr; + unsigned long totlen; + char ChipID; /* Type of DiskOnChip */ + + unsigned long mfr; /* Flash IDs - only one type of flash per device */ + unsigned long id; + int chipshift; + + int curfloor; + int curchip; + + int numchips; + struct Nand *chips; +}; + + +#endif /* __MTD_DOC2000_H__ */ diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/ftl.h mtd-19990817/include/linux/mtd/ftl.h --- mtd-19990810/include/linux/mtd/ftl.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/ftl.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,50 @@ +/* + * ftl.h 1.1 1995/05/23 19:52:23 (David Hinds) + */ + +#ifndef __MTD_FTL_H__ +#define __MTD_FTL_H__ + +typedef struct erase_unit_header_t { + u_char LinkTargetTuple[5]; + u_char DataOrgTuple[10]; + u_char NumTransferUnits; + u_long EraseCount; + u_short LogicalEUN; + u_char BlockSize; + u_char EraseUnitSize; + u_short FirstPhysicalEUN; + u_short NumEraseUnits; + u_long FormattedSize; + u_long FirstVMAddress; + u_short NumVMPages; + u_char Flags; + u_char Code; + u_long SerialNumber; + u_long AltEUHOffset; + u_long BAMOffset; + u_char Reserved[12]; + u_char EndTuple[2]; +} erase_unit_header_t; + +/* Flags in erase_unit_header_t */ +#define HIDDEN_AREA 0x01 +#define REVERSE_POLARITY 0x02 +#define DOUBLE_BAI 0x04 + +/* Definitions for block allocation information */ + +#define BLOCK_FREE(b) ((b) == 0xffffffff) +#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) + +#define BLOCK_TYPE(b) ((b) & 0x7f) +#define BLOCK_ADDRESS(b) ((b) & ~0x7f) +#define BLOCK_NUMBER(b) ((b) >> 9) +#define BLOCK_CONTROL 0x30 +#define BLOCK_DATA 0x40 +#define BLOCK_REPLACEMENT 0x60 +#define BLOCK_BAD 0x70 + +#endif /* __MTD_FTL_H__ */ + + diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/iflash.h mtd-19990817/include/linux/mtd/iflash.h --- mtd-19990810/include/linux/mtd/iflash.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/iflash.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,98 @@ +/* iflash.h $revision$ $date$ (David Hinds) */ + +#ifndef __MTD_IFLASH_H__ +#define __MTD_IFLASH_H__ + +/* Extended CIS registers for Series 2 and 2+ cards */ +/* The registers are all offsets from 0x4000 */ +#define CISREG_CSR 0x0100 +#define CISREG_WP 0x0104 +#define CISREG_RDYBSY 0x0140 + +/* Extended CIS registers for Series 2 cards */ +#define CISREG_SLEEP 0x0118 +#define CISREG_RDY_MASK 0x0120 +#define CISREG_RDY_STATUS 0x0130 + +/* Extended CIS registers for Series 2+ cards */ +#define CISREG_VCR 0x010c + +/* Card Status Register */ +#define CSR_SRESET 0x20 /* Soft reset */ +#define CSR_CMWP 0x10 /* Common memory write protect */ +#define CSR_PWRDOWN 0x08 /* Power down status */ +#define CSR_CISWP 0x04 /* Common memory CIS WP */ +#define CSR_WP 0x02 /* Mechanical write protect */ +#define CSR_READY 0x01 /* Ready/busy status */ + +/* Write Protection Register */ +#define WP_BLKEN 0x04 /* Enable block locking */ +#define WP_CMWP 0x02 /* Common memory write protect */ +#define WP_CISWP 0x01 /* Common memory CIS WP */ + +/* Voltage Control Register */ +#define VCR_VCC_LEVEL 0x80 /* 0 = 5V, 1 = 3.3V */ +#define VCR_VPP_VALID 0x02 /* Vpp Valid */ +#define VCR_VPP_GEN 0x01 /* Integrated Vpp generator */ + +/* Ready/Busy Mode Register */ +#define RDYBSY_RACK 0x02 /* Ready acknowledge */ +#define RDYBSY_MODE 0x01 /* 1 = high performance */ + +#define LOW(x) ((x) & 0xff) + +/* 28F008SA-Compatible Command Set */ +#define IF_READ_ARRAY 0xffff +#define IF_INTEL_ID 0x9090 +#define IF_READ_CSR 0x7070 +#define IF_CLEAR_CSR 0x5050 +#define IF_WRITE 0x4040 +#define IF_BLOCK_ERASE 0x2020 +#define IF_ERASE_SUSPEND 0xb0b0 +#define IF_CONFIRM 0xd0d0 + +/* 28F016SA Performance Enhancement Commands */ +#define IF_READ_PAGE 0x7575 +#define IF_PAGE_SWAP 0x7272 +#define IF_SINGLE_LOAD 0x7474 +#define IF_SEQ_LOAD 0xe0e0 +#define IF_PAGE_WRITE 0x0c0c +#define IF_RDY_MODE 0x9696 +#define IF_RDY_LEVEL 0x0101 +#define IF_RDY_PULSE_WRITE 0x0202 +#define IF_RDY_PULSE_ERASE 0x0303 +#define IF_RDY_DISABLE 0x0404 +#define IF_LOCK_BLOCK 0x7777 +#define IF_UPLOAD_STATUS 0x9797 +#define IF_READ_ESR 0x7171 +#define IF_ERASE_UNLOCKED 0xa7a7 +#define IF_SLEEP 0xf0f0 +#define IF_ABORT 0x8080 +#define IF_UPLOAD_DEVINFO 0x9999 + +/* Definitions for Compatible Status Register */ +#define CSR_WR_READY 0x8080 /* Write state machine status */ +#define CSR_ERA_SUSPEND 0x4040 /* Erase suspend status */ +#define CSR_ERA_ERR 0x2020 /* Erase status */ +#define CSR_WR_ERR 0x1010 /* Data write status */ +#define CSR_VPP_LOW 0x0808 /* Vpp status */ + +/* Definitions for Global Status Register */ +#define GSR_WR_READY 0x8080 /* Write state machine status */ +#define GSR_OP_SUSPEND 0x4040 /* Operation suspend status */ +#define GSR_OP_ERR 0x2020 /* Device operation status */ +#define GSR_SLEEP 0x1010 /* Device sleep status */ +#define GSR_QUEUE_FULL 0x0808 /* Queue status */ +#define GSR_PAGE_AVAIL 0x0404 /* Page buffer available status */ +#define GSR_PAGE_READY 0x0202 /* Page buffer status */ +#define GSR_PAGE_SELECT 0x0101 /* Page buffer select status */ + +/* Definitions for Block Status Register */ +#define BSR_READY 0x8080 /* Block status */ +#define BSR_UNLOCK 0x4040 /* Block lock status */ +#define BSR_FAILED 0x2020 /* Block operation status */ +#define BSR_ABORTED 0x1010 /* Operation abort status */ +#define BSR_QUEUE_FULL 0x0808 /* Queue status */ +#define BSR_VPP_LOW 0x0404 /* Vpp status */ + +#endif /* __MTD_IFLASH_H__ */ diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/mapped.h mtd-19990817/include/linux/mtd/mapped.h --- mtd-19990810/include/linux/mtd/mapped.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/mapped.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,92 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: mapped.h,v 1.1 1999/08/17 16:36:03 dwmw2 Exp $ +/* ###################################################################### + + Memory Mapped MTD Routines + + These routines are support routines for memory mapped chips, with + routines to support common sorts of flash. For devices that are based + on a memory mapped interface these routines provide everything necessary, + only a window changing function is required by the low level implementation. + + The entry point to setup and register a memory mapped MTD device, + mtd_mapped_setup will perform a detection sequence that can determine + the type size and configuration of many sorts of chip setups. + + ROMs and RAMs are detected and passed off to very simple routines, Flash + writing and erasing is handled as well. + + ##################################################################### */ + /*}}}*/ +#ifndef __MTD_FLASH_H__ +#define __MTD_FLASH_H__ + +#include +#include + +// MTD flags for ordinary flash +struct JEDECTable +{ + u_short jedec; + char *name; + u_long size; + u_long sectorsize; + u_long capabilities; +}; + +// JEDEC being 0 is the end of the chip array +struct flash_chip +{ + u_short jedec; + u_long size; + u_long sectorsize; + u_long base; + u_long capabilities; + + // These markers are filled in by the flash_chip_scan function + u_long start; + u_long length; +}; + +struct mapped_mtd_info +{ + struct mtd_info mtd; + u_long pagesize; // Size of the memory window + u_long maxsize; // Maximum MTD size in pages + u_char mfr,id; + char part[100]; // Part Catalogue number if available + + // Multiple chip support, only used if this is type MTD_FLASH + u_char interleve; // Address chip interleve (0 = concatination) + struct flash_chip chips[5]; + + // Operations + unsigned long (*page)(struct mapped_mtd_info *map,unsigned long page); + int (*jedec_sense)(struct mapped_mtd_info *map); +}; + +extern struct JEDECTable mtd_JEDEC_table[]; + +// Automatic configurators +extern int mtd_mapped_setup(struct mapped_mtd_info *map); +extern int mtd_mapped_remove(struct mapped_mtd_info *map); + +// Generic functions +extern int flash_jedec(struct mapped_mtd_info *map); +extern int flash_erase(struct mtd_info *map, struct erase_info *instr); +extern int flash_write(struct mtd_info *map, loff_t start, size_t len, + size_t *retlen, const u_char *buf); +extern int rom_read(struct mtd_info *map, loff_t start, size_t len, + size_t *retlen, u_char *buf); +extern int ram_write(struct mtd_info *map, loff_t start, size_t len, + size_t *retlen, const u_char *buf); + +// Helpers +extern int page_jump(struct mapped_mtd_info *map,unsigned long start, + unsigned long len,unsigned long *buffer, + unsigned long *size); +extern void flash_chip_scan(struct mapped_mtd_info *map,unsigned long start, + unsigned long len); + +#endif /* __MTD_FLASH_H__ */ diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/mtd.h mtd-19990817/include/linux/mtd/mtd.h --- mtd-19990810/include/linux/mtd/mtd.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/mtd.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,168 @@ + +#ifndef __MTD_MTD_H__ +#define __MTD_MTD_H__ + + +struct erase_info_user { + unsigned long start; + unsigned long length; +}; + + + +#define MTD_CHAR_MAJOR 90 +#define MTD_BLOCK_MAJOR 31 +#define MAX_MTD_DEVICES 16 + + + +#define MTD_ABSENT 0 +#define MTD_RAM 1 +#define MTD_ROM 2 +#define MTD_NORFLASH 3 +#define MTD_NANDFLASH 4 +#define MTD_PEROM 5 +#define MTD_OTHER 14 +#define MTD_UNKNOWN 15 + + + +#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash) +#define MTD_SET_BITS 2 // Bits can be set +#define MTD_ERASEABLE 4 // Has an erase function +#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible +#define MTD_VOLATILE 16 // Set for RAMs +#define MTD_XIP 32 // eXecute-In-Place possible +#define MTD_OOB 64 // Out-of-band data (NAND flash) +#define MTD_ECC 128 // Device capable of automatic ECC + +// Some common devices / combinations of capabilities +#define MTD_CAP_ROM 0 +#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE) +#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE) +#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB) +#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS) + + +// Types of automatic ECC/Checksum available +#define MTD_ECC_NONE 0 // No automatic ECC available +#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip + +struct mtd_info_user { + char name[32]; + u_char type; + u_long flags; + u_long size; // Total size of the MTD + u_long erasesize; + u_long oobblock; // Size of OOB blocks (e.g. 512) + u_long oobsize; // Amount of OOB data per block (e.g. 16) + u_long ecctype; + u_long eccsize; +}; + +#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) +#define MEMERASE _IOW('M', 2, struct erase_info_user) + +#ifndef __KERNEL__ + +typedef struct mtd_info_user mtd_info_t; +typedef struct erase_info_user erase_info_t; + + /* User-space ioctl definitions */ + + +#else /* __KERNEL__ */ + + +#define MTD_ERASE_PENDING 0x01 +#define MTD_ERASING 0x02 +#define MTD_ERASE_SUSPEND 0x04 +#define MTD_ERASE_DONE 0x08 +#define MTD_ERASE_FAILED 0x10 + +struct erase_info { + struct mtd_info *mtd; + u_long addr; + u_long len; + u_long time; + u_long retries; + u_int dev; + u_int cell; + void (*callback) (struct erase_info *self); + u_long priv; + u_char state; + struct erase_info *next; +}; + + +struct mtd_info { + char name[32]; + u_char type; + u_long flags; + u_long size; // Total size of the MTD + u_long erasesize; + u_long oobblock; // Size of OOB blocks (e.g. 512) + u_long oobsize; // Amount of OOB data per block (e.g. 16) + u_long ecctype; + u_long eccsize; + + // Kernel-only stuff starts here. + + struct module *module; + int (*erase) (struct mtd_info *mtd, struct erase_info *instr); + + /* This stuff for eXecute-In-Place */ + int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); + + /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ + void (*unpoint) (struct mtd_info *mtd, u_char * addr); + + + int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + + int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf); + int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf); + + int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + + void (*sync) (struct mtd_info *mtd); + void *priv; + int *lock; +}; + + + /* Kernel-side ioctl definitions */ + + + + +struct mtd_notifier { + void (*func)(struct mtd_info *mtd, int num); + struct mtd_notifier *next; +}; + +extern int add_mtd_device(struct mtd_info *mtd); +extern struct mtd_info *get_mtd_device(u_char num); +extern int del_mtd_device (struct mtd_info *mtd); +extern void register_mtd_notifier (struct mtd_notifier *new); +extern int unregister_mtd_notifier (struct mtd_notifier *old); + + + +#ifndef MTDC +#define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) +#define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) +#define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) +#define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args) +#define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args) +#define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) +#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) +#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) +#endif /* MTDC */ + +#endif /* __KERNEL__ */ + + +#endif /* __MTD_MTD_H__ */ diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/nand.h mtd-19990817/include/linux/mtd/nand.h --- mtd-19990810/include/linux/mtd/nand.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/nand.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,30 @@ + +/* Defines for NAND flash devices */ +/* (c) 1999 Machine Vision Holdings, Inc. */ +/* Author: David Woodhouse */ +/* $Id: nand.h,v 1.1 1999/08/17 16:36:03 dwmw2 Exp $ */ + +#ifndef __MTD_NAND_H__ +#define __MTD_NAND_H__ + +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 +#define NAND_CMD_PGPROG 0x10 +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_ERASE 0x60 +#define NAND_CMD_STATUS 0x70 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_READID 0x90 +#define NAND_CMD_RESET 0xff + +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec + + +#endif /* __MTD_NAND_H__ */ + + + + + + diff -uNr --exclude CVS mtd-19990810/include/linux/mtd/nftl.h mtd-19990817/include/linux/mtd/nftl.h --- mtd-19990810/include/linux/mtd/nftl.h Thu Jan 1 01:00:00 1970 +++ mtd-19990817/include/linux/mtd/nftl.h Tue Aug 17 17:36:03 1999 @@ -0,0 +1,83 @@ + +/* Defines for NAND Flash Translation Layer */ +/* (c) 1999 Machine Vision Holdings, Inc. */ +/* Author: David Woodhouse */ +/* $Id: nftl.h,v 1.1 1999/08/17 16:36:03 dwmw2 Exp $ */ + +#ifndef __MTD_NFTL_H__ +#define __MTD_NFTL_H__ + +#include + +/* Block Control Information */ + +struct nftl_bci { + char ECCSig[6]; + unsigned short Status; +}__attribute__((packed)); + +/* Unit Control Information */ + +struct nftl_uci0 { + unsigned short VirtUnitNum; + unsigned short ReplUnitNum; + unsigned short SpareVirtUnitNum; + unsigned short SpareReplUnitNum; +} __attribute__((packed)); + +struct nftl_uci1 { + char WearInfo[4]; + short EraseMark; + short EraseMark1; +} __attribute__((packed)); + +struct nftl_uci2 { + char WriteInh[4]; + char unused[4]; +} __attribute__((packed)); + +union nftl_uci { + struct nftl_uci0 a; + struct nftl_uci1 b; + struct nftl_uci2 c; +}; + +/* NFTL Media Header */ + +struct NFTLMediaHeader { + char DataOrgID[6]; + unsigned short NumEraseUnits; + unsigned short FirstPhysicalEUN; + unsigned int FormattedSize; + unsigned char UnitSizeFactor; +} __attribute__((packed)); + +#define ERASE_MARK 0x3c69 +#define BLOCK_FREE 0xffff +#define BLOCK_USED 0x5555 +#define BLOCK_IGNORE 0x1111 +#define BLOCK_DELETED 0x0000 + + + + + +struct NFTLrecord { + struct mtd_info *mtd; + u16 MediaUnit, SpareMediaUnit; + u32 EraseSize; + struct NFTLMediaHeader MediaHdr; + u16 numvunits; + u32 long nr_sects; + int head,sect,cyl; +#define numEUNs MediaHdr.NumEraseUnits + u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ + u16 *VirtualUnitTable; /* [numEUNs]: VirtualUnitNumber for each */ + u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ +}; + +#define NFTL_MAJOR 93 +#define MAX_NFTLS 16 + + +#endif /* __MTD_NFTL_H__ */ diff -uNr --exclude CVS mtd-19990810/include/mapped.h mtd-19990817/include/mapped.h --- mtd-19990810/include/mapped.h Mon Aug 9 19:32:14 1999 +++ mtd-19990817/include/mapped.h Thu Jan 1 01:00:00 1970 @@ -1,92 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: mapped.h,v 1.1 1999/08/09 18:32:14 dwmw2 Exp $ -/* ###################################################################### - - Memory Mapped MTD Routines - - These routines are support routines for memory mapped chips, with - routines to support common sorts of flash. For devices that are based - on a memory mapped interface these routines provide everything necessary, - only a window changing function is required by the low level implementation. - - The entry point to setup and register a memory mapped MTD device, - mtd_mapped_setup will perform a detection sequence that can determine - the type size and configuration of many sorts of chip setups. - - ROMs and RAMs are detected and passed off to very simple routines, Flash - writing and erasing is handled as well. - - ##################################################################### */ - /*}}}*/ -#ifndef LINUX_MTD_FLASH_H -#define LINUX_MTD_FLASH_H 1 - -#include -#include "mtd.h" - -// MTD flags for ordinary flash -struct JEDECTable -{ - u_short jedec; - char *name; - u_long size; - u_long sectorsize; - u_long capabilities; -}; - -// JEDEC being 0 is the end of the chip array -struct flash_chip -{ - u_short jedec; - u_long size; - u_long sectorsize; - u_long base; - u_long capabilities; - - // These markers are filled in by the flash_chip_scan function - u_long start; - u_long length; -}; - -struct mapped_mtd_info -{ - struct mtd_info mtd; - u_long pagesize; // Size of the memory window - u_long maxsize; // Maximum MTD size in pages - u_char mfr,id; - char part[100]; // Part Catalogue number if available - - // Multiple chip support, only used if this is type MTD_FLASH - u_char interleve; // Address chip interleve (0 = concatination) - struct flash_chip chips[5]; - - // Operations - unsigned long (*page)(struct mapped_mtd_info *map,unsigned long page); - int (*jedec_sense)(struct mapped_mtd_info *map); -}; - -extern struct JEDECTable mtd_JEDEC_table[]; - -// Automatic configurators -extern int mtd_mapped_setup(struct mapped_mtd_info *map); -extern int mtd_mapped_remove(struct mapped_mtd_info *map); - -// Generic functions -extern int flash_jedec(struct mapped_mtd_info *map); -extern int flash_erase(struct mtd_info *map, struct erase_info *instr); -extern int flash_write(struct mtd_info *map, loff_t start, size_t len, - size_t *retlen, const u_char *buf); -extern int rom_read(struct mtd_info *map, loff_t start, size_t len, - size_t *retlen, u_char *buf); -extern int ram_write(struct mtd_info *map, loff_t start, size_t len, - size_t *retlen, const u_char *buf); - -// Helpers -extern int page_jump(struct mapped_mtd_info *map,unsigned long start, - unsigned long len,unsigned long *buffer, - unsigned long *size); -extern void flash_chip_scan(struct mapped_mtd_info *map,unsigned long start, - unsigned long len); - -#endif diff -uNr --exclude CVS mtd-19990810/include/mtd.h mtd-19990817/include/mtd.h --- mtd-19990810/include/mtd.h Mon Aug 9 20:26:02 1999 +++ mtd-19990817/include/mtd.h Thu Jan 1 01:00:00 1970 @@ -1,167 +0,0 @@ -#ifndef _LINUX_MTD_H_ -#define _LINUX_MTD_H_ - - -struct erase_info_user { - unsigned long start; - unsigned long length; -}; - - - -#define MTD_CHAR_MAJOR 90 -#define MTD_BLOCK_MAJOR 31 -#define MAX_MTD_DEVICES 16 - - - -#define MTD_ABSENT 0 -#define MTD_RAM 1 -#define MTD_ROM 2 -#define MTD_NORFLASH 3 -#define MTD_NANDFLASH 4 -#define MTD_PEROM 5 -#define MTD_OTHER 14 -#define MTD_UNKNOWN 15 - - - -#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash) -#define MTD_SET_BITS 2 // Bits can be set -#define MTD_ERASEABLE 4 // Has an erase function -#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible -#define MTD_VOLATILE 16 // Set for RAMs -#define MTD_XIP 32 // eXecute-In-Place possible -#define MTD_OOB 64 // Out-of-band data (NAND flash) - -// Some common devices / combinations of capabilities -#define MTD_CAP_ROM 0 -#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE) -#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE) -#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB) -#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS) - -struct mtd_info_user { - char name[32]; - u_char type; - u_long flags; - u_long size; // Total size of the MTD - u_long erasesize; - u_long oobblock; // Size of OOB blocks (e.g. 512) - u_long oobsize; // Amount of OOB data per block (e.g. 16) - -#if 0 /* This stuff isn't generic - it's private to the device */ - u_char mfr; - u_char id; - u_char interleave; - u_long devsize; // Size of each device -#endif -}; - -#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) -#define MEMERASE _IOW('M', 2, struct erase_info_user) - -#ifndef __KERNEL__ - -typedef struct mtd_info_user mtd_info_t; -typedef struct erase_info_user erase_info_t; - - /* User-space ioctl definitions */ - - -#else /* __KERNEL__ */ - - -#define MTD_ERASE_PENDING 0x01 -#define MTD_ERASING 0x02 -#define MTD_ERASE_SUSPEND 0x04 -#define MTD_ERASE_DONE 0x08 -#define MTD_ERASE_FAILED 0x10 - -struct erase_info { - struct mtd_info *mtd; - u_long addr; - u_long len; - u_long time; - u_long retries; - u_int dev; - u_int cell; - void (*callback) (struct erase_info *self); - u_long priv; - u_char state; - struct erase_info *next; -}; - - -struct mtd_info { - char name[32]; - u_char type; - u_long flags; - u_long size; // Total size of the MTD - u_long erasesize; - u16 oobblock; // Size of OOB blocks (e.g. 512) - u16 oobsize; // Amount of OOB data per block (e.g. 16) - -#if 0 /* This stuff isn't generic - it's private to the device */ - u_char mfr; - u_char id; - u_char interleave; - u_long devsize; // Size of each device -#endif - - // Kernel-only stuff starts here. - - struct module *module; - int (*erase) (struct mtd_info *mtd, struct erase_info *instr); - - /* This stuff for eXecute-In-Place */ - int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); - - /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ - void (*unpoint) (struct mtd_info *mtd, u_char * addr); - - - int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - - void (*sync) (struct mtd_info *mtd); - void *priv; - int *lock; -}; - - - /* Kernel-side ioctl definitions */ - - - - -struct mtd_notifier { - void (*func)(struct mtd_info *mtd, int num); - struct mtd_notifier *next; -}; - -extern int add_mtd_device(struct mtd_info *mtd); -extern struct mtd_info *get_mtd_device(u_char num); -extern int del_mtd_device (struct mtd_info *mtd); -extern void register_mtd_notifier (struct mtd_notifier *new); -extern int unregister_mtd_notifier (struct mtd_notifier *old); - - - -#ifndef MTDC -#define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) -#define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) -#define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) -#define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args) -#define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args) -#define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) -#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) -#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) -#endif /* MTDC */ - -#endif /* __KERNEL__ */ - - -#endif /* _LINUX_MTD_H_ */ diff -uNr --exclude CVS mtd-19990810/include/nftl.h mtd-19990817/include/nftl.h --- mtd-19990810/include/nftl.h Mon Aug 9 20:32:33 1999 +++ mtd-19990817/include/nftl.h Thu Jan 1 01:00:00 1970 @@ -1,47 +0,0 @@ - -struct doc_bci { - char ECCSig[6]; - unsigned short Status; -}__attribute__((packed)); - -struct doc_uci0 { - unsigned short VirtUnitNum; - unsigned short ReplUnitNum; - unsigned short SpareVirtUnitNum; - unsigned short SpareReplUnitNum; -} __attribute__((packed)); - -struct doc_uci1 { - char WearInfo[4]; - short EraseMark; - short EraseMark1; -} __attribute__((packed)); - -struct doc_uci2 { - char WriteInh[4]; - char unused[4]; -} __attribute__((packed)); - -union doc_uci { - struct doc_uci0 a; - struct doc_uci1 b; - struct doc_uci2 c; -}; - -struct NFTLMediaHeader { - char DataOrgID[6]; - unsigned short NumEraseUnits; - unsigned short FirstPhysicalEUN; - unsigned int FormattedSize; - unsigned char UnitSizeFactor; -} __attribute__((packed)); - -#define NFTL_MAJOR 93 - - - -#define ERASE_MARK 0x3c69 -#define BLOCK_FREE 0xffff -#define BLOCK_USED 0x5555 -#define BLOCK_IGNORE 0x1111 -#define BLOCK_DELETED 0x0000 diff -uNr --exclude CVS mtd-19990810/kernel/doc1000.c mtd-19990817/kernel/doc1000.c --- mtd-19990810/kernel/doc1000.c Mon Aug 9 19:04:57 1999 +++ mtd-19990817/kernel/doc1000.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: doc1000.c,v 1.2 1999/08/09 18:04:57 dwmw2 Exp $ + $Id: doc1000.c,v 1.3 1999/08/17 16:36:03 dwmw2 Exp $ A general driver for accessing PCMCIA card memory via Bulk Memory Services. @@ -32,8 +32,8 @@ #include #include -#include "mtd.h" -#include "iflash.h" +#include +#include /* Parameters that can be set with 'insmod' */ diff -uNr --exclude CVS mtd-19990810/kernel/doc2000.c mtd-19990817/kernel/doc2000.c --- mtd-19990810/kernel/doc2000.c Mon Aug 9 20:38:05 1999 +++ mtd-19990817/kernel/doc2000.c Tue Aug 17 18:37:25 1999 @@ -2,7 +2,28 @@ /* Linux driver for Disk-On-Chip 2000 */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: doc2000.c,v 1.1 1999/08/09 19:38:05 dwmw2 Exp $ */ +/* $Id: doc2000.c,v 1.5 1999/08/17 17:37:20 dwmw2 Exp $ */ + + +/* DOC_PASSIVE_PROBE: + In order to ensure that the BIOS checksum is correct at boot time, and + hence that the onboard BIOS extension gets executed, the DiskOnChip + goes into reset mode when it is read sequentially: all registers + return 0xff until the chip is woken up again by writing to the + DOCControl register. + + Unfortunately, this means that the probe for the DiskOnChip is unsafe, + because one of the first things it does is write to where it thinks + the DOCControl register should be - which may well be shared memory + for another device. I've had machines which lock up when this is + attempted. Hence the possibility to do a passive probe, which will fail + to detect a chip in reset mode, but is at least guaranteed not to lock + the machine. + + If you have this problem, uncomment the following line: +#define DOC_PASSIVE_PROBE +*/ + #include #include @@ -16,567 +37,593 @@ #include #include -#include "mtd.h" + +#include +#include +#include #ifdef __SMP__ #warning The DiskOnChip driver is not SMP safe. I need to add some locking -dw #endif +//#define PRERELEASE -static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -static ssize_t doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -static int doc_release(struct inode *inode, struct file *file); -static int doc_open(struct inode *inode, struct file *filp); -static int doc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -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, size_t len, size_t *retlen, u_char *buf); - - -#define DoC_M_CDSN_IO 0x800 - -#define DoC_ChipID 0x1000 -#define DoC_DOCStatus 0x1001 -#define DoC_DOCControl 0x1002 -#define DoC_FloorSelect 0x1003 -#define DoC_CSDNControl 0x1004 -#define DoC_CSDNDeviceSelect 0x1005 -#define DoC_ECCConf 0x1006 - -#define DoC_2k_Toggle 0x1007 - -#define DoC_CSDNSlowIO 0x100d -#define DoC_ECCSyndrome0 0x1010 -#define DoC_ECCSyndrome1 0x1011 -#define DoC_ECCSyndrome2 0x1012 -#define DoC_ECCSyndrome3 0x1013 -#define DoC_ECCSyndrome4 0x1014 -#define DoC_ECCSyndrome5 0x1015 -#define DoC_AliasResolution 0x101b -#define DoC_ConfigInput 0x101c -#define DoC_ReadPipeInit 0x101d -#define DoC_WritePipeTerm 0x101e -#define DoC_LastDataRead 0x101f -#define DoC_NOP 0x1020 - -#define DoC_2k_CSDN_IO 0x1800 - -#ifdef __i386__ /* i386 readb/writeb or the address with 0xc0000000 _every_ - time. We don't need that, so we just reference it. */ -#define ReadDOC(adr, reg) *(((volatile unsigned char *)adr) + DoC_##reg) -#define WriteDOC(d, adr, reg) (*(((volatile unsigned char *)adr) + DoC_##reg) = d) -#else -#define ReadDOC(adr, reg) readb(((unsigned long)adr) + DoC_##reg) -#define WriteDOC(d, adr, reg) writeb(d, ((unsigned long)adr) + DoC_##reg) -#endif - -#define DOC_MODE_RESET 0 -#define DOC_MODE_NORMAL 1 -#define DOC_MODE_RESERVED1 2 -#define DOC_MODE_RESERVED2 3 - -#define DOC_MODE_MDWREN 4 -#define DOC_MODE_CLR_ERR 0x80 - -#define DOC_ChipID_Doc2k 0x20 -#define DOC_ChipID_DocMil 0x30 - -#define CSDN_CTRL_FR_B 0x80 -#define CSDN_CTRL_UNKNOWN 0x10 -#define CSDN_CTRL_WP 8 -#define CSDN_CTRL_ALE 4 -#define CSDN_CTRL_CLE 2 -#define CSDN_CTRL_CE 1 - -unsigned long doc_locations[] = { 0xc8000, 0xd0000, 0xd8000, 0 }; - -struct Nand { - char floor, chip; - unsigned long curadr; - unsigned char curmode; - /* Also some erase/write/pipeline info when we get that far */ -}; - -#define MAX_FLOORS 4 -#define MAX_CHIPS 4 - -struct DiskOnChip { - unsigned long physadr; - unsigned long virtadr; - unsigned long totlen; - char ChipID; /* Type of DiskOnChip */ - - unsigned long mfr; /* Flash IDs - only one type of flash per device */ - unsigned long id; - int chipshift; - - int curfloor; - int curchip; - - int numchips; - struct Nand *chips; -}; +unsigned long doc_locations[] = { + 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xe8000, 0xea000, 0xec000, 0xee000, 0 }; static int numdocs = 0; -int doccheck(unsigned long potential, unsigned long physadr); - +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ int _DoC_WaitReady (unsigned long docptr) { - - long c=-1; - - while (!(ReadDOC(docptr, CSDNControl) & CSDN_CTRL_FR_B) && --c) - ; - - if (c == 0) - printk(KERN_WARNING "_DoC_WaitReady timed out."); - - return (c==0); + long c=-1; + + /* Out-of-line routine to wait for chip response */ + while (!(ReadDOC(docptr, CSDNControl) & CSDN_CTRL_FR_B) && --c) + ; + + if (c == 0) + printk(KERN_WARNING "_DoC_WaitReady timed out."); + + return (c==0); } static inline int DoC_WaitReady(unsigned long docptr) { - - /* This is inline, to optimise the case where it's ready instantly */ - - if (!(ReadDOC(docptr, CSDNControl) & CSDN_CTRL_FR_B)) - return _DoC_WaitReady(docptr); /* Call the out-of-line routine and wait */ + /* This is inline, to optimise the common case, where it's ready instantly */ + + if (!(ReadDOC(docptr, CSDNControl) & CSDN_CTRL_FR_B)) + return _DoC_WaitReady(docptr); /* Call the out-of-line routine to wait */ + + return 0; +} - return 0; -} +/* DoC_Command: Send a flash command to the flash chip */ static inline int DoC_Command(unsigned long docptr, unsigned char command) { - WriteDOC( /* Doc2000 driver used 0x1d but I don't know what the - 0x10 bit does */ - CSDN_CTRL_UNKNOWN | CSDN_CTRL_WP | CSDN_CTRL_CLE | CSDN_CTRL_CE, + /* Assert the CLE (Command Latch Enable) line to the flash chip */ + WriteDOC( CSDN_CTRL_FLASH_IO | CSDN_CTRL_WP | CSDN_CTRL_CLE | CSDN_CTRL_CE, docptr, CSDNControl); - if (DoC_WaitReady(docptr)) - return 1; - + /* Send the command */ WriteDOC(command, docptr, 2k_CSDN_IO); - // WriteDOC(0x00, docptr, IPLalias); - - WriteDOC( CSDN_CTRL_UNKNOWN | CSDN_CTRL_WP | CSDN_CTRL_CE, docptr, CSDNControl); + + /* Lower the CLE line */ + WriteDOC( CSDN_CTRL_FLASH_IO | CSDN_CTRL_WP | CSDN_CTRL_CE, docptr, CSDNControl); + /* Wait for the chip to respond */ return DoC_WaitReady(docptr); } +/* DoC_Address: Set the current address for the flash chip */ static inline int DoC_Address (unsigned long docptr, unsigned long ofs) { - WriteDOC( /* Doc2000 driver used 0x1d but I don't know what the - 0x10 bit does */ - CSDN_CTRL_UNKNOWN | CSDN_CTRL_WP | CSDN_CTRL_ALE | CSDN_CTRL_CE, + /* Assert the ALE (Address Latch Enable line to the flash chip */ + WriteDOC( CSDN_CTRL_FLASH_IO | CSDN_CTRL_WP | CSDN_CTRL_ALE | CSDN_CTRL_CE, docptr, CSDNControl); - if (DoC_WaitReady(docptr)) - return 1; - + /* Send the address */ WriteDOC(ofs & 0xff, docptr, 2k_CSDN_IO); - WriteDOC((ofs >> 9) & 0xff, docptr, 2k_CSDN_IO); - WriteDOC((ofs >> 17) & 0xff, docptr, 2k_CSDN_IO); + + /* Lower the ALE line */ + WriteDOC( CSDN_CTRL_FLASH_IO | CSDN_CTRL_ECC_IO | CSDN_CTRL_WP | CSDN_CTRL_CE, docptr, CSDNControl); - WriteDOC( CSDN_CTRL_UNKNOWN | CSDN_CTRL_WP | CSDN_CTRL_CE, docptr, CSDNControl); - + /* Wait for the chip to respond */ return DoC_WaitReady(docptr); } +/* DoC_SelectChip: Select a given flash chip within the current floor */ + static inline int DoC_SelectChip(unsigned long docptr, int chip) { - WriteDOC( chip, docptr, CSDNDeviceSelect); - return DoC_WaitReady(docptr); + /* Select the individual flash chip requested */ + WriteDOC( chip, docptr, CSDNDeviceSelect); + + /* Wait for it to be ready */ + return DoC_WaitReady(docptr); } +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ + static inline int DoC_SelectFloor(unsigned long docptr, int floor) { - WriteDOC( floor, docptr, FloorSelect); - return DoC_WaitReady(docptr); + /* Select the floor (bank) of chips required */ + WriteDOC( floor, docptr, FloorSelect); + + /* Wait for the chip to be ready */ + return DoC_WaitReady(docptr); } +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ + int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) { - int mfr, id, chipshift=0; - char *mfrname=NULL, *idname=NULL; - DoC_SelectFloor(doc->virtadr, floor); - DoC_SelectChip(doc->virtadr, chip); - - if (DoC_Command(doc->virtadr, 0xff)) { - printk("DoC_Command (reset) for %d,%d returned true\n", floor,chip); - return 0; - } - - if(DoC_Command(doc->virtadr, 0x90)) { - printk("DoC_Command (ReadID) for %d,%d returned true\n", floor,chip); - return 0; - } - DoC_Address(doc->virtadr, 0); - - mfr = ReadDOC(doc->virtadr, 2k_CSDN_IO); - id = ReadDOC(doc->virtadr, 2k_CSDN_IO); + int mfr, id, chipshift=0; + char *mfrname=NULL, *idname=NULL; - /* No response - return failure */ - if (mfr == 0xff || mfr == 0) - return 0; - - if (doc->mfr) { - if (doc->mfr == mfr && doc->id == id) - return 1; /* This is another the same the first */ - else - printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n", - floor, chip); - } - - /* This is the first time. Print and store the manufacturer and ID codes. */ - - switch(mfr) { - case 0x98: /* Toshiba */ - mfrname = "Toshiba"; - - switch(id) - { /* How many of these actually get used in DiskOnChip */ - case 0xea: - idname = "TC58V16BDC"; - chipshift = 21; - break; - - case 0x64: - idname = "TC5816BDC"; - chipshift = 21; - break; - - case 0x6b: - idname = "TC5832DC"; - chipshift = 22; - break; - - case 0xe5: - idname = "TC58V32DC"; - chipshift = 22; - break; - - case 0xe6: - idname = "TC58V64DC"; - chipshift = 23; - break; - - case 0x73: - idname = "TH58V128DC"; - chipshift = 24; - break; - - case 0x75: - idname = "TC58256FT/DC"; - chipshift = 25; - break; - } - break; /* End of Toshiba parts */ - - case 0xec: /* Samsung */ - mfrname = "Samsung"; - - switch(id) { - case 0x64: - idname = "KM29N16000"; - chipshift = 21; - - case 0xea: - idname = "KM29W16000"; - chipshift = 21; - break; - - case 0xe3: - idname = "KM29W32000"; - chipshift = 22; - break; - - case 0xe6: - idname = "KM29U64000"; - chipshift = 23; - break; - - case 0x73: - idname = "KM29U128T"; - chipshift = 24; - break; - - case 0x75: - idname = "KM29U256T"; - chipshift = 25; - break; - } - break; /* End of Samsung parts */ - } + /* Page in the required floor/chip */ + DoC_SelectFloor(doc->virtadr, floor); + DoC_SelectChip(doc->virtadr, chip); + + /* Reset the chip */ + if (DoC_Command(doc->virtadr, NAND_CMD_RESET)) { + printk("DoC_Command (reset) for %d,%d returned true\n", floor,chip); + return 0; + } + + /* Read the NAND chip ID: 1. Send ReadID command */ + if(DoC_Command(doc->virtadr, NAND_CMD_READID)) { + printk("DoC_Command (ReadID) for %d,%d returned true\n", floor,chip); + return 0; + } + + /* Read the NAND chip ID: 2. Send address byte zero + * (actually we send three bytes with the DoC_Address() routine, but that's OK. + */ + DoC_Address(doc->virtadr, 0); + + /* Read the manufacturer and device id codes from the device */ + mfr = ReadDOC(doc->virtadr, 2k_CSDN_IO); + id = ReadDOC(doc->virtadr, 2k_CSDN_IO); + + /* No response - return failure */ + if (mfr == 0xff || mfr == 0) + return 0; + + /* 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 + * hardware restriction. */ + if (doc->mfr) { + if (doc->mfr == mfr && doc->id == id) + return 1; /* This is another the same the first */ + else + printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n", + floor, chip); + } + + /* Print (and store if first time) the manufacturer and ID codes. */ - if (idname) { - printk (KERN_INFO "Flash chip found: %2.2X %2.2X (%s %s)\n", - mfr,id,mfrname,idname); - if (!doc->mfr) { - doc->mfr = mfr; - doc->id = id; - doc->chipshift = chipshift; - return 1; - } - return 0; - } - - /* OK. We haven't fully identified the chip. */ - - if (mfrname) - printk(KERN_INFO "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname, - id, mfr); - else - printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr); - - printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n"); - return 0; + switch(mfr) { + case NAND_MFR_TOSHIBA: /* Toshiba */ + mfrname = "Toshiba"; + + switch(id) { + case 0x64: + idname = "TC5816BDC"; + chipshift = 21; + break; + + case 0x6b: + idname = "TC5832DC"; + chipshift = 22; + break; + + case 0x73: + idname = "TH58V128DC"; + chipshift = 24; + break; + + case 0x75: + idname = "TC58256FT/DC"; + chipshift = 25; + break; + + case 0xe5: + idname = "TC58V32DC"; + chipshift = 22; + break; + + case 0xe6: + idname = "TC58V64DC"; + chipshift = 23; + break; + + case 0xea: + idname = "TC58V16BDC"; + chipshift = 21; + break; + } + break; /* End of Toshiba parts */ + + case NAND_MFR_SAMSUNG: /* Samsung */ + mfrname = "Samsung"; + + switch(id) { + case 0x64: + idname = "KM29N16000"; + chipshift = 21; + + case 0x73: + idname = "KM29U128T"; + chipshift = 24; + break; + + case 0x75: + idname = "KM29U256T"; + chipshift = 25; + break; + + case 0xe3: + idname = "KM29W32000"; + chipshift = 22; + break; + + case 0xe6: + idname = "KM29U64000"; + chipshift = 23; + break; + + case 0xea: + idname = "KM29W16000"; + chipshift = 21; + break; + } + break; /* End of Samsung parts */ + } + + /* If we've identified it fully, print the full names */ + if (idname) { +#ifdef PRERELEASE + printk (KERN_INFO "Flash chip found: %2.2X %2.2X (%s %s)\n", + mfr,id,mfrname,idname); +#endif + /* If this is the first chip, store the id codes */ + if (!doc->mfr) { + doc->mfr = mfr; + doc->id = id; + doc->chipshift = chipshift; + return 1; + } + return 0; + } + + /* We haven't fully identified the chip. Print as much as we know. */ + if (mfrname) + printk(KERN_WARNING "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname, + id, mfr); + else + printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr); + + printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n"); + return 0; } +/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ + void DoC_ScanChips(struct DiskOnChip *this) { - int floor, chip; - int numchips[MAX_FLOORS]; - int ret = 1; - - this->numchips = 0; - this->mfr = 0; - this->id = 0; - for (floor = 0 ; floor < MAX_FLOORS ; floor++) { - ret = 1; - numchips[floor]=0; - for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) { - - ret = DoC_IdentChip(this, floor, chip); - if (ret) { - numchips[floor]++; - this->numchips++; - } - } - } - - if (!this->numchips) { - printk("No flash chips recognised.\n"); - return; - } - - this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); - if (!this->chips){ - printk("No memory for allocating chip info structures\n"); - return; - } + int floor, chip; + int numchips[MAX_FLOORS]; + int ret = 1; + + this->numchips = 0; + this->mfr = 0; + this->id = 0; + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0 ; floor < MAX_FLOORS ; floor++) { + ret = 1; + numchips[floor]=0; + for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) { + + ret = DoC_IdentChip(this, floor, chip); + if (ret) { + numchips[floor]++; + this->numchips++; + } + } + } + + /* If there are none at all that we recognise, bail */ + if (!this->numchips) { + printk("No flash chips recognised.\n"); + return; + } + + /* Allocate an array to hold the information for each chip */ + this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); + if (!this->chips){ + printk("No memory for allocating chip info structures\n"); + return; + } + + ret = 0; + + /* 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++) { + this->chips[ret].floor = floor; + this->chips[ret].chip = chip; + this->chips[ret].curadr = 0; + this->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + this->totlen = this->numchips * (1 << this->chipshift); + + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mb\n", this->numchips , + this->totlen >> 20); +} + +/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ + +static inline int doccheck(unsigned long potential, unsigned long physadr) +{ + unsigned long window=potential; + unsigned char tmp, ChipID; +#ifndef DOC_PASSIVE_PROBE + unsigned char tmp2; +#endif - ret = 0; + /* Routine copied from the Linux DOC driver */ + + /* Check for 0x55 0xAA signature at beginning of window */ + if (readb(window) != 0x55 || readb(window+1) != 0xaa) + return 0; + +#ifndef DOC_PASSIVE_PROBE + /* It's not possible to cleanly detect the DiskOnChip - the + * bootup procedure will put the device into reset mode, and + * it's not possible to talk to it without actually writing + * to the DOCControl register. So we store the current contents + * of the DOCControl register's location, in case we later decide + * that it's not a DiskOnChip, and want to put it back how we + * found it. + */ + tmp2 = ReadDOC(window, DOCControl); + + /* Reset the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + + /* Enable the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); +#endif /* !DOC_PASSIVE_PROBE */ + + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_Doc2k: + printk(KERN_NOTICE "DiskOnChip 2000 found at address 0x%lX\n",physadr); + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp) + return ChipID; + break; + + case DOC_ChipID_DocMil: + printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",physadr); + /* We don't actually handle the MDOC yet - it's all hard-coded for the DOC2k. + As M-Systems have now provided me with a sample MDOC, I'll fix this as soon + as I've got DOC2k support completed. + */ + + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp) + return ChipID; + break; + + default: + printk(KERN_WARNING "DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", + ChipID, physadr); + +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register, in case it's not + * actually a DiskOnChip. + */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; + } - for (floor = 0; floor < MAX_FLOORS; floor++) { - for (chip = 0 ; chip < numchips[floor] ; chip++) { - this->chips[ret].floor = floor; - this->chips[ret].chip = chip; - this->chips[ret].curadr = 0; - this->chips[ret].curmode = 0x50; - ret++; - } - } + printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n"); - this->totlen = this->numchips * (1 << this->chipshift); - printk("%d chips found. Total DiskOnChip size: %ld Mb\n", this->numchips , - this->totlen >> 20); - -} +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register: it's not a DiskOnChip */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; +} +/* DoC_Probe: Probe for a DiskOnChip in a given memory window, set up and register + an MTD device for it if neccesary */ void DoC_Probe(unsigned long physadr) { - unsigned long docptr = (unsigned long)ioremap(physadr, 0x2000); - struct DiskOnChip *this; - struct mtd_info *mtd; - int ChipID; - - if (!docptr) return; - - if ((ChipID = doccheck(docptr, physadr))) - { - mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL); - - if (!mtd) { - printk("Cannot allocate memory for data structures. Dropping.\n"); - return; - } - - this = (struct DiskOnChip *)(&mtd[1]); - - memset((char *)mtd,0, sizeof(struct mtd_info)); - - mtd->priv = this; - strncpy(mtd->name, "DiskOnChip 2000", 31); - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; - mtd->size = 0; - mtd->erasesize = 0x2000; - mtd->oobblock = 512; - mtd->oobsize = 16; + unsigned long docptr = (unsigned long)ioremap(physadr, 0x2000); + struct DiskOnChip *this; + struct mtd_info *mtd; + int ChipID; + + if (!docptr) return; + + if ((ChipID = doccheck(docptr, physadr))) { + + mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL); + + if (!mtd) { + printk("Cannot allocate memory for data structures. Dropping.\n"); + iounmap((void *)docptr); + return; + } + + this = (struct DiskOnChip *)(&mtd[1]); + + memset((char *)mtd,0, sizeof(struct mtd_info)); + + mtd->priv = this; + + switch(ChipID) { + case DOC_ChipID_Doc2k: + strcpy(mtd->name, "DiskOnChip 2000"); + break; + + case DOC_ChipID_DocMil: + strcpy(mtd->name, "DiskOnChip Millennium"); + break; + + default: + strcpy(mtd->name, "DiskOnChip"); + } + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->size = 0; + mtd->erasesize = 0x2000; + mtd->oobblock = 512; + mtd->oobsize = 16; #ifdef MODULE - mtd->module = &__this_module; + mtd->module = &__this_module; #endif - mtd->point = NULL; - mtd->unpoint = NULL; - mtd->read = doc_read; - mtd->write = doc_write; - mtd->read_oob = doc_read_oob; - mtd->write_oob = NULL; //doc_writeoob; - mtd->sync = NULL; - - this->physadr = physadr; - this->virtadr = docptr; - this->ChipID = ChipID; - - this->totlen = 0; - this->numchips = 0; - - this->curfloor = -1; - this->curchip = -1; - /* Ident all the chips present. */ - DoC_ScanChips(this); - - if (!this->totlen) - kfree(mtd); - else { - numdocs++; - mtd->size = this->totlen; - add_mtd_device(mtd); - } - } + mtd->point = NULL; + 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 = NULL; //doc_writeoob; + mtd->sync = NULL; + + this->physadr = physadr; + this->virtadr = docptr; + this->ChipID = ChipID; + + this->totlen = 0; + this->numchips = 0; + + this->curfloor = -1; + this->curchip = -1; + + /* Ident all the chips present. */ + DoC_ScanChips(this); + + if (!this->totlen) + kfree(mtd); + else { + numdocs++; + mtd->size = this->totlen; + add_mtd_device(mtd); + return; + } + } + + /* We failed to detect a valid device. Unmap the address range */ + iounmap((void *)docptr); } - - - -int doccheck(unsigned long potential, unsigned long physadr) -{ - unsigned long window=potential; - unsigned char tmp, tmp2, ChipID; - - /* Routine copied from the Linux DOC driver */ - - if (readb(window) != 0x55 || readb(window+1) != 0xaa) - { - //printk ("Start of window not 0x55 0xaa: %2.2X %2.2X\n", - // (unsigned int)readb(window),(unsigned int)readb(window+1)); - return 0; - } - - tmp2 = ReadDOC(window, DOCControl); - - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - window, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - window, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - window, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - window, DOCControl); - - ChipID = ReadDOC(window, ChipID); - - switch (ChipID) { - case DOC_ChipID_Doc2k: - printk(KERN_INFO "Disk-On-Chip 2000 found at 0x%lx\n",physadr); - - tmp = ReadDOC(window, 2k_Toggle) & 4; - if ((ReadDOC(window, 2k_Toggle) & 4) != tmp) - { - return ChipID; - } - break; - - case DOC_ChipID_DocMil: - printk(KERN_INFO "Disk-On-Chip Millennium found at 0x%lx\n",physadr); - /* We don't actually handle the MDOC yet - it's all hard-coded for the DOC. - That'll change when I actually have a MDOC to play with */ - tmp = ReadDOC(window, ECCConf) & 4; - if ((ReadDOC(window, ECCConf) & 4) != tmp) - { - return ChipID; - } - break; - - default: - WriteDOC(tmp2, window, DOCControl); - printk(KERN_WARNING "Disk-On-Chip with unknown ChipID %2.2X found at 0x%lx\n", - ChipID, physadr); - return 0; - } - - printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n"); - WriteDOC(tmp2, window, DOCControl); - return 0; -} static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; - size_t di=0; - int num = 0; //MINOR(filp->f_dentry->d_inode->i_rdev); Must start using - //the right device. - unsigned long docptr; - struct Nand *mychip; - loff_t ofs; - - if (num >= numdocs) - return -ENODEV; - - docptr = this->virtadr; - - if (from > this->totlen) - return -EINVAL; - - if (from + len >= this->totlen) - len = this->totlen - from; - - // Enforce only a single chip. Urgh. How to simply make a 'mask of %d bits'? - if ((from >> this->chipshift) != (from + len) >> this->chipshift) - len = (((from >> this->chipshift) + 1 ) << this->chipshift ) - from; + /* Just a special case of doc_read_ecc */ + return doc_read_ecc(mtd, from, len, retlen, buf, NULL); +} - mychip = &this->chips[from >> (this->chipshift)]; +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 DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + int di=0; /* Yes, DI is a hangover from when I was disassembling the binary driver */ + unsigned long docptr; + struct Nand *mychip; - if (this->curfloor != mychip->floor) { - DoC_SelectFloor(docptr, mychip->floor); - DoC_SelectChip(docptr, mychip->chip); - } - else if (this->curchip != mychip->chip) { - DoC_SelectChip(docptr, mychip->chip); - } + docptr = this->virtadr; - this->curfloor = mychip->floor; - this->curchip = mychip->chip; + /* Don't allow read past end of device */ + if (from > this->totlen) + return -EINVAL; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ( (from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; - /* Yes we don't guarantee to set the address. I'll fix it later */ + /* Find the chip which is to be used and select it */ + mychip = &this->chips[from >> (this->chipshift)]; + + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } + else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + - for (ofs = from; ofs < from + len ; ofs++) - { - if (!(ofs & 0xff)) { - /* Some optimisation required - cache the command and address so we - don't have to load them _every_ time. Also select the correct chip, - for multi-chip DOCs. The latter will happen when I have one. */ - DoC_Command(docptr, (ofs >> 8) & 1); - // DoC_Command(docptr, 0x50); - DoC_Address(docptr, ofs); - } - - //(void)readb(docptr + 0x100d); - buf[di++] = ReadDOC(docptr, 2k_CSDN_IO); - } + if (eccbuf) { + /* Prime the ECC engine */ + WriteDOC ( DOC_ECC_RESET, docptr, ECCConf); + WriteDOC ( DOC_ECC_EN, docptr, ECCConf); + } + + DoC_Command(docptr, (from >> 8) & 1); + DoC_Address(docptr, from); + + for (di=0; di < len ; di++) { + buf[di] = ReadDOC(docptr, 2k_CSDN_IO); + } + + /* Let the caller know we completed it */ + *retlen = len; + + if (eccbuf) { + /* Read the ECC data through the DiskOnChip ECC logic */ + for (di=0; di<6; di++) { + eccbuf[di] = ReadDOC(docptr, 2k_CSDN_IO); + } + + /* Flush the pipeline */ + (void) ReadDOC(docptr, 2k_ECCStatus); + (void) ReadDOC(docptr, 2k_ECCStatus); + + /* Check the ECC Status */ + if (ReadDOC(docptr, 2k_ECCStatus) & 0x80) { + /* There was an ECC error */ + printk("DiskOnChip ECC Error: Read at %lx\n", (long)len); + + /* FIXME: Implement ECC error correction, don't just whinge */ + + /* 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 */ + return -EIO; + } + + /* Reset the ECC engine */ + WriteDOC(DOC_ECC_RESV, docptr , ECCConf); + + } + + return 0; +} - *retlen = len; - return 0; +static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +{ + return doc_write_ecc(mtd, to, len, retlen, buf, NULL); } -static ssize_t doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eecbuf) { /* Yeah, right */ @@ -584,16 +631,6 @@ } -static int doc_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static int doc_open(struct inode *inode, struct file *filp) -{ - return 0; -} - static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf) { @@ -642,43 +679,44 @@ int init_module(void) { - int i; - - - printk("M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n"); - printk("$Id: doc2000.c,v 1.1 1999/08/09 19:38:05 dwmw2 Exp $\n"); - - for (i=0; doc_locations[i]; i++) { - DoC_Probe(doc_locations[i]); - } - - if (numdocs) - return 0; - - printk("No Disk-On-Chip hardware found\n"); - return -ENXIO; - + int i; + + + printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n"); +#ifdef PRERELEASE + printk(KERN_INFO "$Id: doc2000.c,v 1.5 1999/08/17 17:37:20 dwmw2 Exp $\n"); +#endif + + for (i=0; doc_locations[i]; i++) { + DoC_Probe(doc_locations[i]); + } + + if (numdocs) + return 0; + + printk("No DiskOnChip hardware found\n"); + return -ENXIO; + } - void cleanup_module(void) { - int i; - struct mtd_info mtd; - - for (i=0; i < MAX_MTD_DEVICES; i++) { - struct mtd_info *mtd = get_mtd_device(i); - - if (mtd && mtd->module == &__this_module) { - struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; - - del_mtd_device(mtd); - - iounmap((void *)this->virtadr); - kfree(this->chips); - kfree(mtd); - } - } + int i; + struct mtd_info *mtd; + + for (i=0; i < MAX_MTD_DEVICES; i++) { + mtd = get_mtd_device(i); + + if (mtd && mtd->module == &__this_module) { + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + + del_mtd_device(mtd); + + iounmap((void *)this->virtadr); + kfree(this->chips); + kfree(mtd); + } + } } diff -uNr --exclude CVS mtd-19990810/kernel/ftl.c mtd-19990817/kernel/ftl.c --- mtd-19990810/kernel/ftl.c Mon Aug 9 19:04:57 1999 +++ mtd-19990817/kernel/ftl.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: ftl.c,v 1.2 1999/08/09 18:04:57 dwmw2 Exp $ + $Id: ftl.c,v 1.3 1999/08/17 16:36:03 dwmw2 Exp $ A Flash Translation Layer memory card driver @@ -32,8 +32,8 @@ #include #include -#include "ftl.h" -#include "mtd.h" +#include +#include #define FTL_MAJOR 44 diff -uNr --exclude CVS mtd-19990810/kernel/mapped.c mtd-19990817/kernel/mapped.c --- mtd-19990810/kernel/mapped.c Tue Aug 10 15:11:59 1999 +++ mtd-19990817/kernel/mapped.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: mapped.c,v 1.3 1999/08/10 14:00:04 dwmw2 Exp $ +// $Id: mapped.c,v 1.4 1999/08/17 16:36:03 dwmw2 Exp $ /* ###################################################################### Flash MTD Routines @@ -13,7 +13,7 @@ ##################################################################### */ /*}}}*/ -#include "mapped.h" +#include #include #include diff -uNr --exclude CVS mtd-19990810/kernel/mixmem.c mtd-19990817/kernel/mixmem.c --- mtd-19990810/kernel/mixmem.c Wed Jul 7 03:06:33 1999 +++ mtd-19990817/kernel/mixmem.c Tue Aug 17 17:36:21 1999 @@ -15,7 +15,7 @@ #include #include -#include "mapped.h" +#include #define MIXCOM_ID_OFFSET 0xc10 #define MIXCOM_PAGE_OFFSET 0xc11 diff -uNr --exclude CVS mtd-19990810/kernel/mtd.c mtd-19990817/kernel/mtd.c --- mtd-19990810/kernel/mtd.c Tue Aug 10 14:32:32 1999 +++ mtd-19990817/kernel/mtd.c Tue Aug 17 18:37:25 1999 @@ -1,15 +1,12 @@ /*====================================================================== - $Id: mtd.c,v 1.2 1999/08/09 18:04:57 dwmw2 Exp $ + $Id: mtd.c,v 1.6 1999/08/17 17:16:36 dwmw2 Exp $ - A general driver for accessing PCMCIA card memory via Bulk - Memory Services. + A general driver for accessing Memory Technology Devices - This driver provides the equivalent of /dev/mem for a PCMCIA - card's attribute and common memory. It includes character - and block devices. - - Written by David Hinds, dhinds@allegro.stanford.edu + This driver provides the equivalent of /dev/mem for a MTD + device. It includes a character device - a block device is + implemented by mtdblock.c ======================================================================*/ @@ -29,7 +26,11 @@ #include #include -#include "mtd.h" +#ifdef CONFIG_PROC_FS +#include +#endif + +#include /* Major device #'s for memory device */ @@ -38,7 +39,6 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig); - static int mtd_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg); static ssize_t mtd_read(struct file *file, char *buf, size_t count, @@ -118,7 +118,7 @@ /* OK. We're going to open it now. */ if (mtd->module) - __MOD_INC_USE_COUNT(mtd->module); + __MOD_INC_USE_COUNT(mtd->module); return 0; } /* mtd_open */ @@ -321,7 +321,9 @@ mtd_table[i]=mtd; +#ifdef DEBUG printk(KERN_NOTICE "mtd: Giving out device %d to %s\n",i, mtd->name); +#endif while (not) { (*(not->func))(mtd,i); @@ -394,6 +396,51 @@ /*====================================================================*/ +/* /proc/mtd support */ + +#ifdef CONFIG_PROC_FS + +struct proc_dir_entry *proc_mtd; + +static inline int mtd_proc_info (char *buf, int i) +{ + struct mtd_info *this = get_mtd_device(i); + + if (!this) + return 0; + + return sprintf(buf, "mtd%d: %8.8lx \"%s\"\n", i, this->size, + this->name); +} + +static int mtd_read_proc ( char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0, l, i; + off_t begin = 0; + + for (i=0; i< MAX_MTD_DEVICES; i++) { + + l = mtd_proc_info(page + len, i); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} +#endif + +/*====================================================================*/ int init_module(void) { @@ -408,10 +455,23 @@ MTD_CHAR_MAJOR); return EAGAIN; } +#ifdef CONFIG_PROC_FS + if ((proc_mtd = create_proc_entry( "mtd", 0, 0 ))) + proc_mtd->read_proc = mtd_read_proc; +#endif return 0; } void cleanup_module(void) { unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); +#ifdef CONFIG_PROC_FS + if (proc_mtd) + remove_proc_entry( "mtd", 0); +#endif } + + + + + diff -uNr --exclude CVS mtd-19990810/kernel/mtdblock.c mtd-19990817/kernel/mtdblock.c --- mtd-19990810/kernel/mtdblock.c Mon Aug 9 19:04:57 1999 +++ mtd-19990817/kernel/mtdblock.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: mtdblock.c,v 1.1 1999/08/09 18:04:57 dwmw2 Exp $ +// $Id: mtdblock.c,v 1.2 1999/08/17 16:36:03 dwmw2 Exp $ /* ###################################################################### Memory Technology Devices Manager @@ -14,11 +14,12 @@ ##################################################################### */ /*}}}*/ #include -#include "mtd.h" #include #include #include #include + +#include #define MAJOR_NR MTD_BLOCK_MAJOR #define DEVICE_NAME "mtdblock" diff -uNr --exclude CVS mtd-19990810/kernel/nftl.c mtd-19990817/kernel/nftl.c --- mtd-19990810/kernel/nftl.c Tue Aug 10 16:52:24 1999 +++ mtd-19990817/kernel/nftl.c Tue Aug 17 18:37:25 1999 @@ -1,8 +1,10 @@ -/* Linux driver for Disk-On-Chip 2000 */ +/* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: nftl.c,v 1.4 1999/08/10 15:52:24 dwmw2 Exp $ */ +/* $Id: nftl.c,v 1.7 1999/08/17 17:16:36 dwmw2 Exp $ */ + +#define PRERELEASE #include #include @@ -15,8 +17,8 @@ #include #include -#include "mtd.h" -#include "nftl.h" +#include +#include /* NFTL block device stuff */ #define MAJOR_NR NFTL_MAJOR @@ -26,165 +28,149 @@ #include -#define MAX_NFTLS 16 - -/* Given a pointer to a NFTL Media Header, initialise all the structures and - register the block device */ -struct NFTLrecord { - struct mtd_info *mtd; - u16 MediaUnit, SpareMediaUnit; - u32 EraseSize; - struct NFTLMediaHeader MediaHdr; - u16 numvunits; - u32 long nr_sects; - int head,sect,cyl; -#define numEUNs MediaHdr.NumEraseUnits - u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ - u16 *VirtualUnitTable; /* [numEUNs]: VirtualUnitNumber for each */ - u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ -} *NFTLs[MAX_NFTLS]; +struct NFTLrecord *NFTLs[MAX_NFTLS]; int numnftls = 0; void NFTL_setup(struct mtd_info *mtd, unsigned long ofs, - struct NFTLMediaHeader *hdr) + struct NFTLMediaHeader *hdr) { - int i; - struct NFTLrecord *thisNFTL; - - for (i=0; i < numnftls; i++) - if (NFTLs[i] && NFTLs[i]->mtd == mtd && - NFTLs[i]->MediaHdr.FirstPhysicalEUN == hdr->FirstPhysicalEUN) { - /* This is a Spare Media Header for an NFTL we've already found */ - // printk("Spare Media Header for NFTL %d found at %lx\n",i, ofs); - NFTLs[i]->SpareMediaUnit = ofs / mtd->erasesize; - return; - } - - - - /* OK, it's a new one. Set up all the data structures. */ - - printk("Found new NFTL nftl%c at offset %lx\n",numnftls + 'a', ofs); - - if (hdr->UnitSizeFactor != 0xff) { - printk("Sorry, we don't support UnitSizeFactor of != 1 yet\n"); - return; - } - - thisNFTL = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - if (!thisNFTL) { - printk(KERN_WARNING "Out of memory for NFTL data structures\n"); - return; - } - - thisNFTL->EraseSize = mtd->erasesize; - memcpy(&thisNFTL->MediaHdr, hdr, sizeof(*hdr)); - thisNFTL->mtd = mtd; - thisNFTL->MediaUnit = ofs / mtd->erasesize; - thisNFTL->SpareMediaUnit = 0xffff; - thisNFTL->numvunits = le32_to_cpu(thisNFTL->MediaHdr.FormattedSize) / 8192; - thisNFTL->nr_sects = thisNFTL->numvunits * (thisNFTL->EraseSize / 512); - - - thisNFTL->EUNtable = kmalloc( 2 * thisNFTL->numvunits, - GFP_KERNEL); - if (!thisNFTL->EUNtable) { - printk("ENOMEM\n"); - kfree(thisNFTL); - return; - } - memset(thisNFTL->EUNtable, 0xff, 2 * thisNFTL->numvunits); - - thisNFTL->VirtualUnitTable = kmalloc( 2 * thisNFTL->numEUNs , GFP_KERNEL); - if (!thisNFTL->VirtualUnitTable) { - printk("ENOMEM\n"); - kfree(thisNFTL->EUNtable); - kfree(thisNFTL); - return; - } - memset(thisNFTL->VirtualUnitTable, 0xff, 2 * thisNFTL->numEUNs); - - thisNFTL->ReplUnitTable = kmalloc( 2 * thisNFTL->numEUNs , GFP_KERNEL); - if (!thisNFTL->ReplUnitTable) { - printk("ENOMEM\n"); - kfree(thisNFTL->VirtualUnitTable); - kfree(thisNFTL->EUNtable); - kfree(thisNFTL); - return; - } - memset(thisNFTL->ReplUnitTable, 0xff, 2 * thisNFTL->numEUNs); - - /* Ought to check the media header for bad blocks */ - - - /* Scan each physical Erase Unit for validity and to find the - Virtual Erase Unit Chain to which it belongs */ - - for (i=le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN); - i < thisNFTL->numEUNs + - le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN); i++) { - - union doc_uci uci; - unsigned long ofs; - size_t retlen; - ofs = i * thisNFTL->EraseSize; - - MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 512 + 8, 8, &retlen, (char *)&uci); - - if (uci.b.EraseMark != cpu_to_le16(0x3c69) || - uci.b.EraseMark1 != cpu_to_le16(0x3c69)) { - printk("EUN %d: EraseMark not 0x3c69 (0x%4.4x 0x%4.4x instead)\n", - i, le16_to_cpu(uci.b.EraseMark), le16_to_cpu(uci.b.EraseMark1)); - continue; - } - - MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 8, 8, &retlen, (u_char *)&uci); - - if (uci.a.VirtUnitNum != uci.a.SpareVirtUnitNum) - printk("EUN %d: VirtualUnitNumber (%x) != SpareVirtualUnitNumber (%x)\n", - i, le16_to_cpu(uci.a.VirtUnitNum), - le16_to_cpu(uci.a.SpareVirtUnitNum)); - - if (uci.a.ReplUnitNum != uci.a.SpareReplUnitNum) - printk("EUN %d: ReplacementUnitNumber (%x) != SpareReplacementUnitNumber (%x)\n", - i, le16_to_cpu(uci.a.ReplUnitNum), - le16_to_cpu(uci.a.SpareReplUnitNum)); - - /* We don't actually _do_ anything about the above, just whinge */ - - thisNFTL->VirtualUnitTable[i] = le16_to_cpu(uci.a.VirtUnitNum); - thisNFTL->ReplUnitTable[i] = le16_to_cpu(uci.a.ReplUnitNum); - - - /* if (!(VUN & 0x8000) && VUN < (arraybounds)).. optimises to: */ - if (le16_to_cpu(uci.a.VirtUnitNum) < thisNFTL->numvunits) - thisNFTL->EUNtable[le16_to_cpu(uci.a.VirtUnitNum) & 0x7fff] = i; - - } - NFTLs[numnftls++] = thisNFTL; - - if (thisNFTL->mtd->module) - __MOD_INC_USE_COUNT(thisNFTL->mtd->module); - -#if 0 - for (i=0; i < 10/* thisNFTL->numvunits*/; i++) { - u16 curEUN = thisNFTL->EUNtable[i]; - int sillycount=100; - - printk("Virtual Unit #%d: ",i); - if (!curEUN || curEUN == 0xffff) { - printk("Not present\n"); - continue; - } - printk("%d", curEUN); - - while ((curEUN = thisNFTL->ReplUnitTable[curEUN]) != 0xffff && --sillycount) { - printk(", %d", curEUN & 0xffff); - - } - printk("\n"); - } + int i; + struct NFTLrecord *thisNFTL; + + for (i=0; i < numnftls; i++) + if (NFTLs[i] && NFTLs[i]->mtd == mtd && + NFTLs[i]->MediaHdr.FirstPhysicalEUN == hdr->FirstPhysicalEUN) { + /* This is a Spare Media Header for an NFTL we've already found */ + // printk("Spare Media Header for NFTL %d found at %lx\n",i, ofs); + NFTLs[i]->SpareMediaUnit = ofs / mtd->erasesize; + return; + } + + + + /* OK, it's a new one. Set up all the data structures. */ + + printk("Found new NFTL nftl%c at offset %lx\n",numnftls + 'a', ofs); + + if (hdr->UnitSizeFactor != 0xff) { + printk("Sorry, we don't support UnitSizeFactor of != 1 yet\n"); + return; + } + + thisNFTL = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); + if (!thisNFTL) { + printk(KERN_WARNING "Out of memory for NFTL data structures\n"); + return; + } + + thisNFTL->EraseSize = mtd->erasesize; + memcpy(&thisNFTL->MediaHdr, hdr, sizeof(*hdr)); + thisNFTL->mtd = mtd; + thisNFTL->MediaUnit = ofs / mtd->erasesize; + thisNFTL->SpareMediaUnit = 0xffff; + thisNFTL->numvunits = le32_to_cpu(thisNFTL->MediaHdr.FormattedSize) / 8192; + thisNFTL->nr_sects = thisNFTL->numvunits * (thisNFTL->EraseSize / 512); + + + thisNFTL->EUNtable = kmalloc( 2 * thisNFTL->numvunits, + GFP_KERNEL); + if (!thisNFTL->EUNtable) { + printk("ENOMEM\n"); + kfree(thisNFTL); + return; + } + memset(thisNFTL->EUNtable, 0xff, 2 * thisNFTL->numvunits); + + thisNFTL->VirtualUnitTable = kmalloc( 2 * thisNFTL->numEUNs , GFP_KERNEL); + if (!thisNFTL->VirtualUnitTable) { + printk("ENOMEM\n"); + kfree(thisNFTL->EUNtable); + kfree(thisNFTL); + return; + } + memset(thisNFTL->VirtualUnitTable, 0xff, 2 * thisNFTL->numEUNs); + + thisNFTL->ReplUnitTable = kmalloc( 2 * thisNFTL->numEUNs , GFP_KERNEL); + if (!thisNFTL->ReplUnitTable) { + printk("ENOMEM\n"); + kfree(thisNFTL->VirtualUnitTable); + kfree(thisNFTL->EUNtable); + kfree(thisNFTL); + return; + } + memset(thisNFTL->ReplUnitTable, 0xff, 2 * thisNFTL->numEUNs); + + /* Ought to check the media header for bad blocks */ + + + /* Scan each physical Erase Unit for validity and to find the + Virtual Erase Unit Chain to which it belongs */ + + for (i=le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN); + i < thisNFTL->numEUNs + + le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN); i++) { + + union nftl_uci uci; + unsigned long ofs; + size_t retlen; + ofs = i * thisNFTL->EraseSize; + + MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 512 + 8, 8, &retlen, (char *)&uci); + + if (uci.b.EraseMark != cpu_to_le16(0x3c69) || + uci.b.EraseMark1 != cpu_to_le16(0x3c69)) { + printk("EUN %d: EraseMark not 0x3c69 (0x%4.4x 0x%4.4x instead)\n", + i, le16_to_cpu(uci.b.EraseMark), le16_to_cpu(uci.b.EraseMark1)); + continue; + } + + MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 8, 8, &retlen, (u_char *)&uci); + + if (uci.a.VirtUnitNum != uci.a.SpareVirtUnitNum) + printk("EUN %d: VirtualUnitNumber (%x) != SpareVirtualUnitNumber (%x)\n", + i, le16_to_cpu(uci.a.VirtUnitNum), + le16_to_cpu(uci.a.SpareVirtUnitNum)); + + if (uci.a.ReplUnitNum != uci.a.SpareReplUnitNum) + printk("EUN %d: ReplacementUnitNumber (%x) != SpareReplacementUnitNumber (%x)\n", + i, le16_to_cpu(uci.a.ReplUnitNum), + le16_to_cpu(uci.a.SpareReplUnitNum)); + + /* We don't actually _do_ anything about the above, just whinge */ + + thisNFTL->VirtualUnitTable[i] = le16_to_cpu(uci.a.VirtUnitNum); + thisNFTL->ReplUnitTable[i] = le16_to_cpu(uci.a.ReplUnitNum); + + + /* if (!(VUN & 0x8000) && VUN < (arraybounds)).. optimises to: */ + if (le16_to_cpu(uci.a.VirtUnitNum) < thisNFTL->numvunits) + thisNFTL->EUNtable[le16_to_cpu(uci.a.VirtUnitNum) & 0x7fff] = i; + + } + NFTLs[numnftls++] = thisNFTL; + + if (thisNFTL->mtd->module) + __MOD_INC_USE_COUNT(thisNFTL->mtd->module); + +#ifdef PSYCHO_DEBUG + for (i=0; i < 10/* thisNFTL->numvunits*/; i++) { + u16 curEUN = thisNFTL->EUNtable[i]; + int sillycount=100; + + printk("Virtual Unit #%d: ",i); + if (!curEUN || curEUN == 0xffff) { + printk("Not present\n"); + continue; + } + printk("%d", curEUN); + + while ((curEUN = thisNFTL->ReplUnitTable[curEUN]) != 0xffff && --sillycount) { + printk(", %d", curEUN & 0xffff); + + } + printk("\n"); + } #endif } @@ -193,34 +179,34 @@ void NFTL_init(void) { - int i; - struct mtd_info *mtd; - unsigned long ofs; - struct NFTLMediaHeader hdr; - - for (i=0; i < MAX_MTD_DEVICES; i++) { - mtd = get_mtd_device(i); - - if (!mtd) - continue; - - if (!mtd->read_oob) /* If this MTD doesn't have out-of-band data, - then there's no point continuing */ - continue; - - for (ofs = 0; ofs < mtd->size ; ofs += mtd->erasesize) { - size_t retlen; - MTD_READ(mtd, ofs, sizeof(hdr), &retlen, (u_char *)&hdr); - - if (retlen < sizeof(hdr)) - continue; - - if (!strncmp(hdr.DataOrgID, "ANAND", 6)) { - - NFTL_setup(mtd, ofs, &hdr); + int i; + struct mtd_info *mtd; + unsigned long ofs; + struct NFTLMediaHeader hdr; + + for (i=0; i < MAX_MTD_DEVICES; i++) { + mtd = get_mtd_device(i); + + if (!mtd) + continue; + + if (!mtd->read_oob) /* If this MTD doesn't have out-of-band data, + then there's no point continuing */ + continue; + + for (ofs = 0; ofs < mtd->size ; ofs += mtd->erasesize) { + size_t retlen; + MTD_READ(mtd, ofs, sizeof(hdr), &retlen, (u_char *)&hdr); + + if (retlen < sizeof(hdr)) + continue; + + if (!strncmp(hdr.DataOrgID, "ANAND", 6)) { + + NFTL_setup(mtd, ofs, &hdr); + } + } } - } - } } @@ -229,10 +215,10 @@ static int nftl_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - printk("NFTL ioctl called\n"); - return -EINVAL; + printk("NFTL ioctl called\n"); + return -EINVAL; } struct hd_struct part_table[256] = {{0,0},}; @@ -241,102 +227,111 @@ void nftl_request(void) { - unsigned int dev, block, nsect, blockofs; - struct NFTLrecord *thisNFTL; - char *buffer; -repeat: - cli(); - INIT_REQUEST; - dev = MINOR(CURRENT->rq_dev); - block = CURRENT->sector; - nsect = CURRENT->nr_sectors; - buffer = CURRENT->buffer; - - if (dev >= numnftls * 16) { - printk("fl: bad minor number: device=%s\n", - kdevname(CURRENT->rq_dev)); - end_request(0); /* fail */ - goto repeat; - } - - thisNFTL = NFTLs[dev / 16]; - - if (block + nsect >= part_table[dev].nr_sects) { - printk("nftl%c%d: bad access: block=%d, count=%d\n", - (MINOR(CURRENT->rq_dev)>>6)+'a', dev & 0xf, block, nsect); - end_request(0); /* fail */ - goto repeat; - } - - block += part_table[dev].start_sect; - - if (CURRENT->cmd == READ) { - - - for ( ; nsect > 0; nsect-- , block++, buffer+= 512) { - /* Read a single sector to CURRENT->buffer + (512 * i) */ - u16 lastgoodEUN = 0xffff; - u16 thisEUN = thisNFTL->EUNtable[block / (thisNFTL->EraseSize / 512)]; - blockofs = (block * 512) & (thisNFTL->EraseSize -1); - - if (thisEUN == 0xffff) thisEUN = 0; - - while(thisEUN && (thisEUN & 0x7fff) != 0x7fff) { - struct doc_bci bci; - size_t retlen; - - MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + blockofs,8, &retlen, (char *)&bci); - - switch(bci.Status) { - case cpu_to_le16(BLOCK_FREE): - thisEUN = 0; - break; - case cpu_to_le16(BLOCK_USED): - lastgoodEUN = thisEUN; - break; - default: - printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, bci.Status); - } - if (thisEUN) - thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff; - } - if (lastgoodEUN == 0xffff) { - memset(buffer, 0, 512); - } else { - loff_t ptr = (lastgoodEUN * thisNFTL->EraseSize) + blockofs; - size_t retlen; - MTD_READ(thisNFTL->mtd, ptr, 512, &retlen, buffer); - } - } - - end_request(1); - goto repeat; - } - else if (CURRENT->cmd == WRITE) { - printk("Ouch, gotta write request\n"); - end_request(0); /* fail */ - goto repeat; - } - else { - - end_request(0); /* fail */ - goto repeat; - } + unsigned int dev, block, nsect, blockofs; + struct NFTLrecord *thisNFTL; + char *buffer; + repeat: + cli(); + INIT_REQUEST; + dev = MINOR(CURRENT->rq_dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + buffer = CURRENT->buffer; + + if (dev >= numnftls * 16) { + printk("fl: bad minor number: device=%s\n", + kdevname(CURRENT->rq_dev)); + end_request(0); /* fail */ + goto repeat; + } + + thisNFTL = NFTLs[dev / 16]; + + if (block + nsect >= part_table[dev].nr_sects) { + printk("nftl%c%d: bad access: block=%d, count=%d\n", + (MINOR(CURRENT->rq_dev)>>6)+'a', dev & 0xf, block, nsect); + end_request(0); /* fail */ + goto repeat; + } + + block += part_table[dev].start_sect; + + if (CURRENT->cmd == READ) { + + + for ( ; nsect > 0; nsect-- , block++, buffer+= 512) { + /* Read a single sector to CURRENT->buffer + (512 * i) */ + u16 lastgoodEUN = 0xffff; + u16 thisEUN = thisNFTL->EUNtable[block / (thisNFTL->EraseSize / 512)]; + blockofs = (block * 512) & (thisNFTL->EraseSize -1); + + if (thisEUN == 0xffff) thisEUN = 0; + + while(thisEUN && (thisEUN & 0x7fff) != 0x7fff) { + struct nftl_bci bci; + size_t retlen; + + MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + blockofs,8, &retlen, (char *)&bci); + + switch(bci.Status) { + case cpu_to_le16(BLOCK_FREE): + thisEUN = 0; + break; + case cpu_to_le16(BLOCK_USED): + lastgoodEUN = thisEUN; + break; + default: + printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, bci.Status); + } + if (thisEUN) + thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff; + } + if (lastgoodEUN == 0xffff) { + memset(buffer, 0, 512); + } else { + loff_t ptr = (lastgoodEUN * thisNFTL->EraseSize) + blockofs; + size_t retlen; + u_char eccbuf[6]; + + thisNFTL->mtd->read_ecc(thisNFTL->mtd, ptr, 512, &retlen, buffer, eccbuf); + } + } + + end_request(1); + goto repeat; + } + else if (CURRENT->cmd == WRITE) { + printk("Ouch, gotta write request\n"); + end_request(0); /* fail */ + goto repeat; + } + else { + + end_request(0); /* fail */ + goto repeat; + } } static int nftl_open(struct inode *ip, struct file *fp) { - if (fp->f_mode & FMODE_WRITE) - return -EROFS; - - MOD_INC_USE_COUNT; - return 0; + if (fp->f_mode & FMODE_WRITE) + return -EROFS; + + MOD_INC_USE_COUNT; + return 0; } -static int nftl_release(struct inode *ip, struct file *fp) +static int nftl_release(struct inode *inode, struct file *fp) { - MOD_DEC_USE_COUNT; - return 0; + struct super_block *sb = get_super(inode->i_rdev); + + fsync_dev(inode->i_rdev); + if (sb) invalidate_inodes(sb); + invalidate_buffers(inode->i_rdev); + // mtd->sync() + + MOD_DEC_USE_COUNT; + return 0; } static struct gendisk nftl_gendisk = { @@ -380,38 +375,41 @@ int init_module(void) { - int i; - + int i; + + + printk(KERN_NOTICE "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n"); +#ifdef PRERELEASE + printk(KERN_INFO"$Id: nftl.c,v 1.7 1999/08/17 17:16:36 dwmw2 Exp $\n"); +#endif - printk("M-Systems NAND Flash Translation Layer driver.\n (C) 1999 Machine Vision Holdings, Inc.\n"); - printk("$Id: nftl.c,v 1.4 1999/08/10 15:52:24 dwmw2 Exp $\n"); + NFTL_init(); - NFTL_init(); - if (numnftls) { - - for (i=0; i < numnftls ; i++) { - part_table[i * 16].nr_sects = NFTLs[i]->nr_sects; - } - - if (register_blkdev(NFTL_MAJOR, "nftl", &nftl_fops)){ - printk("unable to register NFTL block device\n"); - } else { - blk_dev[NFTL_MAJOR].request_fn = DEVICE_REQUEST; - for (i=0; i < 256 ; i++) - nftl_blocksizes[i] = 1024; - blksize_size[NFTL_MAJOR] = nftl_blocksizes; - nftl_gendisk.next = gendisk_head; - gendisk_head = &nftl_gendisk; - } - - for (i=0; i < numnftls ; i++) { - resetup_one_dev(&nftl_gendisk, i); - } - - return 0; - } - printk("No NFTL partitions found\n"); - return -ENODEV; + if (numnftls) { + + for (i=0; i < numnftls ; i++) { + part_table[i * 16].nr_sects = NFTLs[i]->nr_sects; + } + + if (register_blkdev(NFTL_MAJOR, "nftl", &nftl_fops)){ + printk("unable to register NFTL block device\n"); + } else { + blk_dev[NFTL_MAJOR].request_fn = DEVICE_REQUEST; + for (i=0; i < 256 ; i++) + nftl_blocksizes[i] = 1024; + blksize_size[NFTL_MAJOR] = nftl_blocksizes; + nftl_gendisk.next = gendisk_head; + gendisk_head = &nftl_gendisk; + } + + for (i=0; i < numnftls ; i++) { + resetup_one_dev(&nftl_gendisk, i); + } + + return 0; + } + printk("No NFTL partitions found\n"); + return -ENODEV; } diff -uNr --exclude CVS mtd-19990810/kernel/octagon-5066.c mtd-19990817/kernel/octagon-5066.c --- mtd-19990810/kernel/octagon-5066.c Mon Aug 9 19:32:14 1999 +++ mtd-19990817/kernel/octagon-5066.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: octagon-5066.c,v 1.2 1999/08/09 18:32:14 dwmw2 Exp $ +// $Id: octagon-5066.c,v 1.3 1999/08/17 16:36:03 dwmw2 Exp $ /* ###################################################################### Octagon 5066 MTD Driver. @@ -33,7 +33,7 @@ #include #include -#include "mapped.h" +#include /*}}} */ #define WINDOW_START 0xe8000 diff -uNr --exclude CVS mtd-19990810/kernel/slram.c mtd-19990817/kernel/slram.c --- mtd-19990810/kernel/slram.c Mon Aug 9 19:04:57 1999 +++ mtd-19990817/kernel/slram.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: slram.c,v 1.2 1999/08/09 18:04:57 dwmw2 Exp $ + $Id: slram.c,v 1.3 1999/08/17 16:36:03 dwmw2 Exp $ A general driver for accessing PCMCIA card memory via Bulk Memory Services. @@ -31,7 +31,7 @@ #include #include -#include "mtd.h" +#include struct mypriv { u_char *start; diff -uNr --exclude CVS mtd-19990810/kernel/vmax301.c mtd-19990817/kernel/vmax301.c --- mtd-19990810/kernel/vmax301.c Mon Aug 9 19:32:14 1999 +++ mtd-19990817/kernel/vmax301.c Tue Aug 17 17:36:21 1999 @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: vmax301.c,v 1.2 1999/08/09 18:32:14 dwmw2 Exp $ +// $Id: vmax301.c,v 1.3 1999/08/17 16:36:03 dwmw2 Exp $ /* ###################################################################### Tempustech VMAX SBC301 MTD Driver. @@ -24,7 +24,7 @@ #include #include -#include "mapped.h" +#include /*}}} */ #define WINDOW_START 0xd8000 diff -uNr --exclude CVS mtd-19990810/util/erase.c mtd-19990817/util/erase.c --- mtd-19990810/util/erase.c Tue Jul 27 17:52:18 1999 +++ mtd-19990817/util/erase.c Tue Aug 17 17:37:30 1999 @@ -6,7 +6,7 @@ #include #include -#include "devices/mtd.h" +#include int main(int argc,char *argv[]) { diff -uNr --exclude CVS mtd-19990810/util/ftl_format.c mtd-19990817/util/ftl_format.c --- mtd-19990810/util/ftl_format.c Mon Aug 9 19:04:57 1999 +++ mtd-19990817/util/ftl_format.c Tue Aug 17 17:37:12 1999 @@ -21,8 +21,8 @@ #include #include #include -#include "mtd.h" -#include "ftl.h" +#include +#include /*====================================================================*/ diff -uNr --exclude CVS mtd-19990810/util/mkfs.ffs2.c mtd-19990817/util/mkfs.ffs2.c --- mtd-19990810/util/mkfs.ffs2.c Mon Aug 9 15:26:22 1999 +++ mtd-19990817/util/mkfs.ffs2.c Tue Aug 17 17:37:58 1999 @@ -22,8 +22,8 @@ #include #include -#include "devices/mtd.h" -#include "ffs2/ffs2_fs.h" +#include