Added docs and code for use with real MTD as well as emulation, and patched
authorwookey <wookey>
Wed, 22 May 2002 12:38:56 +0000 (12:38 +0000)
committerwookey <wookey>
Wed, 22 May 2002 12:38:56 +0000 (12:38 +0000)
MTD interface

Documentation/yaffs_on_mtd.html [new file with mode: 0644]
mtdemul/Makefile [new file with mode: 0644]
mtdemul/nandemul.c [new file with mode: 0644]
mtdemul/nandemul.h [new file with mode: 0644]
patches/mtdpart.c [new file with mode: 0644]
yaffs_fs.c
yaffsdev.proj

diff --git a/Documentation/yaffs_on_mtd.html b/Documentation/yaffs_on_mtd.html
new file mode 100644 (file)
index 0000000..b994fba
--- /dev/null
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+       <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
+       <TITLE></TITLE>
+       <META NAME="GENERATOR" CONTENT="StarOffice/5.2 (Linux)">
+       <META NAME="CREATED" CONTENT="20020517;23103700">
+       <META NAME="CHANGEDBY" CONTENT=" ">
+       <META NAME="CHANGED" CONTENT="20020518;7200400">
+</HEAD>
+<BODY>
+<H2 ALIGN=CENTER>Running up YAFFS using the MTD interface</H2>
+<P>Here are  the steps required to get YAFFS going with the
+NANDemulation MTD that I have written.</P>
+<P><FONT COLOR="#800000"><FONT SIZE=4 STYLE="font-size: 16pt"><I><U><B>Warning:
+This is experimental stuff that plugs into the kernel. It has only
+been lightly tested. Don't play with this on a box you are not
+prepared to reboot.</B></U></I></FONT></FONT></P>
+<P>There are a few things you need to do. This document assumes that
+you're working from the 2.4.18 kernel code base.</P>
+<H3>Preparing the kernel</H3>
+<P>First off, you need to patch the mtdcore services.</P>
+<OL>
+       <LI><P>Replace the devices/mtd/mtdpart.c file with the one enclosed.
+       This patches the problem where special NAND functions are not being
+       copied through the partition handler. The changes are marked with a
+       comment containing my initials <B><FONT FACE="Courier, monospace">cdhm</FONT></B>.</P>
+       <LI><P>Build the kernel including the following configurations to
+       support mtd.</P>
+</OL>
+<P STYLE="margin-left: 2cm">CONFIG_MTD=y Turn on MTD support</P>
+<P STYLE="margin-left: 2cm">CONFIG_MTD_PARTITIONS=y Turn on partition
+support</P>
+<P STYLE="margin-left: 2cm">CONFIG_MTD_CHAR=y Need char drivers to
+access the data from user space.</P>
+<P STYLE="margin-left: 2cm">CONFIG_MTD_BLOCK=y Block driver interface
+used only to find the device for mounting</P>
+<P STYLE="margin-left: 2cm">may as well also set:</P>
+<P STYLE="margin-left: 2cm">CONFIG_MTD_DEBUG=y</P>
+<OL>
+       <P>CONFIG_MTD_DEBUG_VERBOSE=3</P>
+       <H3 ALIGN=LEFT></H3>
+</OL>
+<H3 ALIGN=LEFT>Setting up yaffs</H3>
+<OL>
+       <LI><P>Run the mtd utility MAKEDEV to make the /dev/mtdxxx entries.</P>
+       <LI><P>Load up the NANDemul MTD by typing<BR><FONT FACE="Courier, monospace">#/sbin/insmod
+       mtdemul/nandemul.o</FONT><BR>You should now be able to see the
+       device in the mtd list by typing  <BR>#<FONT FACE="Courier, monospace">cat
+       /proc/mtd</FONT><BR>If all is well, the device will now be
+       accessible as <FONT FACE="Courier, monospace">/dev/mtd0</FONT> and
+       <FONT FACE="Courier, monospace">/dev/mtdblock0</FONT> (or whatever).</P>
+       <LI><P>Now load up the yaffs filesystem module by
+       typing<BR><FONT FACE="Courier, monospace">#/sbin/insmod
+       mtdemul/yaffs.o<BR><FONT FACE="Times, serif">You should now be able
+       to see the yaffs file systems by typing</FONT><BR>#cat
+       /proc/filesystems</FONT></P>
+       <LI><P><FONT FACE="Times, serif">Now create a mount point:<BR><FONT FACE="Courier, monospace">#mkdir
+       /mnt/y</FONT></FONT></P>
+       <LI><P><FONT FACE="Times, serif">Mount the file system:<BR><FONT FACE="Courier, monospace">#mount
+       -t yaffs /dev/mtdblock0 /mnt/y</FONT></FONT></P>
+       <LI><P><FONT FACE="Times, serif">Well if that all worked you have
+       YAFFS running on the /mnt/y mount point using the NANDemul mtd.</FONT></P>
+</OL>
+<H3>What about real NAND?</H3>
+<P><FONT FACE="Times, serif">You might want to try getting going on a
+real NAND device.</FONT></P>
+<P><FONT FACE="Times, serif">I have not yet done this, but the
+NANDemul tests out the mtd interface so in theory it should work on
+real NAND too.</FONT></P>
+<P><FONT FACE="Times, serif">Note though that since YAFFS applies the
+ECC, it does not expect the NAND device to be applying ECC.  You
+probably want to configure the NAND driver with ECC disabled.</FONT></P>
+<P><BR><BR>
+</P>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/mtdemul/Makefile b/mtdemul/Makefile
new file mode 100644 (file)
index 0000000..1817228
--- /dev/null
@@ -0,0 +1,29 @@
+#Makefile for NANDemul MTD
+#
+# NB this is not yet suitable for putting into the kernel tree.
+# YAFFS: Yet another FFS. A NAND-flash specific file system. 
+#
+# Copyright (C) 2002 Aleph One Ltd.
+#   for Toby Churchill Ltd and Brightstar Engineering
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+## Change or override  KERNELDIR to your kernel
+## comment out USE_xxxx if you don't want these features.
+
+KERNELDIR = /usr/src/kernel-headers-2.4.18
+
+CFLAGS = -D__KERNEL__ -DMODULE   -I$(KERNELDIR)/include -O2 -Wall
+
+
+OBJS = nandemul.o
+
+
+
+$(OBJS): %.o: %.c
+       gcc -c $(CFLAGS) $< -o $@
+
diff --git a/mtdemul/nandemul.c b/mtdemul/nandemul.c
new file mode 100644 (file)
index 0000000..12fe39d
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system. 
+ *
+ * Copyright (C) 2002 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/uaccess.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+
+#define T(x) printk x
+#define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
+#define FREE(x)     kfree(x)
+
+#define DEFAULT_SIZE_IN_MB 16
+
+#define NAND_SHIFT 9
+
+
+static struct mtd_info nandemul_mtd;
+
+typedef struct
+{
+       __u8 data[528]; // Data + spare
+       int count[3];   // The programming count for each area of
+                       // the page (0..255,256..511,512..527
+       int empty;      // is this empty?
+} nandemul_Page;
+
+typedef struct
+{
+       nandemul_Page page[32]; // The pages in the block
+       __u8 damaged;           // Is the block damaged?
+       
+} nandemul_Block;
+
+
+
+typedef struct
+{
+       nandemul_Block **block;
+       int nBlocks;
+} nandemul_Device;
+
+nandemul_Device device;
+
+int sizeInMB = DEFAULT_SIZE_IN_MB;
+
+int nandemul_CalcNBlocks(void)
+{
+        switch(sizeInMB)
+        {
+               case 8:
+               case 16:
+               case 32:
+               case 64:
+               case 128:
+               case 256:
+               case 512:
+                       break;
+               default:
+                       sizeInMB = DEFAULT_SIZE_IN_MB;
+        }
+       return sizeInMB * 64;
+}
+
+
+static void nandemul_ReallyEraseBlock(int blockNumber)
+{
+       int i;
+       
+       nandemul_Block *theBlock = device.block[blockNumber];
+       
+       for(i = 0; i < 32; i++)
+       {
+               memset(theBlock->page[i].data,0xff,528);
+               theBlock->page[i].count[0] = 0;
+               theBlock->page[i].count[1] = 0;
+               theBlock->page[i].count[2] = 0;
+               theBlock->page[i].empty = 1;
+       }
+
+}
+
+static int nandemul_DoErase(int blockNumber)
+{
+       if(blockNumber < 0 || nandemul_CalcNBlocks())
+       {
+               T(("Attempt to erase non-existant block %d\n",blockNumber));
+       }
+       else if(device.block[blockNumber]->damaged)
+       {
+               T(("Attempt to erase damaged block %d\n",blockNumber));
+       }
+       else
+       {
+               nandemul_ReallyEraseBlock(blockNumber);
+       }
+
+       return 1;
+       
+}
+
+
+int nandemul_Initialise(void)
+{
+       int i;
+       int fail = 0;
+       int nBlocks = nandemul_CalcNBlocks();
+       int nAllocated = 0;
+
+       device.block = ALLOCATE (sizeof(nandemul_Block *) * nBlocks);
+
+       if(!device.block) return 0;
+
+       for(i=0; i <nBlocks; i++)
+       {
+               device.block[i] = NULL;
+       }
+       
+       for(i=0; i <nBlocks && !fail; i++)
+       {
+               if((device.block[i] = ALLOCATE(sizeof(nandemul_Block))) == 0)
+               {
+                       fail = 1;
+               }
+               else
+               {
+                       nandemul_ReallyEraseBlock(i);
+                       device.block[i]->damaged = 0;
+                       nAllocated++;
+               }
+       }
+       
+       if(fail)
+       {
+               for(i = 0; i < nAllocated; i++)
+               {
+                       FREE(device.block[i]);
+               }
+               FREE(device.block);
+
+               T(("Allocation failed, could only allocate %dMB of %dMB requested.\n",
+                  nAllocated/64,sizeInMB));
+               return 0;
+       }
+
+       device.nBlocks = nBlocks;
+       return 1;
+}
+
+int nandemul_DeInitialise(void)
+{
+       int i;
+       for(i = 0; i < device.nBlocks; i++)
+       {
+               FREE(device.block[i]);
+               device.block[i] = NULL;
+       }
+       
+       FREE(device.block);
+       device.block = NULL;
+       return 1;
+}
+
+int nandemul_GetNumberOfBlocks(__u32 *nBlocks)
+{
+       *nBlocks = device.nBlocks;
+       
+       return 1;
+}
+
+int nandemul_Reset(void)
+{
+       // Do nothing
+       return 1;
+}
+
+int nandemul_Read(__u8 *buffer, __u32 pageAddress,__u32 pageOffset, __u32 nBytes)
+{
+       unsigned blockN, pageN;
+       
+       blockN = pageAddress/32;
+       pageN =  pageAddress % 32;
+       
+       // TODO: Do tests for valid blockN, pageN, pageOffset
+
+       memcpy(buffer,&device.block[blockN]->page[pageN].data[pageOffset],nBytes);
+       
+       return 1;
+               
+}
+
+int nandemul_Program(const __u8 *buffer, __u32 pageAddress,__u32 pageOffset, __u32 nBytes)
+{
+       unsigned blockN, pageN, pageO;
+       
+       int p0, p1, p2;
+       int i;
+       
+       blockN = pageAddress/32;
+       pageN =  pageAddress % 32;
+       p0 = 0;
+       p1 = 0;
+       p2 = 0;
+       
+       // TODO: Do tests for valid blockN, pageN, pageOffset
+
+
+    for(i = 0,pageO = pageOffset; i < nBytes; i++, pageO++)
+    {
+       device.block[blockN]->page[pageN].data[pageO] &= buffer[i];
+       
+               if(pageO < 256) p0 = 1;
+               else if(pageO <512) p1 = 1;
+               else p2 = 1;
+    }
+       
+       device.block[blockN]->page[pageN].empty = 0;
+       device.block[blockN]->page[pageN].count[0] += p0;
+       device.block[blockN]->page[pageN].count[1] += p1;
+       device.block[blockN]->page[pageN].count[2] += p2;
+       
+       if(device.block[blockN]->page[pageN].count[0] > 1)
+       {
+               T(("block %d page %d first half programmed %d times\n",
+                   blockN,pageN,device.block[blockN]->page[pageN].count[0]));
+       }
+       if(device.block[blockN]->page[pageN].count[1] > 1)
+       {
+               T(("block %d page %d second half programmed %d times\n",
+                   blockN,pageN,device.block[blockN]->page[pageN].count[1]));
+       }
+       if(device.block[blockN]->page[pageN].count[2] > 3)
+       {
+               T(("block %d page %d spare programmed %d times\n",
+                   blockN,pageN,device.block[blockN]->page[pageN].count[2]));
+       }
+
+       return 1;
+       
+}
+
+int nandemul_CauseBitErrors( __u32 pageAddress, __u32 pageOffset, __u8 xorPattern)
+{
+       unsigned blockN, pageN;
+
+       
+       blockN = pageAddress/32;
+       pageN =  pageAddress % 32;
+
+       
+       // TODO: Do tests for valid blockN, pageN, pageOffset
+
+    device.block[blockN]->page[pageN].data[pageOffset] ^= xorPattern;
+       
+
+       return 1;
+       
+}
+
+
+int nandemul_BlockErase(__u32 pageAddress)
+{
+       unsigned blockN;
+       
+       blockN = pageAddress/32;
+
+       // TODO: Do tests for valid blockN
+       // TODO: Test that the block has not failed
+
+       return nandemul_DoErase(blockN);
+       
+}
+
+int nandemul_FailBlock(__u32 pageAddress)
+{
+       unsigned blockN;
+       
+       blockN = pageAddress/32;
+
+       // TODO: Do tests for valid blockN
+       // TODO: Test that the block has not failed
+       
+       nandemul_DoErase(blockN);
+       return 1;
+}
+
+int nandemul_ReadId(__u8 *vendorId, __u8 *deviceId)
+{
+       *vendorId = 0xEC;
+       *deviceId = 0x75;
+       
+       return 1;
+}
+
+int nandemul_CopyPage(__u32 fromPageAddress, __u32 toPageAddress)
+{
+       __u8 copyBuffer[528];
+       
+       // TODO: Check the bitplane issue.
+       nandemul_Read(copyBuffer, fromPageAddress,0,528);
+       nandemul_Program(copyBuffer, toPageAddress,0,528);
+       
+       return 1;
+}
+
+int nandemul_ReadStatus(__u8 *status)
+{
+               *status = 0;
+               return 1;
+}
+
+
+#ifdef CONFIG_MTD_NAND_ECC
+#include <linux/mtd/nand_ecc.h>
+#endif
+
+/*
+ * NAND low-level MTD interface functions
+ */
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf);
+static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                               size_t *retlen, u_char *buf, u_char *ecc_code);
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+                               size_t *retlen, u_char *buf);
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf);
+static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t *retlen, const u_char *buf,
+                               u_char *ecc_code);
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t *retlen, const u_char *buf);
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
+                               unsigned long count, loff_t to, size_t *retlen);
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
+static void nand_sync (struct mtd_info *mtd);
+
+
+
+/*
+ * NAND read
+ */
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
+{
+       return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
+}
+
+/*
+ * NAND read with ECC
+ */
+static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                               size_t *retlen, u_char *buf, u_char *ecc_code)
+{
+       int     start, page;
+       int n = len;
+       int nToCopy;
+
+
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+
+       /* Initialize return value */
+       *retlen = 0;
+
+       while(n > 0)
+       {
+
+               /* First we calculate the starting page */
+               page = from >> NAND_SHIFT;
+
+               /* Get raw starting column */
+
+               start = from & (mtd->oobblock-1);
+
+               // OK now check for the curveball where the start and end are in
+               // the same page
+               if((start + n) < mtd->oobblock)
+               {
+                       nToCopy = n;
+               }
+               else
+               {
+                       nToCopy =  mtd->oobblock - start;
+               }
+
+               nandemul_Read(buf, page, start, nToCopy);
+
+               n -= nToCopy;
+               from += nToCopy;
+               buf += nToCopy;
+               *retlen += nToCopy;
+
+       }
+
+
+       return 0;
+}
+
+/*
+ * NAND read out-of-band
+ */
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+                               size_t *retlen, u_char *buf)
+{
+       int col, page;
+
+       DEBUG (MTD_DEBUG_LEVEL3,
+               "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from,
+               (int) len);
+
+       /* Shift to get page */
+       page = ((int) from) >> NAND_SHIFT;
+
+       /* Mask to get column */
+       col = from & 0x0f;
+
+       /* Initialize return length value */
+       *retlen = 0;
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0,
+                       "nand_read_oob: Attempt read beyond end of device\n");
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+       nandemul_Read(buf,page,512 + col,len);
+
+       /* Return happy */
+       *retlen = len;
+       return 0;
+}
+
+/*
+ * NAND write
+ */
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
+}
+
+/*
+ * NAND write with ECC
+ */
+static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t *retlen, const u_char *buf,
+                               u_char *ecc_code)
+{
+
+       int     start, page;
+       int n = len;
+       int nToCopy;
+
+
+
+       /* Do not allow reads past end of device */
+       if ((to + len) > mtd->size) {
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+
+       /* Initialize return value */
+       *retlen = 0;
+
+       while(n > 0)
+       {
+
+               /* First we calculate the starting page */
+               page = to >> NAND_SHIFT;
+
+               /* Get raw starting column */
+
+               start = to & (mtd->oobblock - 1);
+
+               // OK now check for the curveball where the start and end are in
+               // the same page
+               if((start + n) < mtd->oobblock)
+               {
+                       nToCopy = n;
+               }
+               else
+               {
+                       nToCopy =  mtd->oobblock - start;
+               }
+
+               nandemul_Program(buf, page, start, nToCopy);
+
+               n -= nToCopy;
+               to += nToCopy;
+               buf += nToCopy;
+               *retlen += nToCopy;
+
+       }
+
+
+       return 0;
+}
+
+/*
+ * NAND write out-of-band
+ */
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t *retlen, const u_char *buf)
+{
+       int col, page;
+
+
+       DEBUG (MTD_DEBUG_LEVEL3,
+               "nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
+               (int) len);
+
+       /* Shift to get page */
+       page = ((int) to) >> NAND_SHIFT;
+
+       /* Mask to get column */
+       col = to & 0x0f;
+
+       /* Initialize return length value */
+       *retlen = 0;
+
+       /* Do not allow reads past end of device */
+       if ((to + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0,
+                       "nand_read_oob: Attempt read beyond end of device\n");
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+       nandemul_Program(buf,page,512 + col,len);
+
+       /* Return happy */
+       *retlen = len;
+       return 0;
+
+}
+
+/*
+ * NAND write with iovec
+ */
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
+                               unsigned long count, loff_t to, size_t *retlen)
+{
+       return -EINVAL;
+}
+
+/*
+ * NAND erase a block
+ */
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+       int i, nBlocks,block;
+
+       DEBUG (MTD_DEBUG_LEVEL3,
+               "nand_erase: start = 0x%08x, len = %i\n",
+               (unsigned int) instr->addr, (unsigned int) instr->len);
+
+       /* Start address must align on block boundary */
+       if (instr->addr & (mtd->erasesize - 1)) {
+               DEBUG (MTD_DEBUG_LEVEL0,
+                       "nand_erase: Unaligned address\n");
+               return -EINVAL;
+       }
+
+       /* Length must align on block boundary */
+       if (instr->len & (mtd->erasesize - 1)) {
+               DEBUG (MTD_DEBUG_LEVEL0,
+                       "nand_erase: Length not block aligned\n");
+               return -EINVAL;
+       }
+
+       /* Do not allow erase past end of device */
+       if ((instr->len + instr->addr) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0,
+                       "nand_erase: Erase past end of device\n");
+               return -EINVAL;
+       }
+
+       nBlocks = instr->len >> (NAND_SHIFT + 5);
+       block = instr->addr >> (NAND_SHIFT + 5);
+
+       for(i = 0; i < nBlocks; i++)
+       {
+               nandemul_DoErase(block);
+               block++;
+       }
+
+
+
+       return 0;
+
+
+}
+
+/*
+ * NAND sync
+ */
+static void nand_sync (struct mtd_info *mtd)
+{
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+
+}
+
+/*
+ * Scan for the NAND device
+ */
+int nand_scan (struct mtd_info *mtd)
+{
+       mtd->oobblock = 512;
+       mtd->oobsize = 16;
+       mtd->erasesize = 512 * 32;
+       mtd->size = sizeInMB * 1024*1024;
+
+
+
+       /* Fill in remaining MTD driver data */
+       mtd->type = MTD_NANDFLASH;
+       mtd->flags = MTD_CAP_NANDFLASH;
+       mtd->module = THIS_MODULE;
+       mtd->ecctype = MTD_ECC_NONE;
+       mtd->erase = nand_erase;
+       mtd->point = NULL;
+       mtd->unpoint = NULL;
+       mtd->read = nand_read;
+       mtd->write = nand_write;
+       mtd->read_ecc = nand_read_ecc;
+       mtd->write_ecc = nand_write_ecc;
+       mtd->read_oob = nand_read_oob;
+       mtd->write_oob = nand_write_oob;
+       mtd->readv = NULL;
+       mtd->writev = nand_writev;
+       mtd->sync = nand_sync;
+       mtd->lock = NULL;
+       mtd->unlock = NULL;
+       mtd->suspend = NULL;
+       mtd->resume = NULL;
+
+       /* Return happy */
+       return 0;
+}
+
+#if 0
+#ifdef MODULE
+MODULE_PARM(sizeInMB, "i");
+
+__setup("sizeInMB=",sizeInMB);
+#endif
+#endif
+
+/*
+ * Define partitions for flash devices
+ */
+
+static struct mtd_partition nandemul_partition[] =
+{
+       { name: "NANDemul partition 1",
+         offset:  0,
+         size: 0 },
+};
+
+static int nPartitions = sizeof(nandemul_partition)/sizeof(nandemul_partition[0]);
+
+/*
+ * Main initialization routine
+ */
+int __init nandemul_init (void)
+{
+
+       // Do the nand init
+
+       nand_scan(&nandemul_mtd);
+
+       nandemul_Initialise();
+
+       // Build the partition table
+
+       nandemul_partition[0].size = sizeInMB * 1024 * 1024;
+
+       // Register the partition
+       add_mtd_partitions(&nandemul_mtd,nandemul_partition,nPartitions);
+
+       return 0;
+
+}
+
+module_init(nandemul_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit nandemul_cleanup (void)
+{
+
+       nandemul_DeInitialise();
+
+       /* Unregister partitions */
+       del_mtd_partitions(&nandemul_mtd);
+
+       /* Unregister the device */
+       del_mtd_device (&nandemul_mtd);
+
+}
+module_exit(nandemul_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>");
+MODULE_DESCRIPTION("NAND emulated in RAM");
+
+
+
+
diff --git a/mtdemul/nandemul.h b/mtdemul/nandemul.h
new file mode 100644 (file)
index 0000000..1a89590
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __NANDEMUL_H__
+#define __NANDEMUL_H__
+
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+
+int nandemul_Initialise(void);
+int nandemul_DeInitialise(void);
+
+int nandemul_GetNumberOfBlocks(__u32 *nBlocks);
+int nandemul_Reset(void);
+int nandemul_Read(__u8 *buffer, __u32 pageAddress, __u32 pageOffset, __u32 nBytes);
+int nandemul_Program(__u8 *buffer, __u32 pageAddress, __u32 pageOffset, __u32 nBytes);
+
+
+
+int nandemul_BlockErase(__u32 address);
+
+int nandemul_ReadId(__u8 *vendorId, __u8 *deviceId);
+
+int nandemul_CopyPage(__u32 fromAddress, __u32 toAddress);
+
+int nandemul_ReadStatus(__u8 *status);
+
+int nandemul_FailBlock(__u32 pageAddress);
+int nandemul_CauseBitErrors( __u32 pageAddress, __u32 pageOffset, __u8 xorPattern);
+
+#endif
+
+
+
diff --git a/patches/mtdpart.c b/patches/mtdpart.c
new file mode 100644 (file)
index 0000000..e28fe39
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Simple MTD partitioning layer
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdpart.c,v 1.1 2002-05-22 12:38:56 wookey Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+
+/* Our partition linked list */
+static LIST_HEAD(mtd_partitions);
+
+/* Our partition node structure */
+struct mtd_part {
+       struct mtd_info mtd;
+       struct mtd_info *master;
+       u_int32_t offset;
+       int index;
+       struct list_head list;
+};
+
+/*
+ * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+ * the pointer to that structure with this macro.
+ */
+#define PART(x)  ((struct mtd_part *)(x))
+
+       
+/* 
+ * MTD methods which simply translate the effective address and pass through
+ * to the _real_ device.
+ */
+
+static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
+                       size_t *retlen, u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (from >= mtd->size)
+               len = 0;
+       else if (from + len > mtd->size)
+               len = mtd->size - from;
+       return part->master->read (part->master, from + part->offset, 
+                                       len, retlen, buf);
+}
+
+static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (to >= mtd->size)
+               len = 0;
+       else if (to + len > mtd->size)
+               len = mtd->size - to;
+       return part->master->write (part->master, to + part->offset, 
+                                       len, retlen, buf);
+}
+
+static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
+                        unsigned long count, loff_t to, size_t *retlen)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       return part->master->writev (part->master, vecs, count,
+                                       to + part->offset, retlen);
+}
+
+static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
+                        unsigned long count, loff_t from, size_t *retlen)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->readv (part->master, vecs, count,
+                                       from + part->offset, retlen);
+}
+
+static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (instr->addr >= mtd->size)
+               return -EINVAL;
+       instr->addr += part->offset;
+       return part->master->erase(part->master, instr);
+}
+
+static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       if ((len + ofs) > mtd->size) 
+               return -EINVAL;
+       return part->master->lock(part->master, ofs + part->offset, len);
+}
+
+static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       if ((len + ofs) > mtd->size) 
+               return -EINVAL;
+       return part->master->unlock(part->master, ofs + part->offset, len);
+}
+
+static void part_sync(struct mtd_info *mtd)
+{
+       struct mtd_part *part = PART(mtd);
+       part->master->sync(part->master);
+}
+
+static int part_suspend(struct mtd_info *mtd)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->suspend(part->master);
+}
+
+static void part_resume(struct mtd_info *mtd)
+{
+       struct mtd_part *part = PART(mtd);
+       part->master->resume(part->master);
+}
+
+/* 
+ * This function unregisters and destroy all slave MTD objects which are 
+ * attached to the given master MTD object.
+ */
+
+int del_mtd_partitions(struct mtd_info *master)
+{
+       struct list_head *node;
+       struct mtd_part *slave;
+
+       for (node = mtd_partitions.next;
+            node != &mtd_partitions;
+            node = node->next) {
+               slave = list_entry(node, struct mtd_part, list);
+               if (slave->master == master) {
+                       struct list_head *prev = node->prev;
+                       __list_del(prev, node->next);
+                       del_mtd_device(&slave->mtd);
+                       kfree(slave);
+                       node = prev;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * This function, given a master MTD object and a partition table, creates
+ * and registers slave MTD objects which are bound to the master according to
+ * the partition definitions.
+ * (Q: should we register the master MTD object as well?)
+ */
+
+int add_mtd_partitions(struct mtd_info *master, 
+                      struct mtd_partition *parts,
+                      int nbparts)
+{
+       struct mtd_part *slave;
+       u_int32_t cur_offset = 0;
+       int i;
+
+       printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
+
+       for (i = 0; i < nbparts; i++) {
+
+               /* allocate the partition structure */
+               slave = kmalloc (sizeof(*slave), GFP_KERNEL);
+               if (!slave) {
+                       printk ("memory allocation error while creating partitions for \"%s\"\n",
+                               master->name);
+                       del_mtd_partitions(master);
+                       return -ENOMEM;
+               }
+               memset(slave, 0, sizeof(*slave));
+               list_add(&slave->list, &mtd_partitions);
+
+               /* set up the MTD object for this partition */
+               slave->mtd.type = master->type;
+               slave->mtd.flags = master->flags & ~parts[i].mask_flags;
+               slave->mtd.size = parts[i].size;
+               slave->mtd.oobblock = master->oobblock;
+               slave->mtd.oobsize = master->oobsize;
+               slave->mtd.ecctype = master->ecctype;
+               slave->mtd.eccsize = master->eccsize;
+
+               slave->mtd.name = parts[i].name;
+               slave->mtd.bank_size = master->bank_size;
+
+               slave->mtd.module = master->module;
+
+               slave->mtd.read = part_read;
+               slave->mtd.write = part_write;
+               if (master->sync)
+                       slave->mtd.sync = part_sync;
+               if (!i && master->suspend && master->resume) {
+                               slave->mtd.suspend = part_suspend;
+                               slave->mtd.resume = part_resume;
+               }
+
+               if (master->writev)
+                       slave->mtd.writev = part_writev;
+               if (master->readv)
+                       slave->mtd.readv = part_readv;
+               if (master->lock)
+                       slave->mtd.lock = part_lock;
+               if (master->unlock)
+                       slave->mtd.unlock = part_unlock;
+/* cdhm: fix add oob functions to partitions */
+               if (master->read_oob)
+                       slave->mtd.read_oob = master->read_oob;
+               if (master->write_oob)
+                       slave->mtd.write_oob = master->write_oob;
+/* cdhm: end of fix */
+               slave->mtd.erase = part_erase;
+               slave->master = master;
+               slave->offset = parts[i].offset;
+               slave->index = i;
+
+               if (slave->offset == MTDPART_OFS_APPEND)
+                       slave->offset = cur_offset;
+               if (slave->mtd.size == MTDPART_SIZ_FULL)
+                       slave->mtd.size = master->size - slave->offset;
+               cur_offset = slave->offset + slave->mtd.size;
+       
+               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 
+                       slave->offset + slave->mtd.size, slave->mtd.name);
+
+               /* let's do some sanity checks */
+               if (slave->offset >= master->size) {
+                               /* let's register it anyway to preserve ordering */
+                       slave->offset = 0;
+                       slave->mtd.size = 0;
+                       printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
+                               parts[i].name);
+               }
+               if (slave->offset + slave->mtd.size > master->size) {
+                       slave->mtd.size = master->size - slave->offset;
+                       printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
+                               parts[i].name, master->name, slave->mtd.size);
+               }
+               if (master->numeraseregions>1) {
+                       /* Deal with variable erase size stuff */
+                       int i;
+                       struct mtd_erase_region_info *regions = master->eraseregions;
+                       
+                       /* Find the first erase regions which is part of this partition. */
+                       for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
+                               ;
+
+                       for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
+                               if (slave->mtd.erasesize < regions[i].erasesize) {
+                                       slave->mtd.erasesize = regions[i].erasesize;
+                               }
+                       }
+               } else {
+                       /* Single erase size */
+                       slave->mtd.erasesize = master->erasesize;
+               }
+
+               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+                   (slave->offset % slave->mtd.erasesize)) {
+                       /* Doesn't start on a boundary of major erase size */
+                       /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
+                       slave->mtd.flags &= ~MTD_WRITEABLE;
+                       printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+                               parts[i].name);
+               }
+               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+                   (slave->mtd.size % slave->mtd.erasesize)) {
+                       slave->mtd.flags &= ~MTD_WRITEABLE;
+                       printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+                               parts[i].name);
+               }
+
+               /* register our partition */
+               add_mtd_device(&slave->mtd);
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL(add_mtd_partitions);
+EXPORT_SYMBOL(del_mtd_partitions);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");
+
index a0ada3922443b31ed328d9f1295207692efd7248..de113037ddb33ee1bd3ac6beae32a3ce0ee38e3c 100644 (file)
@@ -14,7 +14,7 @@
  * This is the file system front-end to YAFFS that hooks it up to
  * the VFS.
  *
- * Special notes:
+ * Special notes: 
  * >> sb->u.generic_sbp points to the yaffs_Device associated with this superblock
  * >> inode->u.generic_ip points to the associated yaffs_Object.
  */
@@ -40,7 +40,7 @@
 #include "yaffs_guts.h"
 
 #ifdef YAFFS_RAM_ENABLED
-#include "yaffs_nandemul.h"
+#include "yaffs_nandemul.h" 
 // 2 MB of RAM for emulation
 #define YAFFS_RAM_EMULATION_SIZE  0x200000
 #endif // YAFFS_RAM_ENABLED
@@ -115,7 +115,7 @@ static struct inode_operations yaffs_dir_inode_operations = {
        create:         yaffs_create,
        lookup:         yaffs_lookup,
        link:           yaffs_link,
-       unlink:         yaffs_unlink,
+       unlink:         yaffs_unlink,   
        symlink:        yaffs_symlink,
        mkdir:          yaffs_mkdir,
        rmdir:          yaffs_unlink,
@@ -143,18 +143,18 @@ static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry)
 {
        yaffs_Object *obj;
        struct inode *inode;
-
-
+       
+       
        T((KERN_DEBUG"yaffs_lookup for %d:%s\n",yaffs_InodeToObject(dir)->objectId,dentry->d_name.name));
-
+       
        obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),dentry->d_name.name);
-
+       
        if(obj)
        {
                T((KERN_DEBUG"yaffs_lookup found %d\n",obj->objectId));
-
+               
                inode = yaffs_get_inode(dir->i_sb, obj->st_mode,0,obj);
-
+               
                if(inode)
                {
                        T((KERN_DEBUG"yaffs_loookup looks good\n"));
@@ -167,10 +167,10 @@ static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry)
        else
        {
                T((KERN_DEBUG"yaffs_lookup not found\n"));
-
+               
        }
        return NULL;
-
+       
 }
 
 // For now put inode is just for debugging
@@ -212,7 +212,7 @@ static int yaffs_commit_write(struct file *file, struct page *page, unsigned off
 
 static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
 {
-       if (inode && obj)
+       if (inode && obj) 
        {
                inode->i_ino = obj->objectId;
                inode->i_mode = obj->st_mode;
@@ -227,16 +227,16 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
                inode->i_ctime = obj->st_ctime;
                inode->i_size = yaffs_GetObjectFileLength(obj);
                inode->i_nlink = yaffs_GetObjectLinkCount(obj);
-
+               
                T((KERN_DEBUG"yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
                                inode->i_mode, inode->i_uid, inode->i_gid, (int)inode->i_size, atomic_read(&inode->i_count)));
-
-               switch (obj->st_mode & S_IFMT)
+               
+               switch (obj->st_mode & S_IFMT) 
                {
                        default:
                        //      init_special_inode(inode, mode, dev);
                                break;
-                       case S_IFREG:   // file
+                       case S_IFREG:   // file         
                                inode->i_op = &yaffs_file_inode_operations;
                                inode->i_fop = &yaffs_file_operations;
                                break;
@@ -248,10 +248,10 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
                                inode->i_op = &page_symlink_inode_operations;
                                break;
                }
-
-
+               
+               
                inode->u.generic_ip = obj;
-
+               
        }
        else
        {
@@ -263,7 +263,7 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj)
 {
        struct inode * inode;
-
+       
        T((KERN_DEBUG"yaffs_get_inode for object %d\n",obj->objectId));
 
        inode = iget(sb,obj->objectId);
@@ -279,13 +279,13 @@ static ssize_t yaffs_file_read(struct file *f, char *buf, size_t n, loff_t *pos)
        yaffs_Object *obj;
        int nRead,ipos;
        struct inode *inode;
-
+       
        T((KERN_DEBUG"yaffs_file_read\n"));
 
        obj  = yaffs_DentryToObject(f->f_dentry);
        inode = f->f_dentry->d_inode;
-
-       if (*pos < inode->i_size)
+       
+       if (*pos < inode->i_size) 
        {
                        if (*pos + n > inode->i_size)
                        {
@@ -296,7 +296,7 @@ static ssize_t yaffs_file_read(struct file *f, char *buf, size_t n, loff_t *pos)
        {
                n = 0;
        }
-
+       
        nRead = yaffs_ReadDataFromFile(obj,buf,*pos,n);
        if(nRead > 0)
        {
@@ -305,7 +305,7 @@ static ssize_t yaffs_file_read(struct file *f, char *buf, size_t n, loff_t *pos)
        ipos = *pos;
        T((KERN_DEBUG"yaffs_file_read read %d bytes, %d read at %d\n",n,nRead,ipos));
        return nRead;
-
+       
 }
 
 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos)
@@ -313,7 +313,7 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_
        yaffs_Object *obj;
        int nWritten,ipos;
        struct inode *inode;
-
+       
        obj  = yaffs_DentryToObject(f->f_dentry);
        inode = f->f_dentry->d_inode;
        nWritten = yaffs_WriteDataToFile(obj,buf,*pos,n);
@@ -328,9 +328,9 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_
                        inode->i_size = *pos;
                        T((KERN_DEBUG"yaffs_file_write size updated to %d\n",ipos));
                }
-
+               
        }
-       return nWritten;
+       return nWritten;        
 }
 
 
@@ -339,17 +339,17 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
        yaffs_Object *obj;
        struct inode *inode = f->f_dentry->d_inode;
        unsigned long offset, curoffs;
-       struct list_head *i;
+       struct list_head *i;    
        yaffs_Object *l;
-
+       
        char name[YAFFS_MAX_NAME_LENGTH +1];
-
+               
        obj =  yaffs_DentryToObject(f->f_dentry);
-
+       
        offset = f->f_pos;
-
+       
        T(("yaffs_readdir: starting at %d\n",(int)offset));
-
+       
        if(offset == 0)
        {
         T((KERN_DEBUG"yaffs_readdir: entry . ino %d \n",(int)inode->i_ino));
@@ -370,22 +370,22 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                offset++;
                f->f_pos++;
        }
-
+       
        curoffs = 1;
-
+       
        //down(&obj->sem);
 
-
+       
        list_for_each(i,&obj->variant.directoryVariant.children)
        {
                curoffs++;
                if(curoffs >= offset)
-               {
+               {               
                        l = list_entry(i, yaffs_Object,siblings);
-
-                       yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);
+                       
+                       yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1); 
                        T((KERN_DEBUG"yaffs_readdir: %s inode %d\n",name,yaffs_GetObjectInode(l)));
-
+                       
                        if(filldir(dirent,
                                           name,
                                           strlen(name),
@@ -396,16 +396,16 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                        {
                                goto up_and_out;
                        }
-
+                       
                        offset++;
-                       f->f_pos++;
+                       f->f_pos++;        
                }
        }
 
   up_and_out:
 
        //up(&obj->sem);
-
+       
   out:
        return 0;
 }
@@ -417,10 +417,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
 {
        struct inode *inode;
-
+       
        yaffs_Object *obj = NULL;
        yaffs_Object *parent = yaffs_InodeToObject(dir);
-
+       
        int error = -ENOSPC;
 
        if(parent)
@@ -433,16 +433,16 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int d
                T((KERN_DEBUG"yaffs_mknod: could not get parent object\n"));
                return -EPERM;
        }
-
+       
        T(("yaffs_mknod: making oject for %s, mode %x\n",
                                dentry->d_name.name, mode));
 
-       switch (mode & S_IFMT)
+       switch (mode & S_IFMT) 
        {
                default:
-
+               
                        break;
-               case S_IFREG:   // file
+               case S_IFREG:   // file         
                        T((KERN_DEBUG"yaffs_mknod: making file\n"));
                        obj = yaffs_MknodFile(parent,dentry->d_name.name,mode,current->uid, current->gid);
                        break;
@@ -455,7 +455,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int d
                        obj = NULL; // Todo
                        break;
        }
-
+       
        if(obj)
        {
                inode = yaffs_get_inode(dir->i_sb, mode, dev, obj);
@@ -471,7 +471,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int d
                T((KERN_DEBUG"yaffs_mknod failed making object\n"));
                error = -ENOMEM;
        }
-
+       
 
        return error;
 }
@@ -500,9 +500,9 @@ static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
 
 static int yaffs_unlink(struct inode * dir, struct dentry *dentry)
 {
-
+       
        T((KERN_DEBUG"yaffs_unlink\n"));
-
+       
        if(yaffs_Unlink(yaffs_InodeToObject(dir),dentry->d_name.name) == YAFFS_OK)
        {
                return 0;
@@ -520,11 +520,11 @@ static int yaffs_unlink(struct inode * dir, struct dentry *dentry)
 static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
 {
        struct inode *inode = old_dentry->d_inode;
-
+       
        T((KERN_DEBUG"yaffs_link\n"));
-
+       
        return -EPERM; //Todo
-
+       
 
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
@@ -537,10 +537,10 @@ static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dent
 static int yaffs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
 {
        int error;
-
+       
        T((KERN_DEBUG"yaffs_symlink\n"));
 
-
+       
        return -ENOMEM; //Todo
 
        error = yaffs_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
@@ -560,8 +560,8 @@ static int yaffs_sync_object(struct file * file, struct dentry *dentry, int data
  */
 static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
 {
-
-
+       
+       
        if( yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
                               yaffs_InodeToObject(new_dir),new_dentry->d_name.name) == YAFFS_OK)
        {
@@ -571,7 +571,7 @@ static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struc
        {
                return -ENOTEMPTY;
        }
-
+       
 
 }
 
@@ -579,12 +579,12 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
        int error;
-
+       
        T((KERN_DEBUG"yaffs_setattr\n"));
-
+       
        if((error = inode_change_ok(inode,attr)) == 0)
        {
-
+       
                if(yaffs_SetAttributes(yaffs_InodeToObject(inode),attr) == YAFFS_OK)
                {
                        error = 0;
@@ -616,12 +616,12 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
 static void yaffs_read_inode (struct inode *inode)
 {
 
-       yaffs_Object *obj ;
-
+       yaffs_Object *obj ; 
+       
        T((KERN_DEBUG"yaffs_read_inode for %d\n",(int)inode->i_ino));
 
        obj  = yaffs_FindObjectByNumber(yaffs_SuperToDevice(inode->i_sb),inode->i_ino);
-
+       
        yaffs_FillInodeFromObject(inode,obj);
 }
 
@@ -631,24 +631,25 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
        struct inode * inode;
        struct dentry * root;
        yaffs_Device *dev;
+       
 
-
-       T(("yaffs_read_super:\n"));
+       T(("yaffs_read_super: %s\n", useRam ? "RAM" : "MTD"));
        sb->s_blocksize = YAFFS_BYTES_PER_CHUNK;
        sb->s_blocksize_bits = YAFFS_CHUNK_SIZE_SHIFT;
        sb->s_magic = YAFFS_MAGIC;
        sb->s_op = &yaffs_super_ops;
-
+       
        if(!sb)
-               printk(KERN_INFO"sb is NULL\n");
+               printk(KERN_INFO"yaffs: sb is NULL\n");
        else if(!sb->s_dev)
-               printk(KERN_INFO"sb->s_dev is NULL\n");
+               printk(KERN_INFO"yaffs: sb->s_dev is NULL\n");
        else if(! kdevname(sb->s_dev))
-               printk(KERN_INFO"kdevname is NULL\n");
+               printk(KERN_INFO"yaffs: kdevname is NULL\n");
        else
-               printk(KERN_INFO"dev is %d name is \"%s\"\n", sb->s_dev, kdevname(sb->s_dev));
-
+               printk(KERN_INFO"yaffs: dev is %d name is \"%s\"\n", sb->s_dev, kdevname(sb->s_dev));
 
+       
+       
        if(useRam)
        {
 
@@ -678,23 +679,36 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
 
        }
        else
-       {
+       {       
 #ifdef YAFFS_MTD_ENABLED
                struct mtd_info *mtd;
-
+               
+               printk(KERN_DEBUG "yaffs: Attempting MTD mount on %u.%u, \"%s\"\n",
+                MAJOR(sb->s_dev),MINOR(sb->s_dev),kdevname(sb->s_dev));
+                       
                // Hope it's a NAND mtd
                mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
-               if (!mtd)
+               if (!mtd) 
                {
                        printk(KERN_DEBUG "yaffs: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev));
                        return NULL;
                }
+               
                if(mtd->type != MTD_NANDFLASH)
                {
                        printk(KERN_DEBUG "yaffs: MTD device is not NAND it's type %d\n", mtd->type);
                        return NULL;
                }
 
+               printk(KERN_DEBUG" erase %x\n",mtd->erase);
+               printk(KERN_DEBUG" read %x\n",mtd->read);
+               printk(KERN_DEBUG" write %x\n",mtd->write);
+               printk(KERN_DEBUG" readoob %x\n",mtd->read_oob);
+               printk(KERN_DEBUG" writeoob %x\n",mtd->write_oob);
+               printk(KERN_DEBUG" oobblock %x\n",mtd->oobblock);
+               printk(KERN_DEBUG" oobsize %x\n",mtd->oobsize);
+
+
                if(!mtd->erase ||
                   !mtd->read  ||
                   !mtd->write ||
@@ -704,16 +718,16 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
                        printk(KERN_DEBUG "yaffs: MTD device does not support required functions\n");
                        return NULL;
                }
-
+               
                if(mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
                   mtd->oobsize != YAFFS_BYTES_PER_SPARE)
                {
                        printk(KERN_DEBUG "yaffs: MTD device does not support have the right page sizes\n");
                        return NULL;
                }
+                  
 
-
-               // OK, so if we got here, we have an MTD that's NAND and looks
+               // OK, so if we got here, we have an MTD that's NAND and looks 
                // like it has the right capabilities
                // Set the yaffs_Device up for ram emulation
 
@@ -726,11 +740,11 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
                }
 
                memset(dev,0,sizeof(yaffs_Device));
-               dev->genericDevice = mtd;
+               dev->genericDevice = mtd; 
 
                // Set up the memory size parameters....
-
-               dev->nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+               
+               dev->nBlocks = YAFFS_RAM_EMULATION_SIZE / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
                dev->startBlock = 1;  // Don't use block 0
                dev->endBlock = dev->nBlocks - 1;
 
@@ -739,7 +753,7 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
                dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
                dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
                dev->initialiseNAND = nandmtd_InitialiseNAND;
-
+               
 #endif
        }
 
@@ -754,7 +768,7 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
                return NULL;
 
        T(("yaffs_read_super: got root inode\n"));
-
+               
 
        root = d_alloc_root(inode);
 
@@ -808,9 +822,9 @@ static int  yaffs_proc_read(
        if (offset > 0) return 0;
 
        /* Fill the buffer and get its length */
-       sprintf( my_buffer,
+       sprintf( my_buffer, 
                "YAFFS built:"__DATE__ " "__TIME__"\n"
-
+               
        );
 
        strcpy(page,my_buffer);
@@ -820,7 +834,7 @@ static int  yaffs_proc_read(
 static int __init init_yaffs_fs(void)
 {
        int error = 0;
-
+       
        printk(KERN_DEBUG "yaffs " __DATE__ " " __TIME__ " Initialisation\n");
     /* Install the proc_fs entry */
     my_proc_entry = create_proc_read_entry("yaffs",
@@ -860,12 +874,12 @@ static void __exit exit_yaffs_fs(void)
        printk(KERN_DEBUG "yaffs " __DATE__ " " __TIME__ " Clean up\n");
 
     remove_proc_entry("yaffs",&proc_root);
-
+    
 #ifdef YAFFS_RAM_ENABLED
-       unregister_filesystem(&yaffs_ram_fs_type);
+       unregister_filesystem(&yaffs_fs_type);
 #endif
 #ifdef YAFFS_MTD_ENABLED
-       unregister_filesystem(&yaffs_fs_type);
+       unregister_filesystem(&yaffs_ram_fs_type);
 #endif
 
 }
index 233551187effaeeb5015185a415ac0c2bbd4a863..b6f80f5aa93e77e197762d84bdab35ebc16ac520 100644 (file)
Binary files a/yaffsdev.proj and b/yaffsdev.proj differ