summaryrefslogtreecommitdiff
path: root/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff
diff options
context:
space:
mode:
Diffstat (limited to 'linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff')
-rw-r--r--linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff51503
1 files changed, 0 insertions, 51503 deletions
diff --git a/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff b/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff
deleted file mode 100644
index 74e6375385..0000000000
--- a/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff
+++ /dev/null
@@ -1,51503 +0,0 @@
-diff -Nurb linux-mips-2.4.27/drivers/mtd/Config.in linux/drivers/mtd/Config.in
---- linux-mips-2.4.27/drivers/mtd/Config.in 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/Config.in 2004-11-19 10:25:11.607244176 +0100
-@@ -1,5 +1,5 @@
-
--# $Id$
-+# $Id$
-
- mainmenu_option next_comment
- comment 'Memory Technology Devices (MTD)'
-@@ -30,6 +30,7 @@
- if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
- bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW
- fi
-+ dep_tristate ' INFTL (Inverse NAND Flash Translation Layer) support' CONFIG_INFTL $CONFIG_MTD
-
- source drivers/mtd/chips/Config.in
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/Makefile linux/drivers/mtd/Makefile
---- linux-mips-2.4.27/drivers/mtd/Makefile 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/Makefile 2004-11-19 10:25:11.608244024 +0100
-@@ -1,30 +1,7 @@
- #
- # Makefile for the memory technology device drivers.
- #
--# Note! Dependencies are done automagically by 'make dep', which also
--# removes any old dependencies. DON'T put your own dependencies here
--# unless it's something special (ie not a .c file).
--#
--# Note 2! The CFLAGS definitions are now inherited from the
--# parent makes..
--#
--# $Id$
--
--
--obj-y += chips/chipslink.o maps/mapslink.o \
-- devices/devlink.o nand/nandlink.o
--obj-m :=
--obj-n :=
--obj- :=
--
--O_TARGET := mtdlink.o
--
--export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o
--list-multi := nftl.o
--
--mod-subdirs :=
--subdir-y := chips maps devices nand
--subdir-m := $(subdir-y)
-+# $Id$
-
- # *** BIG UGLY NOTE ***
- #
-@@ -52,15 +29,44 @@
-
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_CHAR) += mtdchar.o
--obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
--obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o
--obj-$(CONFIG_FTL) += ftl.o
--obj-$(CONFIG_NFTL) += nftl.o
-+obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o
-+obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o
-+obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
-+obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
-+obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
-
- nftl-objs := nftlcore.o nftlmount.o
-+inftl-objs := inftlcore.o inftlmount.o
-+
-+ifeq ($(PATCHLEVEL),4)
-+
-+export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o \
-+ mtdconcat.o mtd_blkdevs-24.o
-+
-+mtd_blkdevs-objs := mtd_blkdevs-24.o
-+
-+obj-y += chips/chipslink.o maps/mapslink.o \
-+ devices/devlink.o nand/nandlink.o
-+
-+O_TARGET := mtdlink.o
-+
-+list-multi := nftl.o inftl.o mtd_blkdevs.o
-+
-+mod-subdirs :=
-+subdir-y := chips maps devices nand
-+subdir-m := $(subdir-y)
-
- include $(TOPDIR)/Rules.make
-
- nftl.o: $(nftl-objs)
- $(LD) -r -o $@ $(nftl-objs)
-
-+inftl.o: $(inftl-objs)
-+ $(LD) -r -o $@ $(inftl-objs)
-+
-+mtd_blkdevs.o: $(mtd_blkdevs-objs)
-+ $(LD) -r -o $@ $(mtd_blkdevs-objs)
-+
-+else
-+obj-y += chips/ maps/ devices/ nand/
-+endif
-diff -Nurb linux-mips-2.4.27/drivers/mtd/afs.c linux/drivers/mtd/afs.c
---- linux-mips-2.4.27/drivers/mtd/afs.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/afs.c 2004-11-19 10:25:11.610243720 +0100
-@@ -21,7 +21,7 @@
- This is access code for flashes using ARM's flash partitioning
- standards.
-
-- $Id$
-+ $Id$
-
- ======================================================================*/
-
-@@ -76,17 +76,19 @@
- return ret;
- }
-
-+ ret = 1;
-+
- /*
- * Does it contain the magic number?
- */
- if (fs.signature != 0xa0ffff9f)
-- ret = 1;
-+ ret = 0;
-
- /*
- * Don't touch the SIB.
- */
- if (fs.type == 2)
-- ret = 1;
-+ ret = 0;
-
- *iis_start = fs.image_info_base & mask;
- *img_start = fs.image_start & mask;
-@@ -96,14 +98,14 @@
- * be located after the footer structure.
- */
- if (*iis_start >= ptr)
-- ret = 1;
-+ ret = 0;
-
- /*
- * Check the start of this image. The image
- * data can not be located after this block.
- */
- if (*img_start > off)
-- ret = 1;
-+ ret = 0;
-
- return ret;
- }
-@@ -125,7 +127,9 @@
- return ret;
- }
-
--int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts)
-+static int parse_afs_partitions(struct mtd_info *mtd,
-+ struct mtd_partition **pparts,
-+ unsigned long origin)
- {
- struct mtd_partition *parts;
- u_int mask, off, idx, sz;
-@@ -150,7 +154,7 @@
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
- if (ret < 0)
- break;
-- if (ret == 1)
-+ if (ret == 0)
- continue;
-
- ret = afs_read_iis(mtd, &iis, iis_ptr);
-@@ -183,7 +187,7 @@
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
- if (ret < 0)
- break;
-- if (ret == 1)
-+ if (ret == 0)
- continue;
-
- /* Read the image info block */
-@@ -227,7 +231,25 @@
- return idx ? idx : ret;
- }
-
--EXPORT_SYMBOL(parse_afs_partitions);
-+static struct mtd_part_parser afs_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_afs_partitions,
-+ .name = "afs",
-+};
-+
-+static int __init afs_parser_init(void)
-+{
-+ return register_mtd_parser(&afs_parser);
-+}
-+
-+static void __exit afs_parser_exit(void)
-+{
-+ deregister_mtd_parser(&afs_parser);
-+}
-+
-+module_init(afs_parser_init);
-+module_exit(afs_parser_exit);
-+
-
- MODULE_AUTHOR("ARM Ltd");
- MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/Config.in linux/drivers/mtd/chips/Config.in
---- linux-mips-2.4.27/drivers/mtd/chips/Config.in 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/Config.in 2004-11-19 10:25:11.712228216 +0100
-@@ -1,6 +1,6 @@
- # drivers/mtd/chips/Config.in
-
--# $Id$
-+# $Id$
-
- mainmenu_option next_comment
-
-@@ -11,13 +11,12 @@
-
- if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
- define_bool CONFIG_MTD_GEN_PROBE y
--else
-- if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
-+elif [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
- define_bool CONFIG_MTD_GEN_PROBE m
-- else
-+else
- define_bool CONFIG_MTD_GEN_PROBE n
-- fi
- fi
-+
- if [ "$CONFIG_MTD_GEN_PROBE" = "y" -o "$CONFIG_MTD_GEN_PROBE" = "m" ]; then
- bool ' Flash chip driver advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS
- if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then
-@@ -44,8 +43,27 @@
- fi
- dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
- dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
-+if [ "$CONFIG_MTD_CFI_AMDSTD" = "y" -o "$CONFIG_MTD_CFI_AMDSTD" = "m" ]; then
-+ bool ' Retry failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY n
-+ if [ "$CONFIG_MTD_CFI_AMDSTD_RETRY" = "y" ]; then
-+ int ' Max retries of failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0
-+ fi
-+fi
-+
- dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
-
-+if [ "$CONFIG_MTD_CFI_INTELEXT" = "y" \
-+ -o "$CONFIG_MTD_CFI_AMDSTD" = "y" \
-+ -o "$CONFIG_MTD_CFI_STAA" = "y" ]; then
-+ define_bool CONFIG_MTD_CFI_UTIL y
-+elif [ "$CONFIG_MTD_CFI_INTELEXT" = "m" \
-+ -o "$CONFIG_MTD_CFI_AMDSTD" = "m" \
-+ -o "$CONFIG_MTD_CFI_STAA" = "m" ]; then
-+ define_bool CONFIG_MTD_CFI_UTIL m
-+else
-+ define_bool CONFIG_MTD_CFI_UTIL n
-+fi
-+
- dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
- dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
- dep_tristate ' Support for absent chips in bus mapping' CONFIG_MTD_ABSENT $CONFIG_MTD
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/Makefile linux/drivers/mtd/chips/Makefile
---- linux-mips-2.4.27/drivers/mtd/chips/Makefile 2003-07-05 05:23:38.000000000 +0200
-+++ linux/drivers/mtd/chips/Makefile 2004-11-19 10:25:11.714227912 +0100
-@@ -1,11 +1,12 @@
- #
- # linux/drivers/chips/Makefile
- #
--# $Id$
-+# $Id$
-
-+ifeq ($(PATCHLEVEL),4)
- O_TARGET := chipslink.o
--
--export-objs := chipreg.o gen_probe.o
-+export-objs := chipreg.o gen_probe.o cfi_util.o
-+endif
-
- # *** BIG UGLY NOTE ***
- #
-@@ -17,6 +18,7 @@
- obj-$(CONFIG_MTD) += chipreg.o
- obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
- obj-$(CONFIG_MTD_CFI) += cfi_probe.o
-+obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o
- obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
- obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
- obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
-@@ -28,4 +30,4 @@
- obj-$(CONFIG_MTD_SHARP) += sharp.o
- obj-$(CONFIG_MTD_ABSENT) += map_absent.o
-
--include $(TOPDIR)/Rules.make
-+-include $(TOPDIR)/Rules.make
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
---- linux-mips-2.4.27/drivers/mtd/chips/amd_flash.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/amd_flash.c 2004-11-19 10:25:11.722226696 +0100
-@@ -3,7 +3,7 @@
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
-- * $Id$
-+ * $Id$
- *
- * Copyright (c) 2001 Axis Communications AB
- *
-@@ -19,6 +19,7 @@
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/init.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/flashchip.h>
-@@ -125,10 +126,10 @@
-
-
- static struct mtd_chip_driver amd_flash_chipdrv = {
-- probe: amd_flash_probe,
-- destroy: amd_flash_destroy,
-- name: "amd_flash",
-- module: THIS_MODULE
-+ .probe = amd_flash_probe,
-+ .destroy = amd_flash_destroy,
-+ .name = "amd_flash",
-+ .module = THIS_MODULE
- };
-
-
-@@ -140,11 +141,11 @@
- static inline __u32 wide_read(struct map_info *map, __u32 addr)
- {
- if (map->buswidth == 1) {
-- return map->read8(map, addr);
-+ return map_read8(map, addr);
- } else if (map->buswidth == 2) {
-- return map->read16(map, addr);
-+ return map_read16(map, addr);
- } else if (map->buswidth == 4) {
-- return map->read32(map, addr);
-+ return map_read32(map, addr);
- }
-
- return 0;
-@@ -153,11 +154,11 @@
- static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
- {
- if (map->buswidth == 1) {
-- map->write8(map, val, addr);
-+ map_write8(map, val, addr);
- } else if (map->buswidth == 2) {
-- map->write16(map, val, addr);
-+ map_write16(map, val, addr);
- } else if (map->buswidth == 4) {
-- map->write32(map, val, addr);
-+ map_write32(map, val, addr);
- }
- }
-
-@@ -424,231 +425,228 @@
-
- static struct mtd_info *amd_flash_probe(struct map_info *map)
- {
-- /* Keep this table on the stack so that it gets deallocated after the
-- * probe is done.
-- */
-- const struct amd_flash_info table[] = {
-+ static const struct amd_flash_info table[] = {
- {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DT,
-- name: "AMD AM29LV160DT",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DT,
-+ .name = "AMD AM29LV160DT",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DB,
-- name: "AMD AM29LV160DB",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DB,
-+ .name = "AMD AM29LV160DB",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT160,
-- name: "Toshiba TC58FVT160",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT160,
-+ .name = "Toshiba TC58FVT160",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160TE,
-- name: "Fujitsu MBM29LV160TE",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160TE,
-+ .name = "Fujitsu MBM29LV160TE",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB160,
-- name: "Toshiba TC58FVB160",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB160,
-+ .name = "Toshiba TC58FVB160",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160BE,
-- name: "Fujitsu MBM29LV160BE",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160BE,
-+ .name = "Fujitsu MBM29LV160BE",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BB,
-- name: "AMD AM29F800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BB,
-+ .name = "AMD AM29F800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BT,
-- name: "AMD AM29LV800BT",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BT,
-+ .name = "AMD AM29LV800BT",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BT,
-- name: "AMD AM29F800BT",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BT,
-+ .name = "AMD AM29F800BT",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800BB,
-- name: "Fujitsu MBM29LV800BB",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800BB,
-+ .name = "Fujitsu MBM29LV800BB",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W800T,
-- name: "ST M29W800T",
-- size: 0x00100000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W800T,
-+ .name = "ST M29W800T",
-+ .size = 0x00100000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DT,
-- name: "ST M29W160DT",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 }
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W160DT,
-+ .name = "ST M29W160DT",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DB,
-- name: "ST M29W160DB",
-- size: 0x00200000,
-- numeraseregions: 4,
-- regions: {
-- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 },
-- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 },
-- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W160DB,
-+ .name = "ST M29W160DB",
-+ .size = 0x00200000,
-+ .numeraseregions = 4,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
-+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
-+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29BDS323D,
-- name: "AMD AM29BDS323D",
-- size: 0x00400000,
-- numeraseregions: 3,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 48 },
-- { offset: 0x300000, erasesize: 0x10000, numblocks: 15 },
-- { offset: 0x3f0000, erasesize: 0x02000, numblocks: 8 },
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29BDS323D,
-+ .name = "AMD AM29BDS323D",
-+ .size = 0x00400000,
-+ .numeraseregions = 3,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
-+ { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-+ { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29BDS643D,
-- name: "AMD AM29BDS643D",
-- size: 0x00800000,
-- numeraseregions: 3,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 96 },
-- { offset: 0x600000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 },
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29BDS643D,
-+ .name = "AMD AM29BDS643D",
-+ .size = 0x00800000,
-+ .numeraseregions = 3,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
-+ { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49xV16x,
-- name: "Atmel AT49xV16x",
-- size: 0x00200000,
-- numeraseregions: 2,
-- regions: {
-- { offset: 0x000000, erasesize: 0x02000, numblocks: 8 },
-- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49xV16x,
-+ .name = "Atmel AT49xV16x",
-+ .size = 0x00200000,
-+ .numeraseregions = 2,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 },
-+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49xV16xT,
-- name: "Atmel AT49xV16xT",
-- size: 0x00200000,
-- numeraseregions: 2,
-- regions: {
-- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
-- { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 }
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49xV16xT,
-+ .name = "Atmel AT49xV16xT",
-+ .size = 0x00200000,
-+ .numeraseregions = 2,
-+ .regions = {
-+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-+ { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 }
- }
- }
- };
-@@ -822,7 +820,7 @@
-
- chip->state = FL_READY;
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-@@ -984,7 +982,7 @@
- u_char tmp_buf[4];
- __u32 datum;
-
-- map->copy_from(map, tmp_buf,
-+ map_copy_from(map, tmp_buf,
- bus_ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len && i < map->buswidth)
-@@ -1057,7 +1055,7 @@
- u_char tmp_buf[2];
- __u32 datum;
-
-- map->copy_from(map, tmp_buf,
-+ map_copy_from(map, tmp_buf,
- ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len--) {
-@@ -1178,7 +1176,7 @@
- __u8 verify;
-
- for (address = adr; address < (adr + size); address++) {
-- if ((verify = map->read8(map, address)) != 0xFF) {
-+ if ((verify = map_read8(map, address)) != 0xFF) {
- error = 1;
- break;
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c linux/drivers/mtd/chips/cfi_cmdset_0001.c
---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c 2003-07-05 05:23:38.000000000 +0200
-+++ linux/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-19 10:25:11.733225024 +0100
-@@ -4,7 +4,7 @@
- *
- * (C) 2000 Red Hat. GPL'd
- *
-- * $Id$
-+ * $Id$
- *
- *
- * 10/10/2000 Nicolas Pitre <nico@cam.org>
-@@ -21,6 +21,7 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
-@@ -29,10 +30,14 @@
- #include <linux/delay.h>
- #include <linux/interrupt.h>
- #include <linux/mtd/map.h>
--#include <linux/mtd/cfi.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/compatmac.h>
-+#include <linux/mtd/cfi.h>
-+
-+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
-
--// debugging, turns off buffer write mode #define FORCE_WORD_WRITE
-+// debugging, turns off buffer write mode if set to 1
-+#define FORCE_WORD_WRITE 0
-
- static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-@@ -52,16 +57,21 @@
-
- static struct mtd_info *cfi_intelext_setup (struct map_info *);
-
--static int do_point (struct mtd_info *mtd, loff_t from, size_t len,
-+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf);
--static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len);
-
-+
-+/*
-+ * *********** SETUP AND PROBE BITS ***********
-+ */
-+
- static struct mtd_chip_driver cfi_intelext_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_intelext_destroy,
-- name: "cfi_cmdset_0001",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_intelext_destroy,
-+ .name = "cfi_cmdset_0001",
-+ .module = THIS_MODULE
- };
-
- /* #define DEBUG_LOCK_BITS */
-@@ -102,13 +112,63 @@
- }
-
- printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
-- extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
-+ extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
- if (extp->VppOptimal)
- printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
-- extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
-+ extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
- }
- #endif
-
-+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
-+static void fixup_intel_strataflash(struct map_info *map, void* param)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
-+
-+ printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
-+ "erase on write disabled.\n");
-+ extp->SuspendCmdSupport &= ~1;
-+}
-+#endif
-+
-+static void fixup_st_m28w320ct(struct map_info *map, void* param)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */
-+ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
-+}
-+
-+static void fixup_st_m28w320cb(struct map_info *map, void* param)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ /* Note this is done after the region info is endian swapped */
-+ cfi->cfiq->EraseRegionInfo[1] =
-+ (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
-+};
-+
-+static struct cfi_fixup fixup_table[] = {
-+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-+ {
-+ CFI_MFR_ANY, CFI_ID_ANY,
-+ fixup_intel_strataflash, NULL
-+ },
-+#endif
-+ {
-+ 0x0020, /* STMicroelectronics */
-+ 0x00ba, /* M28W320CT */
-+ fixup_st_m28w320ct, NULL
-+ }, {
-+ 0x0020, /* STMicroelectronics */
-+ 0x00bb, /* M28W320CB */
-+ fixup_st_m28w320cb, NULL
-+ }, {
-+ 0, 0, NULL, NULL
-+ }
-+};
-+
- /* This routine is made available to other mtd code via
- * inter_module_register. It must only be accessed through
- * inter_module_get which will bump the use count of this module. The
-@@ -120,7 +180,6 @@
- {
- struct cfi_private *cfi = map->fldrv_priv;
- int i;
-- __u32 base = cfi->chips[0].start;
-
- if (cfi->cfi_mode == CFI_MODE_CFI) {
- /*
-@@ -130,59 +189,29 @@
- */
- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
- struct cfi_pri_intelext *extp;
-- int ofs_factor = cfi->interleave * cfi->device_type;
--
-- //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
-- if (!adr)
-- return NULL;
-
-- /* Switch it into Query Mode */
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
--
-- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-- if (!extp) {
-- printk(KERN_ERR "Failed to allocate memory\n");
-+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
-+ if (!extp)
- return NULL;
-- }
--
-- /* Read in the Extended Query Table */
-- for (i=0; i<sizeof(*extp); i++) {
-- ((unsigned char *)extp)[i] =
-- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-- }
--
-- if (extp->MajorVersion != '1' ||
-- (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-- printk(KERN_WARNING " Unknown IntelExt Extended Query "
-- "version %c.%c.\n", extp->MajorVersion,
-- extp->MinorVersion);
-- kfree(extp);
-- return NULL;
-- }
-
- /* Do some byteswapping if necessary */
- extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
- extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
- extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
-
-+ /* Install our own private info structure */
-+ cfi->cmdset_priv = extp;
-+
-+ cfi_fixup(map, fixup_table);
-+
- #ifdef DEBUG_CFI_FEATURES
- /* Tell the user about it in lots of lovely detail */
- cfi_tell_features(extp);
- #endif
-
- if(extp->SuspendCmdSupport & 1) {
--//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
--#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
--/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
-- printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
-- "erase on write disabled.\n");
-- extp->SuspendCmdSupport &= ~1;
--#else
- printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
--#endif
- }
-- /* Install our own private info structure */
-- cfi->cmdset_priv = extp;
- }
-
- for (i=0; i< cfi->numchips; i++) {
-@@ -194,8 +223,6 @@
-
- map->fldrv = &cfi_intelext_chipdrv;
-
-- /* Make sure it's in read mode */
-- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
- return cfi_intelext_setup(map);
- }
-
-@@ -261,20 +288,16 @@
- mtd->erase = cfi_intelext_erase_varsize;
- mtd->read = cfi_intelext_read;
-
-- if(map->point && map->unpoint){
-- mtd->point = do_point;
-- mtd->unpoint = do_unpoint;
-+ if (map_is_linear(map)) {
-+ mtd->point = cfi_intelext_point;
-+ mtd->unpoint = cfi_intelext_unpoint;
- }
-
--#ifndef FORCE_WORD_WRITE
-- if ( cfi->cfiq->BufWriteTimeoutTyp ) {
-- printk("Using buffer write method\n" );
-+ if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
-+ printk(KERN_INFO "Using buffer write method\n" );
- mtd->write = cfi_intelext_write_buffers;
- } else {
--#else
-- {
--#endif
-- printk("Using word write method\n" );
-+ printk(KERN_INFO "Using word write method\n" );
- mtd->write = cfi_intelext_write_words;
- }
- mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
-@@ -286,8 +309,8 @@
- mtd->resume = cfi_intelext_resume;
- mtd->flags = MTD_CAP_NORFLASH;
- map->fldrv = &cfi_intelext_chipdrv;
-- MOD_INC_USE_COUNT;
- mtd->name = map->name;
-+ __module_get(THIS_MODULE);
- return mtd;
-
- setup_err:
-@@ -301,78 +324,170 @@
- return NULL;
- }
-
--static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
-+/*
-+ * *********** CHIP ACCESS FUNCTIONS ***********
-+ */
-+
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
- {
-- cfi_word status, status_OK;
-- unsigned long timeo;
- DECLARE_WAITQUEUE(wait, current);
-- unsigned long cmd_addr;
- struct cfi_private *cfi = map->fldrv_priv;
-+ cfi_word status, status_OK = CMD(0x80);
-+ unsigned long timeo;
-+ struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv;
-
-- adr += chip->start;
--
-- /* Ensure cmd read/writes are aligned. */
-- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
--
-- /* Let's determine this according to the interleave only once */
-- status_OK = CMD(0x80);
--
-+ resettime:
- timeo = jiffies + HZ;
- retry:
-- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * If it's in FL_ERASING state, suspend it and make it talk now.
-- */
- switch (chip->state) {
-
-- case FL_READY:
-- case FL_POINT:
-+ case FL_STATUS:
-+ for (;;) {
-+ status = cfi_read(map, adr);
-+ if ((status & status_OK) == status_OK)
- break;
-
-+ if (time_after(jiffies, timeo)) {
-+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n",
-+ (long long)status);
-+ spin_unlock(chip->mutex);
-+ return -EIO;
-+ }
-+ spin_unlock(chip->mutex);
-+ cfi_udelay(1);
-+ spin_lock(chip->mutex);
-+ /* Someone else might have been playing with it. */
-+ goto retry;
-+ }
-+
-+ case FL_READY:
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_STATUS;
-+ return 0;
-
-- case FL_STATUS:
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK) {
-- cfi_write(map, CMD(0xff), cmd_addr);
-- chip->state = FL_READY;
-+ case FL_ERASING:
-+ if (!(cfip->FeatureSupport & 2) ||
-+ !(mode == FL_READY || mode == FL_POINT ||
-+ (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
-+ goto sleep;
-+
-+
-+ /* Erase suspend */
-+ cfi_write(map, CMD(0xB0), adr);
-+
-+ /* If the flash has finished erasing, then 'erase suspend'
-+ * appears to make some (28F320) flash devices switch to
-+ * 'read' mode. Make sure that we switch to 'read status'
-+ * mode so we get the right data. --rmk
-+ */
-+ cfi_write(map, CMD(0x70), adr);
-+ chip->oldstate = FL_ERASING;
-+ chip->state = FL_ERASE_SUSPENDING;
-+ chip->erase_suspended = 1;
-+ for (;;) {
-+ status = cfi_read(map, adr);
-+ if ((status & status_OK) == status_OK)
- break;
-- }
-
-- /* Urgh. Chip not yet ready to talk to us. */
- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
-+ /* Urgh. Resume and pretend we weren't here. */
-+ cfi_write(map, CMD(0xd0), adr);
-+ /* Make sure we're in 'read status' mode if it had finished */
-+ cfi_write(map, CMD(0x70), adr);
-+ chip->state = FL_ERASING;
-+ chip->oldstate = FL_READY;
-+ printk(KERN_ERR "Chip not ready after erase "
-+ "suspended: status = 0x%x\n", status);
- return -EIO;
- }
-
-- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- cfi_udelay(1);
-- goto retry;
-+ spin_lock(chip->mutex);
-+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
-+ So we can just loop here. */
-+ }
-+ chip->state = FL_STATUS;
-+ return 0;
-+
-+ case FL_POINT:
-+ /* Only if there's no operation suspended... */
-+ if (mode == FL_READY && chip->oldstate == FL_READY)
-+ return 0;
-
- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-+ sleep:
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ spin_lock(chip->mutex);
-+ goto resettime;
- }
-+}
-+
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ switch(chip->oldstate) {
-+ case FL_ERASING:
-+ chip->state = chip->oldstate;
-+ /* What if one interleaved chip has finished and the
-+ other hasn't? The old code would leave the finished
-+ one in READY mode. That's bad, and caused -EROFS
-+ errors to be returned from do_erase_oneblock because
-+ that's the only bit it checked for at the time.
-+ As the state machine appears to explicitly allow
-+ sending the 0x70 (Read Status) command to an erasing
-+ chip and expecting it to be ignored, that's what we
-+ do. */
-+ cfi_write(map, CMD(0xd0), adr);
-+ cfi_write(map, CMD(0x70), adr);
-+ chip->oldstate = FL_READY;
-+ chip->state = FL_ERASING;
-+ break;
-+
-+ case FL_READY:
-+ case FL_STATUS:
-+ /* We should really make set_vpp() count, rather than doing this */
-+ DISABLE_VPP(map);
-+ break;
-+ default:
-+ printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate);
-+ }
-+ wake_up(&chip->wq);
-+}
-+
-+static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
-+{
-+ unsigned long cmd_addr;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ret = 0;
-+
-+ adr += chip->start;
-+
-+ /* Ensure cmd read/writes are aligned. */
-+ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
-+
-+ spin_lock(chip->mutex);
-+
-+ ret = get_chip(map, chip, cmd_addr, FL_POINT);
-+
-+ if (!ret) {
-+ if (chip->state != FL_POINT && chip->state != FL_READY)
-+ cfi_write(map, CMD(0xff), cmd_addr);
-
- chip->state = FL_POINT;
- chip->ref_point_counter++;
-+ }
- spin_unlock(chip->mutex);
-- return 0;
-+
-+ return ret;
- }
--static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
-+
-+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-@@ -380,12 +495,10 @@
- int chipnum;
- int ret = 0;
-
-- if (from + len > mtd->size)
-+ if (!map->virt || (from + len > mtd->size))
- return -EINVAL;
-
-- *mtdbuf = map->point(map, from, len);
-- if(*mtdbuf == NULL)
-- return -EINVAL; /* can not point this region */
-+ *mtdbuf = (void *)map->virt + from;
- *retlen = 0;
-
- /* Now lock the chip(s) to POINT state */
-@@ -418,14 +531,13 @@
- return 0;
- }
-
--static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
-+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- unsigned long ofs;
- int chipnum;
-
-- map->unpoint(map, addr, from, len);
- /* Now unlock the chip(s) POINT state */
-
- /* ofs: offset within the first chip that the first read should start */
-@@ -446,13 +558,14 @@
- thislen = len;
-
- spin_lock(chip->mutex);
-- if(chip->state == FL_POINT){
-+ if (chip->state == FL_POINT) {
- chip->ref_point_counter--;
- if(chip->ref_point_counter == 0)
- chip->state = FL_READY;
- } else
-- printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
-- wake_up(&chip->wq);
-+ printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
-+
-+ put_chip(map, chip, chip->start);
- spin_unlock(chip->mutex);
-
- len -= thislen;
-@@ -463,136 +576,32 @@
-
- static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
- {
-- cfi_word status, status_OK;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int suspended = 0;
- unsigned long cmd_addr;
- struct cfi_private *cfi = map->fldrv_priv;
-+ int ret;
-
- adr += chip->start;
-
- /* Ensure cmd read/writes are aligned. */
- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
-
-- /* Let's determine this according to the interleave only once */
-- status_OK = CMD(0x80);
--
-- timeo = jiffies + HZ;
-- retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * If it's in FL_ERASING state, suspend it and make it talk now.
-- */
-- switch (chip->state) {
-- case FL_ERASING:
-- if (!cfi->cmdset_priv ||
-- !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), cmd_addr);
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- // printk("Erase suspending at 0x%lx\n", cmd_addr);
-- for (;;) {
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_ERASING;
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%llx\n", (__u64)status);
-- return -EIO;
-- }
--
-+ ret = get_chip(map, chip, cmd_addr, FL_READY);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- spin_lock(chip->mutex);
-+ return ret;
- }
-
-- suspended = 1;
-+ if (chip->state != FL_POINT && chip->state != FL_READY) {
- cfi_write(map, CMD(0xff), cmd_addr);
-- chip->state = FL_READY;
-- break;
--
--#if 0
-- case FL_WRITING:
-- /* Not quite yet */
--#endif
--
-- case FL_READY:
-- case FL_POINT:
-- break;
--
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_addr);
-- chip->state = FL_STATUS;
-
-- case FL_STATUS:
-- status = cfi_read(map, cmd_addr);
-- if ((status & status_OK) == status_OK) {
-- cfi_write(map, CMD(0xff), cmd_addr);
- chip->state = FL_READY;
-- break;
- }
-
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
-- return -EIO;
-- }
-+ map_copy_from(map, buf, adr, len);
-
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
-+ put_chip(map, chip, cmd_addr);
-
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-- }
--
-- map->copy_from(map, buf, adr, len);
--
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), cmd_addr);
-- cfi_write(map, CMD(0x70), cmd_addr);
-- }
--
-- wake_up(&chip->wq);
- spin_unlock(chip->mutex);
- return 0;
- }
-@@ -640,70 +649,52 @@
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-- int ofs_factor = cfi->interleave * cfi->device_type;
-- int count=len;
-+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- struct flchip *chip;
-- int chip_num,offst;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-+ int ofs_factor = cfi->interleave * cfi->device_type;
-+ int count = len;
-+ int chip_num, offst;
-+ int ret;
-
-- chip=0;
-- /* Calculate which chip & protection register offset we need */
-- chip_num=((unsigned int)from/reg_sz);
-- offst=from-(reg_sz*chip_num)+base_offst;
-+ chip_num = ((unsigned int)from/reg_sz);
-+ offst = from - (reg_sz*chip_num)+base_offst;
-
-- while(count){
-+ while (count) {
-+ /* Calculate which chip & protection register offset we need */
-
-- if(chip_num>=cfi->numchips)
-+ if (chip_num >= cfi->numchips)
- goto out;
-
-- /* Make sure that the chip is in the right state */
-+ chip = &cfi->chips[chip_num];
-
-- timeo = jiffies + HZ;
-- chip=&cfi->chips[chip_num];
-- retry:
- spin_lock(chip->mutex);
--
-- switch (chip->state) {
-- case FL_READY:
-- case FL_STATUS:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- break;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return (len-count)?:ret;
- }
-
-- /* Now read the data required from this flash */
-+ if (chip->state != FL_JEDEC_QUERY) {
-+ cfi_write(map, CMD(0x90), chip->start);
-+ chip->state = FL_JEDEC_QUERY;
-+ }
-
-- cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL);
-- while(count && ((offst-base_offst)<reg_sz)){
-- *buf=map->read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
-+ while (count && ((offst-base_offst) < reg_sz)) {
-+ *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
- buf++;
- offst++;
- count--;
- }
-
-- chip->state=FL_CFI_QUERY;
-+ put_chip(map, chip, chip->start);
- spin_unlock(chip->mutex);
-+
- /* Move on to the next chip */
- chip_num++;
-- offst=base_offst;
--
-+ offst = base_offst;
- }
-
- out:
-- wake_up(&chip->wq);
- return len-count;
- }
-
-@@ -749,103 +740,20 @@
- static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-- cfi_word status, status_OK;
-- unsigned long timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int z, suspended=0, ret=0;
--
-- adr += chip->start;
--
-- /* Let's determine this according to the interleave only once */
-- status_OK = CMD(0x80);
--
-- timeo = jiffies + HZ;
-- retry:
-- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * Later, we can actually think about interrupting it
-- * if it's in FL_ERASING state.
-- * Not just yet, though.
-- */
-- switch (chip->state) {
-- case FL_READY:
-- break;
--
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in read\n");
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- case FL_ERASING:
-- if (!extp ||
-- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), adr);
--
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), adr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- for (;;) {
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
-+ cfi_word status, status_OK;
-+ unsigned long timeo;
-+ int z, ret=0;
-
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), adr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_ERASING;
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%x\n", status);
-- return -EIO;
-- }
-+ adr += chip->start;
-
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- spin_lock(chip->mutex);
-- }
-- suspended = 1;
-- chip->state = FL_STATUS;
-- break;
-+ /* Let's determine this according to the interleave only once */
-+ status_OK = CMD(0x80);
-
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
- ENABLE_VPP(map);
-@@ -862,6 +770,8 @@
- for (;;) {
- if (chip->state != FL_WRITING) {
- /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-+
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
-@@ -879,7 +789,6 @@
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
- printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
- ret = -EIO;
- goto out;
-@@ -908,27 +817,11 @@
- /* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
- ret = -EROFS;
-- goto out;
- }
- out:
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), adr);
-- cfi_write(map, CMD(0x70), adr);
-- } else
-- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */
--
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
-+
- return ret;
- }
-
-@@ -1059,11 +952,9 @@
- unsigned long adr, const u_char *buf, int len)
- {
- struct cfi_private *cfi = map->fldrv_priv;
-- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- cfi_word status, status_OK;
- unsigned long cmd_adr, timeo;
-- DECLARE_WAITQUEUE(wait, current);
-- int wbufsize, z, suspended=0, ret=0;
-+ int wbufsize, z, ret=0, bytes, words;
-
- wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
- adr += chip->start;
-@@ -1072,91 +963,18 @@
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
-- retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us.
-- * Later, we can actually think about interrupting it
-- * if it's in FL_ERASING state.
-- * Not just yet, though.
-- */
-- switch (chip->state) {
-- case FL_READY:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- cfi_write(map, CMD(0x70), cmd_adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, cmd_adr);
-- if ((status & status_OK) == status_OK)
-- break;
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-+ ret = get_chip(map, chip, cmd_adr, FL_WRITING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");
-- return -EIO;
-+ return ret;
- }
-
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- case FL_ERASING:
-- if (!extp ||
-- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
-- goto sleep; /* We don't support erase suspend */
--
-- cfi_write (map, CMD(0xb0), adr);
--
-- /* If the flash has finished erasing, then 'erase suspend'
-- * appears to make some (28F320) flash devices switch to
-- * 'read' mode. Make sure that we switch to 'read status'
-- * mode so we get the right data. --rmk
-- */
-- cfi_write(map, CMD(0x70), adr);
-- chip->oldstate = FL_ERASING;
-- chip->state = FL_ERASE_SUSPENDING;
-- for (;;) {
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- if (time_after(jiffies, timeo)) {
-- /* Urgh */
-- cfi_write(map, CMD(0xd0), adr);
-- /* make sure we're in 'read status' mode */
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_ERASING;
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "Chip not ready after erase "
-- "suspended: status = 0x%x\n", status);
-- return -EIO;
-- }
-+ if (chip->state != FL_STATUS)
-+ cfi_write(map, CMD(0x70), cmd_adr);
-
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- spin_lock(chip->mutex);
-- }
-- suspended = 1;
-- chip->state = FL_STATUS;
-- break;
-+ status = cfi_read(map, cmd_adr);
-
-- default:
-- sleep:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-- }
-- /* We know we're now in FL_STATUS mode, and 'status' is current */
- /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
- [...], the device will not accept any more Write to Buffer commands".
- So we must check here and reset those bits if they're set. Otherwise
-@@ -1185,7 +1003,6 @@
- /* Argh. Not ready for write to buffer */
- cfi_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
- printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
- /* Odd. Clear status bits */
- cfi_write(map, CMD(0x50), cmd_adr);
-@@ -1196,20 +1013,42 @@
- }
-
- /* Write length of data to come */
-- cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
-+ bytes = len & (CFIDEV_BUSWIDTH-1);
-+ words = len / CFIDEV_BUSWIDTH;
-+ cfi_write(map, CMD(words - !bytes), cmd_adr );
-
- /* Write data */
-- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
-+ z = 0;
-+ while(z < words * CFIDEV_BUSWIDTH) {
- if (cfi_buswidth_is_1()) {
-- map->write8 (map, *((__u8*)buf)++, adr+z);
-+ map_write8 (map, *((__u8*)buf)++, adr+z);
- } else if (cfi_buswidth_is_2()) {
-- map->write16 (map, *((__u16*)buf)++, adr+z);
-+ map_write16 (map, *((__u16*)buf)++, adr+z);
- } else if (cfi_buswidth_is_4()) {
-- map->write32 (map, *((__u32*)buf)++, adr+z);
-+ map_write32 (map, *((__u32*)buf)++, adr+z);
- } else if (cfi_buswidth_is_8()) {
-- map->write64 (map, *((__u64*)buf)++, adr+z);
-+ map_write64 (map, *((__u64*)buf)++, adr+z);
-+ } else {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ z += CFIDEV_BUSWIDTH;
-+ }
-+ if (bytes) {
-+ int i = 0, n = 0;
-+ u_char tmp_buf[8], *tmp_p = tmp_buf;
-+
-+ while (bytes--)
-+ tmp_buf[i++] = buf[n++];
-+ while (i < CFIDEV_BUSWIDTH)
-+ tmp_buf[i++] = 0xff;
-+ if (cfi_buswidth_is_2()) {
-+ map_write16 (map, *((__u16*)tmp_p)++, adr+z);
-+ } else if (cfi_buswidth_is_4()) {
-+ map_write32 (map, *((__u32*)tmp_p)++, adr+z);
-+ } else if (cfi_buswidth_is_8()) {
-+ map_write64 (map, *((__u64*)tmp_p)++, adr+z);
- } else {
-- DISABLE_VPP(map);
- ret = -EINVAL;
- goto out;
- }
-@@ -1227,6 +1066,7 @@
- for (;;) {
- if (chip->state != FL_WRITING) {
- /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
-@@ -1244,7 +1084,6 @@
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
- printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
- ret = -EIO;
- goto out;
-@@ -1266,6 +1105,7 @@
-
- /* Done and happy. */
- chip->state = FL_STATUS;
-+
- /* check for lock bit */
- if (status & CMD(0x02)) {
- /* clear status */
-@@ -1273,26 +1113,10 @@
- /* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
- ret = -EROFS;
-- goto out;
- }
-- out:
-- if (suspended) {
-- chip->state = chip->oldstate;
-- /* What if one interleaved chip has finished and the
-- other hasn't? The old code would leave the finished
-- one in READY mode. That's bad, and caused -EROFS
-- errors to be returned from do_erase_oneblock because
-- that's the only bit it checked for at the time.
-- As the state machine appears to explicitly allow
-- sending the 0x70 (Read Status) command to an erasing
-- chip and expecting it to be ignored, that's what we
-- do. */
-- cfi_write(map, CMD(0xd0), adr);
-- cfi_write(map, CMD(0x70), adr);
-- } else
-- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */
-
-- wake_up(&chip->wq);
-+ out:
-+ put_chip(map, chip, cmd_adr);
- spin_unlock(chip->mutex);
- return ret;
- }
-@@ -1336,12 +1160,12 @@
- }
-
- /* Write buffer is worth it only if more than one word to write... */
-- while(len > CFIDEV_BUSWIDTH) {
-+ while(len) {
- /* We must not cross write block boundaries */
- int size = wbufsize - (ofs & (wbufsize-1));
-
- if (size > len)
-- size = len & ~(CFIDEV_BUSWIDTH-1);
-+ size = len;
- ret = do_write_buffer(map, &cfi->chips[chipnum],
- ofs, buf, size);
- if (ret)
-@@ -1359,17 +1183,6 @@
- return 0;
- }
- }
--
-- /* ... and write the remaining bytes */
-- if (len > 0) {
-- size_t local_retlen;
-- ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift),
-- len, &local_retlen, buf);
-- if (ret)
-- return ret;
-- (*retlen) += local_retlen;
-- }
--
- return 0;
- }
-
-@@ -1479,45 +1292,12 @@
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
--retry:
-+ retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us. */
-- switch (chip->state) {
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, adr, FL_ERASING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
- ENABLE_VPP(map);
-@@ -1528,7 +1308,7 @@
- cfi_write(map, CMD(0x20), adr);
- cfi_write(map, CMD(0xD0), adr);
- chip->state = FL_ERASING;
-- chip->oldstate = 0;
-+ chip->erase_suspended = 0;
-
- spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
-@@ -1550,11 +1330,11 @@
- spin_lock(chip->mutex);
- continue;
- }
-- if (chip->oldstate) {
-+ if (chip->erase_suspended) {
- /* This erase was suspended and resumed.
- Adjust the timeout */
- timeo = jiffies + (HZ*20); /* FIXME */
-- chip->oldstate = 0;
-+ chip->erase_suspended = 0;
- }
-
- status = cfi_read(map, adr);
-@@ -1658,39 +1438,22 @@
- int i;
- struct flchip *chip;
- int ret = 0;
-- DECLARE_WAITQUEUE(wait, current);
-
- for (i=0; !ret && i<cfi->numchips; i++) {
- chip = &cfi->chips[i];
-
-- retry:
- spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, chip->start, FL_SYNCING);
-
-- switch(chip->state) {
-- case FL_READY:
-- case FL_STATUS:
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-+ if (!ret) {
- chip->oldstate = chip->state;
- chip->state = FL_SYNCING;
- /* No need to wake_up() on this state change -
- * as the whole point is that nobody can do anything
- * with the chip now anyway.
- */
-- case FL_SYNCING:
-- spin_unlock(chip->mutex);
-- break;
--
-- default:
-- /* Not an idle state */
-- add_wait_queue(&chip->wq, &wait);
--
-- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--
-- goto retry;
- }
-+ spin_unlock(chip->mutex);
- }
-
- /* Unlock the chips again */
-@@ -1731,52 +1494,18 @@
- struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
-- DECLARE_WAITQUEUE(wait, current);
-+ int ret;
-
- adr += chip->start;
-
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
-- timeo = jiffies + HZ;
--retry:
- spin_lock(chip->mutex);
--
-- /* Check that the chip's ready to talk to us. */
-- switch (chip->state) {
-- case FL_CFI_QUERY:
-- case FL_JEDEC_QUERY:
-- case FL_READY:
-- cfi_write(map, CMD(0x70), adr);
-- chip->state = FL_STATUS;
--
-- case FL_STATUS:
-- status = cfi_read(map, adr);
-- if ((status & status_OK) == status_OK)
-- break;
--
-- /* Urgh. Chip not yet ready to talk to us. */
-- if (time_after(jiffies, timeo)) {
-- spin_unlock(chip->mutex);
-- printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__);
-- return -EIO;
-- }
--
-- /* Latency issues. Drop the lock, wait a while and retry */
-- spin_unlock(chip->mutex);
-- cfi_udelay(1);
-- goto retry;
--
-- default:
-- /* Stick ourselves on a wait queue to be woken when
-- someone changes the status */
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ ret = get_chip(map, chip, adr, FL_LOCKING);
-+ if (ret) {
- spin_unlock(chip->mutex);
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
-- timeo = jiffies + HZ;
-- goto retry;
-+ return ret;
- }
-
- ENABLE_VPP(map);
-@@ -1823,8 +1552,7 @@
-
- /* Done and happy. */
- chip->state = FL_STATUS;
-- DISABLE_VPP(map);
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- return 0;
- }
-@@ -1889,22 +1617,23 @@
-
- spin_lock(chip->mutex);
-
-- switch(chip->state) {
-+ switch (chip->state) {
- case FL_READY:
- case FL_STATUS:
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
-+ if (chip->oldstate == FL_READY) {
- chip->oldstate = chip->state;
- chip->state = FL_PM_SUSPENDED;
- /* No need to wake_up() on this state change -
- * as the whole point is that nobody can do anything
- * with the chip now anyway.
- */
-- case FL_PM_SUSPENDED:
-+ }
- break;
--
- default:
- ret = -EAGAIN;
-+ case FL_PM_SUSPENDED:
- break;
- }
- spin_unlock(chip->mutex);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c linux/drivers/mtd/chips/cfi_cmdset_0002.c
---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-19 10:25:11.745223200 +0100
-@@ -6,16 +6,22 @@
- *
- * 2_by_8 routines added by Simon Munton
- *
-+ * 4_by_16 work by Carolyn J. Smith
-+ *
-+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
-+ *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- *
- */
-
-+#include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
-@@ -23,16 +29,50 @@
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/cfi.h>
-
- #define AMD_BOOTLOC_BUG
-+#define FORCE_WORD_WRITE 0
-+
-+
-+/*
-+ * This is an attempt to coalesce the retry logic in one place - that way
-+ * there aren't #ifdefs scattered throughout.
-+ */
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+
-+#ifndef CONFIG_MTD_CFI_AMDSTD_RETRY_MAX
-+#define CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0
-+#endif
-+
-+#define RETRY_CMD_LABEL retry_cmd: do {} while (0)
-+#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, retry_cmd_cnt, adr, datum, prev_oldstatus, prev_status, oldstatus, status)
-+static int retry_cmd_max = CONFIG_MTD_CFI_AMDSTD_RETRY_MAX;
-+#define DECLARE_RETRY_CMD_CNT() int retry_cmd_cnt = 0
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+#define CHECK_RETRIES() do { if (++retry_cmd_cnt <= retry_cmd_max) goto retry_cmd; } while (0)
-+#endif
-+
-+#else
-+
-+#define RETRY_CMD_LABEL do {} while (0)
-+#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, adr, datum, prev_oldstatus, prev_status, oldstatus, status)
-+#define DECLARE_RETRY_CMD_CNT()
-+#define CHECK_RETRIES()
-+
-+#endif /* !defined(CONFIG_MTD_CFI_AMDSTD_RETRY) */
-+
-
- static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-+static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-+static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
- static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
--static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
- static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
-+static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t);
-+static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t);
- static void cfi_amdstd_sync (struct mtd_info *);
- static int cfi_amdstd_suspend (struct mtd_info *);
- static void cfi_amdstd_resume (struct mtd_info *);
-@@ -45,55 +85,136 @@
-
-
- static struct mtd_chip_driver cfi_amdstd_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_amdstd_destroy,
-- name: "cfi_cmdset_0002",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_amdstd_destroy,
-+ .name = "cfi_cmdset_0002",
-+ .module = THIS_MODULE
- };
-
--struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
-+
-+/* #define DEBUG_LOCK_BITS */
-+/* #define DEBUG_CFI_FEATURES */
-+
-+
-+#ifdef DEBUG_CFI_FEATURES
-+static void cfi_tell_features(struct cfi_pri_amdstd *extp)
- {
-- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned char bootloc;
-- int ofs_factor = cfi->interleave * cfi->device_type;
-- int i;
-- __u8 major, minor;
-- __u32 base = cfi->chips[0].start;
-+ const char* erase_suspend[3] = {
-+ "Not supported", "Read only", "Read/write"
-+ };
-+ const char* top_bottom[6] = {
-+ "No WP", "8x8KiB sectors at top & bottom, no WP",
-+ "Bottom boot", "Top boot",
-+ "Uniform, Bottom WP", "Uniform, Top WP"
-+ };
-+
-+ printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1);
-+ printk(" Address sensitive unlock: %s\n",
-+ (extp->SiliconRevision & 1) ? "Not required" : "Required");
-
-- if (cfi->cfi_mode==CFI_MODE_CFI){
-- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
-+ if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
-+ printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
-+ else
-+ printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
-
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-+ if (extp->BlkProt == 0)
-+ printk(" Block protection: Not supported\n");
-+ else
-+ printk(" Block protection: %d sectors per group\n", extp->BlkProt);
-+
-+
-+ printk(" Temporary block unprotect: %s\n",
-+ extp->TmpBlkUnprotect ? "Supported" : "Not supported");
-+ printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
-+ printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps);
-+ printk(" Burst mode: %s\n",
-+ extp->BurstMode ? "Supported" : "Not supported");
-+ if (extp->PageMode == 0)
-+ printk(" Page mode: Not supported\n");
-+ else
-+ printk(" Page mode: %d word page\n", extp->PageMode << 2);
-
-- major = cfi_read_query(map, base + (adr+3)*ofs_factor);
-- minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
-+ printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
-+ extp->VppMin >> 4, extp->VppMin & 0xf);
-+ printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
-+ extp->VppMax >> 4, extp->VppMax & 0xf);
-
-- printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
-- major, minor, adr);
-- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
--
-- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
-- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
-- cfi->mfr = cfi_read_query(map, base);
-- cfi->id = cfi_read_query(map, base + ofs_factor);
-+ if (extp->TopBottom < ARRAY_SIZE(top_bottom))
-+ printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
-+ else
-+ printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
-+}
-+#endif
-
-- /* Wheee. Bring me the head of someone at AMD. */
- #ifdef AMD_BOOTLOC_BUG
-+/* Wheee. Bring me the head of someone at AMD. */
-+static void fixup_amd_bootblock(struct map_info *map, void* param)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
-+ __u8 major = extp->MajorVersion;
-+ __u8 minor = extp->MinorVersion;
-+
- if (((major << 8) | minor) < 0x3131) {
- /* CFI version 1.0 => don't trust bootloc */
- if (cfi->id & 0x80) {
- printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
-- bootloc = 3; /* top boot */
-+ extp->TopBottom = 3; /* top boot */
- } else {
-- bootloc = 2; /* bottom boot */
-+ extp->TopBottom = 2; /* bottom boot */
- }
-- } else
-+ }
-+}
- #endif
-+
-+static struct cfi_fixup fixup_table[] = {
-+#ifdef AMD_BOOTLOC_BUG
- {
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-- bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
-+ 0x0001, /* AMD */
-+ CFI_ID_ANY,
-+ fixup_amd_bootblock, NULL
-+ },
-+#endif
-+ { 0, 0, NULL, NULL }
-+};
-+
-+
-+struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ unsigned char bootloc;
-+ int i;
-+
-+ if (cfi->cfi_mode==CFI_MODE_CFI){
-+ /*
-+ * It's a real CFI chip, not one for which the probe
-+ * routine faked a CFI structure. So we read the feature
-+ * table from it.
-+ */
-+ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
-+ struct cfi_pri_amdstd *extp;
-+
-+ extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
-+ if (!extp)
-+ return NULL;
-+
-+ /* Install our own private info structure */
-+ cfi->cmdset_priv = extp;
-+
-+ cfi_fixup(map, fixup_table);
-+
-+#ifdef DEBUG_CFI_FEATURES
-+ /* Tell the user about it in lots of lovely detail */
-+ cfi_tell_features(extp);
-+#endif
-+
-+ bootloc = extp->TopBottom;
-+ if ((bootloc != 2) && (bootloc != 3)) {
-+ printk(KERN_WARNING "%s: CFI does not contain boot "
-+ "bank location. Assuming top.\n", map->name);
-+ bootloc = 2;
- }
-+
- if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
- printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
-
-@@ -106,6 +227,11 @@
- cfi->cfiq->EraseRegionInfo[j] = swap;
- }
- }
-+ /*
-+ * These might already be setup (more correctly) by
-+ * jedec_probe.c - still need it for cfi_probe.c path.
-+ */
-+ if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) {
- switch (cfi->device_type) {
- case CFI_DEVICETYPE_X8:
- cfi->addr_unlock1 = 0x555;
-@@ -125,9 +251,13 @@
- cfi->addr_unlock2 = 0xaaa;
- break;
- default:
-- printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
-+ printk(KERN_WARNING
-+ "MTD %s(): Unsupported device type %d\n",
-+ __func__, cfi->device_type);
- return NULL;
- }
-+ }
-+
- } /* CFI mode */
-
- for (i=0; i< cfi->numchips; i++) {
-@@ -138,15 +268,17 @@
-
- map->fldrv = &cfi_amdstd_chipdrv;
-
-- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
- return cfi_amdstd_setup(map);
- }
-
-+
- static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
- {
- struct cfi_private *cfi = map->fldrv_priv;
- struct mtd_info *mtd;
- unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
-+ unsigned long offset = 0;
-+ int i,j;
-
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
- printk(KERN_NOTICE "number of %s chips: %d\n",
-@@ -163,15 +295,9 @@
- /* Also select the correct geometry setup too */
- mtd->size = devsize * cfi->numchips;
-
-- if (cfi->cfiq->NumEraseRegions == 1) {
-- /* No need to muck about with multiple erase sizes */
-- mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
-- } else {
-- unsigned long offset = 0;
-- int i,j;
--
- mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
-+ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
-+ * mtd->numeraseregions, GFP_KERNEL);
- if (!mtd->eraseregions) {
- printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
- goto setup_err;
-@@ -206,39 +332,52 @@
- mtd->eraseregions[i].numblocks);
- }
- #endif
-- }
-
- switch (CFIDEV_BUSWIDTH)
- {
- case 1:
- case 2:
- case 4:
--#if 1
-- if (mtd->numeraseregions > 1)
-- mtd->erase = cfi_amdstd_erase_varsize;
-- else
-+#ifdef CFI_WORD_64
-+ case 8:
- #endif
-- if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
-+ if (mtd->numeraseregions == 1
-+ && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) {
- mtd->erase = cfi_amdstd_erase_chip;
-- else
-- mtd->erase = cfi_amdstd_erase_onesize;
-+ } else {
-+ mtd->erase = cfi_amdstd_erase_varsize;
-+ mtd->lock = cfi_amdstd_lock_varsize;
-+ mtd->unlock = cfi_amdstd_unlock_varsize;
-+ }
-+
-+ if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
-+ DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
-+ mtd->write = cfi_amdstd_write_buffers;
-+ } else {
-+ DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" );
-+ mtd->write = cfi_amdstd_write_words;
-+ }
-+
- mtd->read = cfi_amdstd_read;
-- mtd->write = cfi_amdstd_write;
- break;
-
- default:
-- printk(KERN_WARNING "Unsupported buswidth\n");
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
- goto setup_err;
- break;
- }
- if (cfi->fast_prog) {
-- /* In cfi_amdstd_write() we frob the protection stuff
-+ /* In cfi_amdstd_write_words() we frob the protection stuff
- without paying any attention to the state machine.
- This upsets in-progress erases. So we turn this flag
- off for now till the code gets fixed. */
- printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
- cfi->fast_prog = 0;
- }
-+ /* FIXME: erase-suspend-program is broken. See
-+ http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
-+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
-
-
- /* does this chip have a secsi area? */
-@@ -266,7 +405,7 @@
- mtd->flags = MTD_CAP_NORFLASH;
- map->fldrv = &cfi_amdstd_chipdrv;
- mtd->name = map->name;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
-
- setup_err:
-@@ -280,46 +419,210 @@
- return NULL;
- }
-
--static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-+
-+/* This is more work to coalesce the retry #ifdefs in one location */
-+static inline void handle_wacky_state(const char *func,
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+ int retry_cmd_cnt,
-+#endif
-+ unsigned long adr,
-+ cfi_word datum,
-+ cfi_word prev_oldstatus,
-+ cfi_word prev_status,
-+ cfi_word oldstatus,
-+ cfi_word status)
-+{
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+ if ( retry_cmd_cnt == retry_cmd_max ) {
-+#endif
-+ printk(KERN_WARNING
-+ "MTD %s(): Wacky! Unable to decode failure status\n"
-+ "Possible buggy device - try "
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+ "increasing retry_cmd_max from %d\n"
-+#else
-+ "enabling CONFIG_MTD_CFI_AMDSTD_RETRY\n"
-+ "in your kernel config and setting driver retry_cmd_max\n"
-+#endif
-+ , func
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+ , retry_cmd_max
-+#endif
-+ );
-+
-+ printk(KERN_WARNING
-+ "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
-+ func, adr, datum,
-+ prev_oldstatus, prev_status,
-+ oldstatus, status);
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+ }
-+#endif
-+}
-+
-+
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
- {
- DECLARE_WAITQUEUE(wait, current);
-- unsigned long timeo = jiffies + HZ;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ cfi_word status, oldstatus;
-+ cfi_word dq6 = CMD(1<<6);
-+ cfi_word dq2 = CMD(1<<2);
-+ unsigned long timeo;
-+ struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
-
-+ resettime:
-+ timeo = jiffies + HZ;
- retry:
-+ switch (chip->state) {
-+
-+ case FL_STATUS:
-+ for (;;) {
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ if (((oldstatus ^ status) & (dq6 | dq2)) == 0)
-+ break;
-+
-+ if (time_after(jiffies, timeo)) {
-+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n",
-+ (long long)status);
-+ cfi_spin_unlock(chip->mutex);
-+ return -EIO;
-+ }
-+ cfi_spin_unlock(chip->mutex);
-+ cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
-+ /* Someone else might have been playing with it. */
-+ goto retry;
-+ }
-
-- if (chip->state != FL_READY){
--#if 0
-- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
--#endif
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ case FL_READY:
-+ case FL_CFI_QUERY:
-+ case FL_JEDEC_QUERY:
-+ return 0;
-+
-+ case FL_ERASING:
-+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
-+ goto sleep;
-+
-+ if (!(mode == FL_READY || mode == FL_POINT
-+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
-+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
-+ goto sleep;
-+
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ if ((oldstatus ^ status) & dq2) {
-+ printk(KERN_ERR "Can't suspend erase -- block in progress\n");
-+ goto sleep;
-+ }
-+
-+ /* Erase suspend */
-+ /* FIXME - is there a way to verify suspend? */
-+ cfi_write(map, CMD(0xB0), chip->in_progress_block_addr);
-+ chip->oldstate = FL_ERASING;
-+ chip->state = FL_ERASE_SUSPENDING;
-+ chip->erase_suspended = 1;
-+ for (;;) {
-+ oldstatus = cfi_read(map, chip->in_progress_block_addr);
-+ status = cfi_read(map, chip->in_progress_block_addr);
-+ if (((oldstatus ^ status) & dq6) == 0)
-+ break;
-+
-+ if (time_after(jiffies, timeo)) {
-+ /* Urgh. Resume and pretend we weren't here. */
-+ /* FIXME - is there a way to verify resume? */
-+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
-+ chip->state = FL_ERASING;
-+ chip->oldstate = FL_READY;
-+ printk(KERN_ERR "Chip not ready after erase "
-+ "suspended: status = 0x%x\n", status);
-+ return -EIO;
-+ }
-
- cfi_spin_unlock(chip->mutex);
-+ cfi_udelay(1);
-+ cfi_spin_lock(chip->mutex);
-+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
-+ So we can just loop here. */
-+ }
-+ chip->state = FL_READY;
-+ return 0;
-+
-+ case FL_POINT:
-+ /* Only if there's no operation suspended... */
-+ if (mode == FL_READY && chip->oldstate == FL_READY)
-+ return 0;
-
-+ default:
-+ sleep:
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ cfi_spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
-+ cfi_spin_lock(chip->mutex);
-+ goto resettime;
-+ }
-+}
-
-- goto retry;
-+
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+
-+ switch(chip->oldstate) {
-+ case FL_ERASING:
-+ chip->state = chip->oldstate;
-+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
-+ chip->oldstate = FL_READY;
-+ chip->state = FL_ERASING;
-+ break;
-+
-+ case FL_READY:
-+ case FL_STATUS:
-+ /* We should really make set_vpp() count, rather than doing this */
-+ DISABLE_VPP(map);
-+ break;
-+ default:
-+ printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
- }
-+ wake_up(&chip->wq);
-+}
-+
-+
-+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
-+{
-+ unsigned long cmd_addr;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ret;
-
- adr += chip->start;
-
-+ /* Ensure cmd read/writes are aligned. */
-+ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
-+
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, cmd_addr, FL_READY);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-+
-+ if (chip->state != FL_POINT && chip->state != FL_READY) {
-+ cfi_write(map, CMD(0xf0), cmd_addr);
- chip->state = FL_READY;
-+ }
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-+ put_chip(map, chip, cmd_addr);
-
-+ cfi_spin_unlock(chip->mutex);
- return 0;
- }
-
-+
- static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
- {
- struct map_info *map = mtd->priv;
-@@ -361,6 +664,7 @@
- return ret;
- }
-
-+
- static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
- {
- DECLARE_WAITQUEUE(wait, current);
-@@ -394,12 +698,14 @@
-
- chip->state = FL_READY;
-
-+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
-+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-@@ -454,125 +760,241 @@
- return ret;
- }
-
--static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
-+
-+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast)
- {
-- unsigned long timeo = jiffies + HZ;
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
- struct cfi_private *cfi = map->fldrv_priv;
-- DECLARE_WAITQUEUE(wait, current);
-+ unsigned long timeo = jiffies + HZ;
-+ cfi_word oldstatus, status, prev_oldstatus, prev_status;
-+ cfi_word dq6 = CMD(1<<6);
-+ /*
-+ * We use a 1ms + 1 jiffies generic timeout for writes (most devices
-+ * have a max write time of a few hundreds usec). However, we should
-+ * use the maximum timeout value given by the chip at probe time
-+ * instead. Unfortunately, struct flchip does have a field for
-+ * maximum timeout, only for typical which can be far too short
-+ * depending of the conditions. The ' + 1' is to avoid having a
-+ * timeout of 0 jiffies if HZ is smaller than 1000.
-+ */
-+ unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
- int ret = 0;
-+ int ta = 0;
-+ DECLARE_RETRY_CMD_CNT();
-
-- retry:
-- cfi_spin_lock(chip->mutex);
--
-- if (chip->state != FL_READY) {
--#if 0
-- printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
--#endif
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ adr += chip->start;
-
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- cfi_spin_unlock(chip->mutex);
--
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- printk(KERN_DEBUG "Wake up to write:\n");
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
--
-- goto retry;
-+ return ret;
- }
-
-- chip->state = FL_WRITING;
-+ RETRY_CMD_LABEL;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
-+ __func__, adr, datum );
-+
-+ /*
-+ * Check for a NOP for the case when the datum to write is already
-+ * present - it saves time and works around buggy chips that corrupt
-+ * data at other locations when 0xff is written to a location that
-+ * already contains 0xff.
-+ */
-+ status = cfi_read(map, adr);
-+ if (status == datum) {
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP 0x%.8x == 0x%.8x\n",
-+ __func__, status, datum );
-+ goto op_done;
-+ }
-
-- adr += chip->start;
- ENABLE_VPP(map);
- if (fast) { /* Unlock bypass */
- cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-- }
-- else {
-+ } else {
-+ /*
-+ * The CFI_DEVICETYPE_X8 argument is needed even when
-+ * cfi->device_type != CFI_DEVICETYPE_X8. The addresses for
-+ * command sequences don't scale even when the device is
-+ * wider. This is the case for many of the cfi_send_gen_cmd()
-+ * below. I'm not sure, however, why some use
-+ * cfi->device_type.
-+ */
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
--
- cfi_write(map, datum, adr);
-+ chip->state = FL_WRITING;
-
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(chip->word_write_time);
- cfi_spin_lock(chip->mutex);
-
-- /* Polling toggle bits instead of reading back many times
-- This ensures that write operation is really completed,
-- or tells us why it failed. */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-- timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */
-+ /*
-+ * Polling toggle bits instead of reading back many times This ensures
-+ * that write operation is really completed, or tells us why it
-+ * failed.
-+ *
-+ * It may appear that the polling and decoding of error state might be
-+ * simplified. Don't do it unless you really know what you are doing.
-+ *
-+ * You must remember that JESD21-C 3.5.3 states that the status must
-+ * be read back an _additional_ two times before a failure is
-+ * determined. This is because these devices have internal state
-+ * machines that are asynchronous to the external data bus. During an
-+ * erase or write the read-back status of the polling bits might be
-+ * transitioning internaly when the external read-back occurs. This
-+ * means that the bits aren't in the final state and they might appear
-+ * to report an error as they are in a transient state: dq7 is
-+ * asynchronous with dq6 and other status bits.
-+ *
-+ * This asynchronous behaviour can cause infrequent errors that will
-+ * usually disappear the next time an erase or write happens (Try
-+ * tracking those errors down!). To ensure that the bits are not in
-+ * transition, the location must be read-back two more times and
-+ * compared against what was written - BOTH reads MUST match what was
-+ * written. Don't think this can be simplified to only the last read
-+ * matching the datum written: status bits *can* match the datum
-+ * written.
-+ *
-+ * If the final comparison fails, error state can *then* be decoded.
-+ *
-+ * - Thayne Harbaugh
-+ */
-+ /* See comment above for timeout value. */
-+ timeo = jiffies + uWriteTimeout;
-+ for (;;) {
-+ if (chip->state != FL_WRITING) {
-+ /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ cfi_spin_unlock(chip->mutex);
-+ schedule();
-+ remove_wait_queue(&chip->wq, &wait);
-+ timeo = jiffies + (HZ / 2); /* FIXME */
-+ cfi_spin_lock(chip->mutex);
-+ continue;
-+ }
-
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-
-- while( (status & dq6) != (oldstatus & dq6) &&
-- (status & dq5) != dq5 &&
-- !time_after(jiffies, timeo) ) {
-+ /*
-+ * This only checks if dq6 is still toggling and that our
-+ * timer hasn't expired. We purposefully ignore the chip's
-+ * internal timer that will assert dq5 and leave dq6 toggling.
-+ * This is done for a variety of reasons:
-+ *
-+ * 1) Not all chips support dq5.
-+ *
-+ * 2) Dealing with asynchronous status bit and data updates
-+ * and reading a device two more times creates _messy_ logic
-+ * when trying to deal with interleaved devices - some may be
-+ * changing while others are still busy.
-+ *
-+ * 3) Checking dq5 only helps to optimize an error case that
-+ * should at worst be infrequent and at best non-existent.
-+ *
-+ * If our timeout occurs _then_ we will check dq5 to see if
-+ * the device also had an internal timeout.
-+ */
-+ if ( (((status ^ oldstatus) & dq6) == 0)
-+ || ( ta = time_after(jiffies, timeo)) )
-+ break;
-
-- if (need_resched()) {
-+ /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
-- yield();
-+ cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
-- } else
-- udelay(1);
--
-- oldstatus = cfi_read( map, adr );
-- status = cfi_read( map, adr );
- }
-
-- if( (status & dq6) != (oldstatus & dq6) ) {
-- /* The erasing didn't stop?? */
-- if( (status & dq5) == dq5 ) {
-- /* When DQ5 raises, we must check once again
-- if DQ6 is toggling. If not, the erase has been
-- completed OK. If not, reset chip. */
-+ /*
-+ * Something kicked us out of the read-back loop. We'll check success
-+ * befor checking failure. Even though dq6 might be true data, it is
-+ * unkown if all of the other bits have changed to true data due to
-+ * the asynchronous nature of the internal state machine. We will
-+ * read two more times and use this to either verify that the write
-+ * completed successfully or that something really went wrong. BOTH
-+ * reads must match what was written - this certifies that bits aren't
-+ * still changing and that the status bits erroneously match the datum
-+ * that was written.
-+ */
-+ prev_oldstatus = oldstatus;
-+ prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-
-- if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
-- printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
-+ if ( oldstatus == datum && status == datum ) {
-+ /* success - do nothing */
-+ goto op_done;
-+ }
-+
-+ if ( ta ) {
-+ /* Only check dq5 on the chips that are still toggling. */
-+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-+ if ( status & dq5mask ) {
-+ /* dq5 asserted - decode interleave chips */
-+ printk( KERN_WARNING
-+ "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n",
-+ __func__,
-+ status & dq5mask, status, datum );
- } else {
-- /* DQ5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-- printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
-+ printk( KERN_WARNING
-+ "MTD %s(): Software timed out during write.\n",
-+ __func__ );
-+ }
-+ goto op_failed;
- }
-- } else {
-- printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");
-
-+ /*
-+ * If we get to here then it means that something
-+ * is wrong and it's not a timeout. Something
-+ * is seriously wacky! Dump some debug info.
-+ */
-+ /*
-+ * Found a clue about the chips that reach this state.
-+ * Some flash chips (SST >cough<)
-+ * are horribly broken. They do not ignore traffic that is
-+ * destined to other devices. This happens because some solutions
-+ * are on shared busses, the erase and program sequences have
-+ * have multiple commands, and the sequence is interspersed with
-+ * commands destined to other devices. A good flash chip will
-+ * examine the command and destination address and will ignore
-+ * commands that are for other devices.
-+ */
-+ HANDLE_WACKY_STATE();
-+
-+ op_failed:
-+ /* reset on all failures. */
-+ cfi_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+ CHECK_RETRIES();
-+ ret = -EIO;
-+
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-- DISABLE_VPP(map);
-- ret = -EIO;
-- }
-- }
--
-- DISABLE_VPP(map);
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-
- return ret;
- }
-
--static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
-+
-+static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- int ret = 0;
- int chipnum;
- unsigned long ofs, chipstart;
-+ DECLARE_WAITQUEUE(wait, current);
-
- *retlen = 0;
- if (!len)
-@@ -587,19 +1009,52 @@
- unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
- int i = ofs - bus_ofs;
- int n = 0;
-- u_char tmp_buf[4];
-- __u32 datum;
-+ u_char tmp_buf[8];
-+ cfi_word datum;
-+
-+ retry:
-+ cfi_spin_lock(cfi->chips[chipnum].mutex);
-+
-+ if (cfi->chips[chipnum].state != FL_READY) {
-+#if 0
-+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
-+#endif
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ schedule();
-+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+#if 0
-+ if(signal_pending(current))
-+ return -EINTR;
-+#endif
-+ goto retry;
-+ }
-+
-+ map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-
-- map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-- while (len && i < CFIDEV_BUSWIDTH)
-- tmp_buf[i++] = buf[n++], len--;
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ while (len && i < CFIDEV_BUSWIDTH) {
-+ tmp_buf[i++] = buf[n++];
-+ len--;
-+ }
-
-+ /* already know that buswidth > 1 */
- if (cfi_buswidth_is_2()) {
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *(__u64*)tmp_buf;
-+#endif
- } else {
-- return -EINVAL; /* should never happen, but be safe */
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ return -EINVAL;
- }
-
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-@@ -628,7 +1083,7 @@
-
- /* We are now aligned, write as much as possible */
- while(len >= CFIDEV_BUSWIDTH) {
-- __u32 datum;
-+ cfi_word datum;
-
- if (cfi_buswidth_is_1()) {
- datum = *(__u8*)buf;
-@@ -636,7 +1091,13 @@
- datum = *(__u16*)buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)buf;
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *(__u64*)buf;
-+#endif
- } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
- return -EINVAL;
- }
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-@@ -685,10 +1146,34 @@
- /* Write the trailing bytes if any */
- if (len & (CFIDEV_BUSWIDTH-1)) {
- int i = 0, n = 0;
-- u_char tmp_buf[4];
-- __u32 datum;
-+ u_char tmp_buf[8];
-+ cfi_word datum;
-+
-+ retry1:
-+ cfi_spin_lock(cfi->chips[chipnum].mutex);
-+
-+ if (cfi->chips[chipnum].state != FL_READY) {
-+#if 0
-+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
-+#endif
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+ schedule();
-+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
-+#if 0
-+ if(signal_pending(current))
-+ return -EINTR;
-+#endif
-+ goto retry1;
-+ }
-+
-+ map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-+
-+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
-
-- map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
- while (len--)
- tmp_buf[i++] = buf[n++];
-
-@@ -696,8 +1181,14 @@
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *(__u64*)tmp_buf;
-+#endif
- } else {
-- return -EINVAL; /* should never happen, but be safe */
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ return -EINVAL;
- }
-
- ret = do_write_oneword(map, &cfi->chips[chipnum],
-@@ -711,289 +1202,446 @@
- return 0;
- }
-
--static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
-+
-+/*
-+ * FIXME: interleaved mode not tested, and probably not supported!
-+ */
-+static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, const u_char *buf, int len)
- {
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
-- unsigned long timeo = jiffies + HZ;
-- unsigned int adr;
- struct cfi_private *cfi = map->fldrv_priv;
-- DECLARE_WAITQUEUE(wait, current);
--
-- retry:
-- cfi_spin_lock(chip->mutex);
-+ unsigned long timeo = jiffies + HZ;
-+ cfi_word oldstatus, status, prev_oldstatus, prev_status;
-+ cfi_word dq6 = CMD(1<<6);
-+ /* see comments in do_write_oneword() regarding uWriteTimeo. */
-+ static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
-+ int ret = -EIO;
-+ int ta = 0;
-+ unsigned long cmd_adr;
-+ int z, bytes, words;
-+ cfi_word datum;
-+ DECLARE_RETRY_CMD_CNT();
-
-- if (chip->state != FL_READY){
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ adr += chip->start;
-+ cmd_adr = adr;
-
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
-+ if (cfi_buswidth_is_1()) {
-+ datum = *(__u8*)buf;
-+ } else if (cfi_buswidth_is_2()) {
-+ datum = *(__u16*)buf;
-+ } else if (cfi_buswidth_is_4()) {
-+ datum = *(__u32*)buf;
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *(__u64*)buf;
- #endif
-- timeo = jiffies + HZ;
--
-- goto retry;
-+ } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ return -EINVAL;
- }
-
-- chip->state = FL_ERASING;
-+ RETRY_CMD_LABEL;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
-+ __func__, adr, datum );
-
-- /* Handle devices with one erase region, that only implement
-- * the chip erase command.
-- */
- ENABLE_VPP(map);
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- timeo = jiffies + (HZ*20);
-- adr = cfi->addr_unlock1;
-+ //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-
-- /* Wait for the end of programing/erasure by using the toggle method.
-- * As long as there is a programming procedure going on, bit 6 of the last
-- * written byte is toggling it's state with each consectuve read.
-- * The toggling stops as soon as the procedure is completed.
-- *
-- * If the process has gone on for too long on the chip bit 5 gets.
-- * After bit5 is set you can kill the operation by sending a reset
-- * command to the chip.
-- */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-+ /* Write Buffer Load */
-+ cfi_write(map, CMD(0x25), cmd_adr);
-
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- while( ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5) &&
-- !time_after(jiffies, timeo)) {
-- int wait_reps;
-+ chip->state = FL_WRITING_TO_BUFFER;
-+
-+ /* Write length of data to come */
-+ bytes = len & (CFIDEV_BUSWIDTH-1);
-+ words = len / CFIDEV_BUSWIDTH;
-+ cfi_write(map, CMD(words - !bytes), cmd_adr );
-+ /* Write data */
-+ z = 0;
-+ while(z < words * CFIDEV_BUSWIDTH) {
-+ if (cfi_buswidth_is_1()) {
-+ datum = *((__u8*)buf);
-+ map_write8 (map, *((__u8*)buf)++, adr+z);
-+ } else if (cfi_buswidth_is_2()) {
-+ datum = *((__u16*)buf);
-+ map_write16 (map, *((__u16*)buf)++, adr+z);
-+ } else if (cfi_buswidth_is_4()) {
-+ datum = *((__u32*)buf);
-+ map_write32 (map, *((__u32*)buf)++, adr+z);
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *((__u64*)buf);
-+ map_write64 (map, *((__u64*)buf)++, adr+z);
-+#endif
-+ } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ ret = -EINVAL;
-+ goto op_failed;
-+ }
-+ z += CFIDEV_BUSWIDTH;
-+ }
-+ if (bytes) {
-+ int i = 0, n = 0;
-+ u_char tmp_buf[8], *tmp_p = tmp_buf;
-+
-+ while (bytes--)
-+ tmp_buf[i++] = buf[n++];
-+ while (i < CFIDEV_BUSWIDTH)
-+ tmp_buf[i++] = 0xff;
-+ if (cfi_buswidth_is_2()) {
-+ datum = *((__u16*)tmp_p);
-+ map_write16 (map, *((__u16*)tmp_p)++, adr+z);
-+ } else if (cfi_buswidth_is_4()) {
-+ datum = *((__u32*)tmp_p);
-+ map_write32 (map, *((__u32*)tmp_p)++, adr+z);
-+#ifdef CFI_WORD_64
-+ } else if (cfi_buswidth_is_8()) {
-+ datum = *((__u64*)tmp_p);
-+ map_write64 (map, *((__u64*)tmp_p)++, adr+z);
-+#endif
-+ } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ ret = -EINVAL;
-+ goto op_failed;
-+ }
-+ } else if (words > 0) {
-+ z -= CFIDEV_BUSWIDTH;
-+ }
-+
-+ adr += z;
-+
-+ /* Write Buffer Program Confirm: GO GO GO */
-+ cfi_write(map, CMD(0x29), cmd_adr);
-+ chip->state = FL_WRITING;
-
-- /* an initial short sleep */
- cfi_spin_unlock(chip->mutex);
-- schedule_timeout(HZ/100);
-+ cfi_udelay(chip->buffer_write_time);
- cfi_spin_lock(chip->mutex);
-
-- if (chip->state != FL_ERASING) {
-- /* Someone's suspended the erase. Sleep */
-+ timeo = jiffies + uWriteTimeout;
-+
-+ for (;;) {
-+ if (chip->state != FL_WRITING) {
-+ /* Someone's suspended the write. Sleep */
-+ DECLARE_WAITQUEUE(wait, current);
-+
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
--
- cfi_spin_unlock(chip->mutex);
-- printk("erase suspended. Sleeping\n");
--
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if (signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + (HZ*2); /* FIXME */
-+ timeo = jiffies + (HZ / 2); /* FIXME */
- cfi_spin_lock(chip->mutex);
- continue;
- }
-
-- /* Busy wait for 1/10 of a milisecond */
-- for(wait_reps = 0;
-- (wait_reps < 100) &&
-- ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5);
-- wait_reps++) {
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-+
-+ /* See comments in do_write_oneword() about checking status */
-+ if ( (((status ^ oldstatus) & dq6) == 0)
-+ || ( ta = time_after(jiffies, timeo)) ) {
-+ break;
-+ }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
--
- cfi_udelay(1);
--
- cfi_spin_lock(chip->mutex);
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
- }
-+
-+ /* See comments in do_write_oneword() about "two more checks" */
-+ prev_oldstatus = oldstatus;
-+ prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-+
-+ if ( oldstatus == datum && status == datum ) {
-+ /* success - do nothing */
-+ goto op_done;
-+ }
-+
-+ if ( ta ) {
-+ /* Only check dq5 on the chips that are still toggling. */
-+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-+ if ( status & dq5mask ) {
-+ /* dq5 asserted - decode interleave chips */
-+ printk( KERN_WARNING
-+ "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n",
-+ __func__,
-+ status & dq5mask, status, datum );
-+ } else {
-+ printk( KERN_WARNING
-+ "MTD %s(): Software timed out during write.\n",
-+ __func__ );
- }
-- if ((status & dq6) != (oldstatus & dq6)) {
-- /* The erasing didn't stop?? */
-- if ((status & dq5) == dq5) {
-- /* dq5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-+ goto op_failed;
- }
-+
-+ HANDLE_WACKY_STATE();
-+
-+ op_failed:
-+ /* reset on all failures. */
-+ cfi_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+ CHECK_RETRIES();
-+ ret = -EIO;
-+
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-- printk("waiting for erase to complete timed out.");
-- DISABLE_VPP(map);
-- return -EIO;
-+
-+ return ret;
-+}
-+
-+
-+static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ struct map_info *map = mtd->priv;
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
-+ int ret = 0;
-+ int chipnum;
-+ unsigned long ofs;
-+
-+ *retlen = 0;
-+ if (!len)
-+ return 0;
-+
-+ chipnum = to >> cfi->chipshift;
-+ ofs = to - (chipnum << cfi->chipshift);
-+
-+ /* If it's not bus-aligned, do the first word write */
-+ if (ofs & (CFIDEV_BUSWIDTH-1)) {
-+ size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1);
-+ if (local_len > len)
-+ local_len = len;
-+ ret = cfi_amdstd_write_words(mtd, to, local_len,
-+ retlen, buf);
-+ if (ret)
-+ return ret;
-+ ofs += local_len;
-+ buf += local_len;
-+ len -= local_len;
-+
-+ if (ofs >> cfi->chipshift) {
-+ chipnum ++;
-+ ofs = 0;
-+ if (chipnum == cfi->numchips)
-+ return 0;
-+ }
-+ }
-+
-+ /* Write buffer is worth it only if more than one word to write... */
-+ while (len) {
-+ /* We must not cross write block boundaries */
-+ int size = wbufsize - (ofs & (wbufsize-1));
-+
-+ if (size > len)
-+ size = len;
-+ ret = do_write_buffer(map, &cfi->chips[chipnum],
-+ ofs, buf, size);
-+ if (ret)
-+ return ret;
-+
-+ ofs += size;
-+ buf += size;
-+ (*retlen) += size;
-+ len -= size;
-+
-+ if (ofs >> cfi->chipshift) {
-+ chipnum ++;
-+ ofs = 0;
-+ if (chipnum == cfi->numchips)
-+ return 0;
-+ }
- }
-- DISABLE_VPP(map);
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-
- return 0;
- }
-
--static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
-+
-+/*
-+ * Handle devices with one erase region, that only implement
-+ * the chip erase command.
-+ */
-+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
- {
-- unsigned int oldstatus, status;
-- unsigned int dq6, dq5;
-- unsigned long timeo = jiffies + HZ;
- struct cfi_private *cfi = map->fldrv_priv;
-+ cfi_word oldstatus, status, prev_oldstatus, prev_status;
-+ cfi_word dq6 = CMD(1<<6);
-+ unsigned long timeo = jiffies + HZ;
-+ unsigned long int adr;
- DECLARE_WAITQUEUE(wait, current);
-+ int ret = 0;
-+ int ta = 0;
-+ cfi_word datum = 0;
-+ DECLARE_RETRY_CMD_CNT();
-
-- retry:
-- cfi_spin_lock(chip->mutex);
--
-- if (chip->state != FL_READY){
-- set_current_state(TASK_UNINTERRUPTIBLE);
-- add_wait_queue(&chip->wq, &wait);
-+ adr = cfi->addr_unlock1;
-
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_WRITING);
-+ if (ret) {
- cfi_spin_unlock(chip->mutex);
--
-- schedule();
-- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if(signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + HZ;
--
-- goto retry;
-+ return ret;
- }
-
-- chip->state = FL_ERASING;
-+ RETRY_CMD_LABEL;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-+ __func__, chip->start );
-
-- adr += chip->start;
- ENABLE_VPP(map);
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-- cfi_write(map, CMD(0x30), adr);
--
-- timeo = jiffies + (HZ*20);
--
-- /* Wait for the end of programing/erasure by using the toggle method.
-- * As long as there is a programming procedure going on, bit 6 of the last
-- * written byte is toggling it's state with each consectuve read.
-- * The toggling stops as soon as the procedure is completed.
-- *
-- * If the process has gone on for too long on the chip bit 5 gets.
-- * After bit5 is set you can kill the operation by sending a reset
-- * command to the chip.
-- */
-- dq6 = CMD(1<<6);
-- dq5 = CMD(1<<5);
-+ cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
-- while( ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5) &&
-- !time_after(jiffies, timeo)) {
-- int wait_reps;
-+ chip->state = FL_ERASING;
-+ chip->erase_suspended = 0;
-+ chip->in_progress_block_addr = adr;
-
-- /* an initial short sleep */
- cfi_spin_unlock(chip->mutex);
-- schedule_timeout(HZ/100);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout((chip->erase_time*HZ)/(2*1000));
- cfi_spin_lock(chip->mutex);
-
-+ timeo = jiffies + (HZ*20);
-+
-+ for (;;) {
- if (chip->state != FL_ERASING) {
- /* Someone's suspended the erase. Sleep */
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
--
- cfi_spin_unlock(chip->mutex);
-- printk(KERN_DEBUG "erase suspended. Sleeping\n");
--
- schedule();
- remove_wait_queue(&chip->wq, &wait);
--#if 0
-- if (signal_pending(current))
-- return -EINTR;
--#endif
-- timeo = jiffies + (HZ*2); /* FIXME */
- cfi_spin_lock(chip->mutex);
- continue;
- }
-+ if (chip->erase_suspended) {
-+ /* This erase was suspended and resumed.
-+ Adjust the timeout */
-+ timeo = jiffies + (HZ*20); /* FIXME */
-+ chip->erase_suspended = 0;
-+ }
-
-- /* Busy wait for 1/10 of a milisecond */
-- for(wait_reps = 0;
-- (wait_reps < 100) &&
-- ((status & dq6) != (oldstatus & dq6)) &&
-- ((status & dq5) != dq5);
-- wait_reps++) {
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-+ if ( (((status ^ oldstatus) & dq6) == 0)
-+ || ( ta = time_after(jiffies, timeo)) )
-+ break;
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
--
-- cfi_udelay(1);
--
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(1);
- cfi_spin_lock(chip->mutex);
-- oldstatus = cfi_read(map, adr);
-- status = cfi_read(map, adr);
- }
-+
-+ prev_oldstatus = oldstatus;
-+ prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
-- }
-- if( (status & dq6) != (oldstatus & dq6) )
-- {
-- /* The erasing didn't stop?? */
-- if( ( status & dq5 ) == dq5 )
-- {
-- /* When DQ5 raises, we must check once again if DQ6 is toggling.
-- If not, the erase has been completed OK. If not, reset chip. */
-- oldstatus = cfi_read( map, adr );
-- status = cfi_read( map, adr );
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-
-- if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) )
-- {
-- printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" );
-- }
-- else
-- {
-- /* DQ5 is active so we can do a reset and stop the erase */
-- cfi_write(map, CMD(0xF0), chip->start);
-- printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
-+ if ( cfi_buswidth_is_1() ) {
-+ datum = (__u8)~0;
-+ } else if ( cfi_buswidth_is_2() ) {
-+ datum = (__u16)~0;
-+ } else if ( cfi_buswidth_is_4() ) {
-+ datum = (__u32)~0;
-+#ifdef CFI_WORD_64
-+ } else if ( cfi_buswidth_is_8() ) {
-+ datum = (__u64)~0;
-+#endif
-+ } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ goto op_failed;
-+ }
-+
-+ if ( oldstatus == datum && status == datum ) {
-+ /* success - do nothing */
-+ goto op_done;
-+ }
-+
-+ if ( ta ) {
-+ /* Only check dq5 on the chips that are still toggling. */
-+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-+ if ( status & dq5mask ) {
-+ /* dq5 asserted - decode interleave chips */
-+ printk( KERN_WARNING
-+ "MTD %s(): FLASH internal timeout: 0x%.8x\n",
-+ __func__,
-+ status & dq5mask );
-+ } else {
-+ printk( KERN_WARNING
-+ "MTD %s(): Software timed out during write.\n",
-+ __func__ );
- }
-+ goto op_failed;
- }
-- else
-- {
-- printk( "Waiting for erase to complete timed out in do_erase_oneblock.");
-
-- chip->state = FL_READY;
-- wake_up(&chip->wq);
-- cfi_spin_unlock(chip->mutex);
-- DISABLE_VPP(map);
-- return -EIO;
-- }
-- }
-+ HANDLE_WACKY_STATE();
-
-- DISABLE_VPP(map);
-+ op_failed:
-+ /* reset on all failures. */
-+ cfi_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+ CHECK_RETRIES();
-+ ret = -EIO;
-+
-+ op_done:
- chip->state = FL_READY;
-- wake_up(&chip->wq);
-+ put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
-- return 0;
-+
-+ return ret;
- }
-
--static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-+
-+typedef int (*frob_t)(struct map_info *map, struct flchip *chip,
-+ unsigned long adr, void *thunk);
-+
-+
-+static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob,
-+ loff_t ofs, size_t len, void *thunk)
- {
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned long adr, len;
-+ unsigned long adr;
- int chipnum, ret = 0;
- int i, first;
- struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-- if (instr->addr > mtd->size)
-+ if (ofs > mtd->size)
- return -EINVAL;
-
-- if ((instr->len + instr->addr) > mtd->size)
-+ if ((len + ofs) > mtd->size)
- return -EINVAL;
-
- /* Check that both start and end of the requested erase are
-@@ -1008,7 +1656,7 @@
- start of the requested erase, and then go back one.
- */
-
-- while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
-+ while (i < mtd->numeraseregions && ofs >= regions[i].offset)
- i++;
- i--;
-
-@@ -1018,7 +1666,7 @@
- effect here.
- */
-
-- if (instr->addr & (regions[i].erasesize-1))
-+ if (ofs & (regions[i].erasesize-1))
- return -EINVAL;
-
- /* Remember the erase region we start on */
-@@ -1028,7 +1676,7 @@
- * with the erase region at that address.
- */
-
-- while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
-+ while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
- i++;
-
- /* As before, drop back one to point at the region in which
-@@ -1036,17 +1684,16 @@
- */
- i--;
-
-- if ((instr->addr + instr->len) & (regions[i].erasesize-1))
-+ if ((ofs + len) & (regions[i].erasesize-1))
- return -EINVAL;
-
-- chipnum = instr->addr >> cfi->chipshift;
-- adr = instr->addr - (chipnum << cfi->chipshift);
-- len = instr->len;
-+ chipnum = ofs >> cfi->chipshift;
-+ adr = ofs - (chipnum << cfi->chipshift);
-
- i=first;
-
-- while(len) {
-- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-+ while (len) {
-+ ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
-
- if (ret)
- return ret;
-@@ -1066,50 +1713,171 @@
- }
- }
-
-- instr->state = MTD_ERASE_DONE;
-- if (instr->callback)
-- instr->callback(instr);
--
- return 0;
- }
-
--static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
-+
-+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
- {
-- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
-- unsigned long adr, len;
-- int chipnum, ret = 0;
-+ cfi_word oldstatus, status, prev_oldstatus, prev_status;
-+ cfi_word dq6 = CMD(1<<6);
-+ unsigned long timeo = jiffies + HZ;
-+ DECLARE_WAITQUEUE(wait, current);
-+ int ret = 0;
-+ int ta = 0;
-+ cfi_word datum = 0;
-+ DECLARE_RETRY_CMD_CNT();
-
-- if (instr->addr & (mtd->erasesize - 1))
-- return -EINVAL;
-+ adr += chip->start;
-
-- if (instr->len & (mtd->erasesize -1))
-- return -EINVAL;
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_ERASING);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-
-- if ((instr->len + instr->addr) > mtd->size)
-- return -EINVAL;
-+ RETRY_CMD_LABEL;
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-+ __func__, adr );
-
-- chipnum = instr->addr >> cfi->chipshift;
-- adr = instr->addr - (chipnum << cfi->chipshift);
-- len = instr->len;
-+ ENABLE_VPP(map);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_write(map, CMD(0x30), adr);
-
-- while(len) {
-- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-+ chip->state = FL_ERASING;
-+ chip->erase_suspended = 0;
-+ chip->in_progress_block_addr = adr;
-
-- if (ret)
-- return ret;
-+ cfi_spin_unlock(chip->mutex);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout((chip->erase_time*HZ)/(2*1000));
-+ cfi_spin_lock(chip->mutex);
-
-- adr += mtd->erasesize;
-- len -= mtd->erasesize;
-+ timeo = jiffies + (HZ*20);
-
-- if (adr >> cfi->chipshift) {
-- adr = 0;
-- chipnum++;
-+ /* Wait for the end of programing/erasure by using the toggle method.
-+ * As long as there is a programming procedure going on, bit 6 is
-+ * toggling its state with each consecutive read. The toggling stops
-+ * as soon as the procedure is completed.
-+ *
-+ * If the process has gone on for too long on the chip, bit 5 gets
-+ * set. After bit5 is set you can kill the operation by sending a
-+ * reset command to the chip.
-+ */
-+ /* See comments in do_write_oneword(). */
-
-- if (chipnum >= cfi->numchips)
-+ for (;;) {
-+ if (chip->state != FL_ERASING) {
-+ /* Someone's suspended the erase. Sleep */
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ add_wait_queue(&chip->wq, &wait);
-+ cfi_spin_unlock(chip->mutex);
-+ schedule();
-+ remove_wait_queue(&chip->wq, &wait);
-+ cfi_spin_lock(chip->mutex);
-+ continue;
-+ }
-+ if (chip->erase_suspended) {
-+ /* This erase was suspended and resumed.
-+ Adjust the timeout */
-+ timeo = jiffies + (HZ*20); /* FIXME */
-+ chip->erase_suspended = 0;
-+ }
-+
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-+ if ( (((status ^ oldstatus) & dq6) == 0)
-+ || ( ta = time_after(jiffies, timeo)) )
- break;
-+
-+ /* Latency issues. Drop the lock, wait a while and retry */
-+ cfi_spin_unlock(chip->mutex);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(1);
-+ cfi_spin_lock(chip->mutex);
- }
-+
-+ prev_oldstatus = oldstatus;
-+ prev_status = status;
-+ oldstatus = cfi_read(map, adr);
-+ status = cfi_read(map, adr);
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-+ __func__, oldstatus, status );
-+
-+ if ( cfi_buswidth_is_1() ) {
-+ datum = (__u8)~0;
-+ } else if ( cfi_buswidth_is_2() ) {
-+ datum = (__u16)~0;
-+ } else if ( cfi_buswidth_is_4() ) {
-+ datum = (__u32)~0;
-+#ifdef CFI_WORD_64
-+ } else if ( cfi_buswidth_is_8() ) {
-+ datum = (__u64)~0;
-+#endif
-+ } else {
-+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
-+ __func__, CFIDEV_BUSWIDTH);
-+ goto op_failed;
-+ }
-+
-+ if ( oldstatus == datum && status == datum ) {
-+ /* success - do nothing */
-+ goto op_done;
-+ }
-+
-+ if ( ta ) {
-+ /* Only check dq5 on the chips that are still toggling. */
-+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-+ if ( status & dq5mask ) {
-+ /* dq5 asserted - decode interleave chips */
-+ printk( KERN_WARNING
-+ "MTD %s(): FLASH internal timeout: 0x%.8x\n",
-+ __func__,
-+ status & dq5mask );
-+ } else {
-+ printk( KERN_WARNING
-+ "MTD %s(): Software timed out during write.\n",
-+ __func__ );
- }
-+ goto op_failed;
-+ }
-+
-+ HANDLE_WACKY_STATE();
-+
-+ op_failed:
-+ /* reset on all failures. */
-+ cfi_write( map, CMD(0xF0), chip->start );
-+ /* FIXME - should have reset delay before continuing */
-+ CHECK_RETRIES();
-+ ret = -EIO;
-+
-+ op_done:
-+ chip->state = FL_READY;
-+ put_chip(map, chip, adr);
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+}
-+
-+
-+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ unsigned long ofs, len;
-+ int ret;
-+
-+ ofs = instr->addr;
-+ len = instr->len;
-+
-+ ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
-+ if (ret)
-+ return ret;
-
- instr->state = MTD_ERASE_DONE;
- if (instr->callback)
-@@ -1118,6 +1886,7 @@
- return 0;
- }
-
-+
- static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct map_info *map = mtd->priv;
-@@ -1141,6 +1910,7 @@
- return 0;
- }
-
-+
- static void cfi_amdstd_sync (struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1254,6 +2024,7 @@
- return ret;
- }
-
-+
- static void cfi_amdstd_resume(struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1279,6 +2050,137 @@
- }
- }
-
-+
-+#ifdef DEBUG_LOCK_BITS
-+
-+static int do_printlockstatus_oneblock(struct map_info *map,
-+ struct flchip *chip,
-+ unsigned long adr,
-+ void *thunk)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ int ofs_factor = cfi->interleave * cfi->device_type;
-+
-+ cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-+ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
-+ adr, cfi_read_query(map, adr+(2*ofs_factor)));
-+ cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-+
-+ return 0;
-+}
-+
-+
-+#define debug_dump_locks(mtd, frob, ofs, len, thunk) \
-+ cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk))
-+
-+#else
-+
-+#define debug_dump_locks(...)
-+
-+#endif /* DEBUG_LOCK_BITS */
-+
-+
-+struct xxlock_thunk {
-+ cfi_word val;
-+ flstate_t state;
-+};
-+
-+
-+#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING})
-+#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING})
-+
-+
-+/*
-+ * FIXME - this is *very* specific to a particular chip. It likely won't
-+ * work for all chips that require unlock. It also hasn't been tested
-+ * with interleaved chips.
-+ */
-+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk;
-+ int ret;
-+
-+ /*
-+ * This is easy because these are writes to registers and not writes
-+ * to flash memory - that means that we don't have to check status
-+ * and timeout.
-+ */
-+
-+ adr += chip->start;
-+ /*
-+ * lock block registers:
-+ * - on 64k boundariesand
-+ * - bit 1 set high
-+ * - block lock registers are 4MiB lower - overflow subtract (danger)
-+ */
-+ adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff;
-+
-+ cfi_spin_lock(chip->mutex);
-+ ret = get_chip(map, chip, adr, FL_LOCKING);
-+ if (ret) {
-+ cfi_spin_unlock(chip->mutex);
-+ return ret;
-+ }
-+
-+ chip->state = xxlt->state;
-+ cfi_write(map, CMD(xxlt->val), adr);
-+
-+ /* Done and happy. */
-+ chip->state = FL_READY;
-+ put_chip(map, chip, adr);
-+ cfi_spin_unlock(chip->mutex);
-+ return 0;
-+}
-+
-+
-+static int cfi_amdstd_lock_varsize(struct mtd_info *mtd,
-+ loff_t ofs,
-+ size_t len)
-+{
-+ int ret;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-+ __func__, ofs, len);
-+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
-+
-+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
-+ (void *)&DO_XXLOCK_ONEBLOCK_LOCK);
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "%s: lock status after, ret=%d\n",
-+ __func__, ret);
-+
-+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
-+
-+ return ret;
-+}
-+
-+
-+static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd,
-+ loff_t ofs,
-+ size_t len)
-+{
-+ int ret;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-+ __func__, ofs, len);
-+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
-+
-+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
-+ (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK);
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "%s: lock status after, ret=%d\n",
-+ __func__, ret);
-+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
-+
-+ return ret;
-+}
-+
-+
- static void cfi_amdstd_destroy(struct mtd_info *mtd)
- {
- struct map_info *map = mtd->priv;
-@@ -1291,17 +2193,20 @@
-
- static char im_name[]="cfi_cmdset_0002";
-
-+
- int __init cfi_amdstd_init(void)
- {
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
- return 0;
- }
-
-+
- static void __exit cfi_amdstd_exit(void)
- {
- inter_module_unregister(im_name);
- }
-
-+
- module_init(cfi_amdstd_init);
- module_exit(cfi_amdstd_exit);
-
-@@ -1309,3 +2214,7 @@
- MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
- MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
-
-+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-+MODULE_PARM(retry_cmd_max, "i");
-+MODULE_PARM_DESC(retry_cmd_max, "Number of times to retry an erase or program command if it fails - should only be needed by buggy hardware: default 0");
-+#endif
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c linux/drivers/mtd/chips/cfi_cmdset_0020.c
---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-19 10:25:11.747222896 +0100
-@@ -21,16 +21,19 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
-
- #include <linux/errno.h>
-+#include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
--#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/mtd.h>
-
-
- static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-@@ -51,10 +54,10 @@
- static struct mtd_info *cfi_staa_setup (struct map_info *);
-
- static struct mtd_chip_driver cfi_staa_chipdrv = {
-- probe: NULL, /* Not usable directly */
-- destroy: cfi_staa_destroy,
-- name: "cfi_cmdset_0020",
-- module: THIS_MODULE
-+ .probe = NULL, /* Not usable directly */
-+ .destroy = cfi_staa_destroy,
-+ .name = "cfi_cmdset_0020",
-+ .module = THIS_MODULE
- };
-
- /* #define DEBUG_LOCK_BITS */
-@@ -113,7 +116,6 @@
- {
- struct cfi_private *cfi = map->fldrv_priv;
- int i;
-- __u32 base = cfi->chips[0].start;
-
- if (cfi->cfi_mode) {
- /*
-@@ -123,35 +125,10 @@
- */
- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
- struct cfi_pri_intelext *extp;
-- int ofs_factor = cfi->interleave * cfi->device_type;
--
-- printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
-- if (!adr)
-- return NULL;
--
-- /* Switch it into Query Mode */
-- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
--
-- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-- if (!extp) {
-- printk(KERN_ERR "Failed to allocate memory\n");
-- return NULL;
-- }
--
-- /* Read in the Extended Query Table */
-- for (i=0; i<sizeof(*extp); i++) {
-- ((unsigned char *)extp)[i] =
-- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-- }
-
-- if (extp->MajorVersion != '1' ||
-- (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
-- printk(KERN_WARNING " Unknown staa Extended Query "
-- "version %c.%c.\n", extp->MajorVersion,
-- extp->MinorVersion);
-- kfree(extp);
-+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics");
-+ if (!extp)
- return NULL;
-- }
-
- /* Do some byteswapping if necessary */
- extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-@@ -172,11 +149,6 @@
- cfi->chips[i].erase_time = 1024;
- }
-
-- map->fldrv = &cfi_staa_chipdrv;
-- MOD_INC_USE_COUNT;
--
-- /* Make sure it's in read mode */
-- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
- return cfi_staa_setup(map);
- }
-
-@@ -208,6 +180,7 @@
- if (!mtd->eraseregions) {
- printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
- kfree(cfi->cmdset_priv);
-+ kfree(mtd);
- return NULL;
- }
-
-@@ -232,6 +205,7 @@
- printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
- kfree(mtd->eraseregions);
- kfree(cfi->cmdset_priv);
-+ kfree(mtd);
- return NULL;
- }
-
-@@ -256,7 +230,7 @@
- mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
- mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
- map->fldrv = &cfi_staa_chipdrv;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- mtd->name = map->name;
- return mtd;
- }
-@@ -288,7 +262,7 @@
- */
- switch (chip->state) {
- case FL_ERASING:
-- if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
-+ if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
- goto sleep; /* We don't support erase suspend */
-
- cfi_write (map, CMD(0xb0), cmd_addr);
-@@ -374,7 +348,7 @@
- goto retry;
- }
-
-- map->copy_from(map, buf, adr, len);
-+ map_copy_from(map, buf, adr, len);
-
- if (suspended) {
- chip->state = chip->oldstate;
-@@ -540,11 +514,11 @@
- /* Write data */
- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
- if (cfi_buswidth_is_1()) {
-- map->write8 (map, *((__u8*)buf)++, adr+z);
-+ map_write8 (map, *((__u8*)buf)++, adr+z);
- } else if (cfi_buswidth_is_2()) {
-- map->write16 (map, *((__u16*)buf)++, adr+z);
-+ map_write16 (map, *((__u16*)buf)++, adr+z);
- } else if (cfi_buswidth_is_4()) {
-- map->write32 (map, *((__u32*)buf)++, adr+z);
-+ map_write32 (map, *((__u32*)buf)++, adr+z);
- } else {
- DISABLE_VPP(map);
- return -EINVAL;
-@@ -1436,13 +1410,13 @@
-
- static char im_name[]="cfi_cmdset_0020";
-
--mod_init_t cfi_staa_init(void)
-+int __init cfi_staa_init(void)
- {
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
- return 0;
- }
-
--mod_exit_t cfi_staa_exit(void)
-+static void __exit cfi_staa_exit(void)
- {
- inter_module_unregister(im_name);
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_probe.c linux/drivers/mtd/chips/cfi_probe.c
---- linux-mips-2.4.27/drivers/mtd/chips/cfi_probe.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/cfi_probe.c 2004-11-19 10:25:11.766220008 +0100
-@@ -1,13 +1,14 @@
- /*
- Common Flash Interface probe code.
- (C) 2000 Red Hat. GPL'd.
-- $Id$
-+ $Id$
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
- #include <linux/errno.h>
-@@ -25,7 +26,7 @@
- #endif
-
- static int cfi_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
-+ unsigned long *chip_map, struct cfi_private *cfi);
- static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
-
- struct mtd_info *cfi_probe(struct map_info *map);
-@@ -48,7 +49,7 @@
- }
-
- static int cfi_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi)
-+ unsigned long *chip_map, struct cfi_private *cfi)
- {
- int i;
-
-@@ -77,18 +78,24 @@
- }
-
- /* Check each previous chip to see if it's an alias */
-- for (i=0; i<cfi->numchips; i++) {
-+ for (i=0; i < (base >> cfi->chipshift); i++) {
-+ unsigned long start;
-+ if(!test_bit(i, chip_map)) {
-+ /* Skip location; no valid chip at this address */
-+ continue;
-+ }
-+ start = i << cfi->chipshift;
- /* This chip should be in read mode if it's one
- we've already touched. */
-- if (qry_present(map,chips[i].start,cfi)) {
-+ if (qry_present(map, start, cfi)) {
- /* Eep. This chip also had the QRY marker.
- * Is it an alias for the new one? */
-- cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
-
- /* If the QRY marker goes away, it's an alias */
-- if (!qry_present(map, chips[i].start, cfi)) {
-+ if (!qry_present(map, start, cfi)) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- /* Yes, it's actually got QRY for data. Most
-@@ -99,7 +106,7 @@
-
- if (qry_present(map, base, cfi)) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- }
-@@ -107,13 +114,7 @@
-
- /* OK, if we got to here, then none of the previous chips appear to
- be aliases for the current one. */
-- if (cfi->numchips == MAX_CFI_CHIPS) {
-- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-- return -1;
-- }
-- chips[cfi->numchips].start = base;
-- chips[cfi->numchips].state = FL_READY;
-+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
- cfi->numchips++;
-
- /* Put it back into Read Mode */
-@@ -179,9 +180,28 @@
- (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
- #endif
- }
-+
-+ /* Note we put the device back into Read Mode BEFORE going into Auto
-+ * Select Mode, as some devices support nesting of modes, others
-+ * don't. This way should always work.
-+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
-+ * so should be treated as nops or illegal (and so put the device
-+ * back into Read Mode, which is a nop in this case).
-+ */
-+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
-+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
-+ cfi->mfr = cfi_read_query(map, base);
-+ cfi->id = cfi_read_query(map, base + ofs_factor);
-+
- /* Put it back into Read Mode */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-
-+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
-+ map->name, cfi->interleave, cfi->device_type*8, base,
-+ map->buswidth*8);
-+
- return 1;
- }
-
-@@ -240,11 +260,11 @@
- printk("No Alternate Algorithm Table\n");
-
-
-- printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
-- printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
-+ printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
-+ printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
- if (cfip->VppMin) {
-- printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
-- printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
-+ printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
-+ printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
- }
- else
- printk("No Vpp line\n");
-@@ -303,8 +323,8 @@
- #endif /* DEBUG_CFI */
-
- static struct chip_probe cfi_chip_probe = {
-- name: "CFI",
-- probe_chip: cfi_probe_chip
-+ .name = "CFI",
-+ .probe_chip = cfi_probe_chip
- };
-
- struct mtd_info *cfi_probe(struct map_info *map)
-@@ -317,9 +337,9 @@
- }
-
- static struct mtd_chip_driver cfi_chipdrv = {
-- probe: cfi_probe,
-- name: "cfi_probe",
-- module: THIS_MODULE
-+ .probe = cfi_probe,
-+ .name = "cfi_probe",
-+ .module = THIS_MODULE
- };
-
- int __init cfi_probe_init(void)
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_util.c linux/drivers/mtd/chips/cfi_util.c
---- linux-mips-2.4.27/drivers/mtd/chips/cfi_util.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/chips/cfi_util.c 2004-11-19 10:25:11.767219856 +0100
-@@ -0,0 +1,91 @@
-+/*
-+ * Common Flash Interface support:
-+ * Generic utility functions not dependant on command set
-+ *
-+ * Copyright (C) 2002 Red Hat
-+ * Copyright (C) 2003 STMicroelectronics Limited
-+ *
-+ * This code is covered by the GPL.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <asm/io.h>
-+#include <asm/byteorder.h>
-+
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/compatmac.h>
-+
-+struct cfi_extquery *
-+cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ __u32 base = 0; // cfi->chips[0].start;
-+ int ofs_factor = cfi->interleave * cfi->device_type;
-+ int i;
-+ struct cfi_extquery *extp = NULL;
-+
-+ printk(" %s Extended Query Table at 0x%4.4X\n", name, adr);
-+ if (!adr)
-+ goto out;
-+
-+ /* Switch it into Query Mode */
-+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-+
-+ extp = kmalloc(size, GFP_KERNEL);
-+ if (!extp) {
-+ printk(KERN_ERR "Failed to allocate memory\n");
-+ goto out;
-+ }
-+
-+ /* Read in the Extended Query Table */
-+ for (i=0; i<size; i++) {
-+ ((unsigned char *)extp)[i] =
-+ cfi_read_query(map, base+((adr+i)*ofs_factor));
-+ }
-+
-+ if (extp->MajorVersion != '1' ||
-+ (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-+ printk(KERN_WARNING " Unknown %s Extended Query "
-+ "version %c.%c.\n", name, extp->MajorVersion,
-+ extp->MinorVersion);
-+ kfree(extp);
-+ extp = NULL;
-+ goto out;
-+ }
-+
-+out:
-+ /* Make sure it's in read mode */
-+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
-+
-+ return extp;
-+}
-+
-+EXPORT_SYMBOL(cfi_read_pri);
-+
-+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups)
-+{
-+ struct cfi_private *cfi = map->fldrv_priv;
-+ struct cfi_fixup *f;
-+
-+ for (f=fixups; f->fixup; f++) {
-+ if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
-+ ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
-+ f->fixup(map, f->param);
-+ }
-+ }
-+}
-+
-+EXPORT_SYMBOL(cfi_fixup);
-+
-+MODULE_LICENSE("GPL");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/chipreg.c linux/drivers/mtd/chips/chipreg.c
---- linux-mips-2.4.27/drivers/mtd/chips/chipreg.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/chipreg.c 2004-11-19 10:25:11.769219552 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Registration for chip drivers
- *
-@@ -7,10 +7,13 @@
-
- #include <linux/kernel.h>
- #include <linux/config.h>
-+#include <linux/module.h>
- #include <linux/kmod.h>
- #include <linux/spinlock.h>
--#include <linux/mtd/compatmac.h>
-+#include <linux/slab.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
-
- spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED;
- static LIST_HEAD(chip_drvs_list);
-@@ -44,10 +47,8 @@
- break;
- }
- }
-- if (ret && !try_inc_mod_count(ret->module)) {
-- /* Eep. Failed. */
-+ if (ret && !try_module_get(ret->module))
- ret = NULL;
-- }
-
- spin_unlock(&chip_drvs_lock);
-
-@@ -64,32 +65,46 @@
-
- drv = get_mtd_chip_driver(name);
-
-- if (!drv && !request_module(name))
-+ if (!drv && !request_module("%s", name))
- drv = get_mtd_chip_driver(name);
-
- if (!drv)
- return NULL;
-
- ret = drv->probe(map);
--#ifdef CONFIG_MODULES
-+
- /* We decrease the use count here. It may have been a
- probe-only module, which is no longer required from this
- point, having given us a handle on (and increased the use
- count of) the actual driver code.
- */
-- if(drv->module)
-- __MOD_DEC_USE_COUNT(drv->module);
--#endif
-+ module_put(drv->module);
-
- if (ret)
- return ret;
-
- return NULL;
- }
-+/*
-+ * Destroy an MTD device which was created for a map device.
-+ * Make sure the MTD device is already unregistered before calling this
-+ */
-+void map_destroy(struct mtd_info *mtd)
-+{
-+ struct map_info *map = mtd->priv;
-+
-+ if (map->fldrv->destroy)
-+ map->fldrv->destroy(mtd);
-+
-+ module_put(map->fldrv->module);
-+
-+ kfree(mtd);
-+}
-
- EXPORT_SYMBOL(register_mtd_chip_driver);
- EXPORT_SYMBOL(unregister_mtd_chip_driver);
- EXPORT_SYMBOL(do_map_probe);
-+EXPORT_SYMBOL(map_destroy);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/gen_probe.c linux/drivers/mtd/chips/gen_probe.c
---- linux-mips-2.4.27/drivers/mtd/chips/gen_probe.c 2003-08-13 19:19:18.000000000 +0200
-+++ linux/drivers/mtd/chips/gen_probe.c 2004-11-19 10:25:11.770219400 +0100
-@@ -1,14 +1,17 @@
- /*
- * Routines common to all CFI-type probes.
-- * (C) 2001, 2001 Red Hat, Inc.
-+ * (C) 2001-2003 Red Hat, Inc.
- * GPL'd
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/gen_probe.h>
-
- static struct mtd_info *check_cmd_set(struct map_info *, int);
-@@ -50,11 +53,11 @@
-
- struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
- {
-- unsigned long base=0;
- struct cfi_private cfi;
- struct cfi_private *retcfi;
-- struct flchip chip[MAX_CFI_CHIPS];
-- int i;
-+ unsigned long *chip_map;
-+ int i, j;
-+ int max_chips;
-
- memset(&cfi, 0, sizeof(cfi));
-
-@@ -77,8 +80,6 @@
- return NULL;
- }
- #endif
-- chip[0].start = 0;
-- chip[0].state = FL_READY;
- cfi.chipshift = cfi.cfiq->DevSize;
-
- switch(cfi.interleave) {
-@@ -103,20 +104,28 @@
- cfi.numchips = 1;
-
- /*
-+ * Allocate memory for bitmap of valid chips.
-+ * Align bitmap storage size to full byte.
-+ */
-+ max_chips = map->size >> cfi.chipshift;
-+ chip_map = kmalloc((max_chips / 8) + ((max_chips % 8) ? 1 : 0), GFP_KERNEL);
-+ if (!chip_map) {
-+ printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
-+ kfree(cfi.cfiq);
-+ return NULL;
-+ }
-+
-+ set_bit(0, chip_map); /* Mark first chip valid */
-+
-+ /*
- * Now probe for other chips, checking sensibly for aliases while
- * we're at it. The new_chip probe above should have let the first
- * chip in read mode.
-- *
-- * NOTE: Here, we're checking if there is room for another chip
-- * the same size within the mapping. Therefore,
-- * base + chipsize <= map->size is the correct thing to do,
-- * because, base + chipsize would be the _first_ byte of the
-- * next chip, not the one we're currently pondering.
- */
-
-- for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
-- base += (1<<cfi.chipshift))
-- cp->probe_chip(map, base, &chip[0], &cfi);
-+ for (i = 1; i < max_chips; i++) {
-+ cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
-+ }
-
- /*
- * Now allocate the space for the structures we need to return to
-@@ -128,19 +137,26 @@
- if (!retcfi) {
- printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
- kfree(cfi.cfiq);
-+ kfree(chip_map);
- return NULL;
- }
-
- memcpy(retcfi, &cfi, sizeof(cfi));
-- memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-+ memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
-
-- /* Fix up the stuff that breaks when you move it */
-- for (i=0; i< retcfi->numchips; i++) {
-- init_waitqueue_head(&retcfi->chips[i].wq);
-- spin_lock_init(&retcfi->chips[i]._spinlock);
-- retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
-+ for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
-+ if(test_bit(i, chip_map)) {
-+ struct flchip *pchip = &retcfi->chips[j++];
-+
-+ pchip->start = (i << cfi.chipshift);
-+ pchip->state = FL_READY;
-+ init_waitqueue_head(&pchip->wq);
-+ spin_lock_init(&pchip->_spinlock);
-+ pchip->mutex = &pchip->_spinlock;
-+ }
- }
-
-+ kfree(chip_map);
- return retcfi;
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/jedec.c linux/drivers/mtd/chips/jedec.c
---- linux-mips-2.4.27/drivers/mtd/chips/jedec.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/jedec.c 2004-11-19 10:25:11.772219096 +0100
-@@ -11,10 +11,16 @@
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
-- * $Id$
-+ * $Id$
- */
-
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
- #include <linux/mtd/jedec.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
-
- static struct mtd_info *jedec_probe(struct map_info *);
- static int jedec_probe8(struct map_info *map,unsigned long base,
-@@ -33,14 +39,51 @@
-
- /* Listing of parts and sizes. We need this table to learn the sector
- size of the chip and the total length */
--static const struct JEDECTable JEDEC_table[] =
-- {{0x013D,"AMD Am29F017D",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x01A4,"AMD Am29F040",512*1024,64*1024,MTD_CAP_NORFLASH},
-- {0x20E3,"AMD Am29W040B",512*1024,64*1024,MTD_CAP_NORFLASH},
-- {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
-- {}};
-+static const struct JEDECTable JEDEC_table[] = {
-+ {
-+ .jedec = 0x013D,
-+ .name = "AMD Am29F017D",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01AD,
-+ .name = "AMD Am29F016",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01D5,
-+ .name = "AMD Am29F080",
-+ .size = 1*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x01A4,
-+ .name = "AMD Am29F040",
-+ .size = 512*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0x20E3,
-+ .name = "AMD Am29W040B",
-+ .size = 512*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ {
-+ .jedec = 0xC2AD,
-+ .name = "Macronix MX29F016",
-+ .size = 2*1024*1024,
-+ .sectorsize = 64*1024,
-+ .capabilities = MTD_CAP_NORFLASH
-+ },
-+ { .jedec = 0x0 }
-+};
-
- static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
- static void jedec_sync(struct mtd_info *mtd) {};
-@@ -54,9 +97,9 @@
-
-
- static struct mtd_chip_driver jedec_chipdrv = {
-- probe: jedec_probe,
-- name: "jedec",
-- module: THIS_MODULE
-+ .probe = jedec_probe,
-+ .name = "jedec",
-+ .module = THIS_MODULE
- };
-
- /* Probe entry point */
-@@ -131,8 +174,7 @@
- /* Generate a part name that includes the number of different chips and
- other configuration information */
- count = 1;
-- strncpy(Part,map->name,sizeof(Part)-10);
-- Part[sizeof(Part)-11] = 0;
-+ strlcpy(Part,map->name,sizeof(Part)-10);
- strcat(Part," ");
- Uniq = 0;
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-@@ -209,8 +251,7 @@
- // printk("Part: '%s'\n",Part);
-
- memset(MTD,0,sizeof(*MTD));
-- // strncpy(MTD->name,Part,sizeof(MTD->name));
-- // MTD->name[sizeof(MTD->name)-1] = 0;
-+ // strlcpy(MTD->name,Part,sizeof(MTD->name));
- MTD->name = map->name;
- MTD->type = MTD_NORFLASH;
- MTD->flags = MTD_CAP_NORFLASH;
-@@ -229,7 +270,7 @@
- MTD->priv = map;
- map->fldrv_priv = priv;
- map->fldrv = &jedec_chipdrv;
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return MTD;
- }
-
-@@ -351,8 +392,8 @@
- static int jedec_probe8(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
- {
-- #define flread(x) map->read8(map,base+x)
-- #define flwrite(v,x) map->write8(map,v,base+x)
-+ #define flread(x) map_read8(map,base+x)
-+ #define flwrite(v,x) map_write8(map,v,base+x)
-
- const unsigned long AutoSel1 = 0xAA;
- const unsigned long AutoSel2 = 0x55;
-@@ -411,8 +452,8 @@
- static int jedec_probe32(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
- {
-- #define flread(x) map->read32(map,base+((x)<<2))
-- #define flwrite(v,x) map->write32(map,v,base+((x)<<2))
-+ #define flread(x) map_read32(map,base+((x)<<2))
-+ #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
- const unsigned long AutoSel1 = 0xAAAAAAAA;
- const unsigned long AutoSel2 = 0x55555555;
-@@ -490,7 +531,7 @@
- {
- struct map_info *map = (struct map_info *)mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-@@ -514,7 +555,7 @@
- get = priv->bank_fill[0] - offset;
-
- bank /= priv->bank_fill[0];
-- map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-+ map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
- len -= get;
- *retlen += get;
-@@ -545,8 +586,8 @@
- static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- // Does IO to the currently selected chip
-- #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
-- #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
-+ #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
-+ #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
- unsigned long Time = 0;
- unsigned long NoTime = 0;
-@@ -608,7 +649,7 @@
-
- /* Poll the flash for erasure completion, specs say this can take as long
- as 480 seconds to do all the sectors (for a 2 meg flash).
-- Erasure time is dependant on chip age, temp and wear.. */
-+ Erasure time is dependent on chip age, temp and wear.. */
-
- /* This being a generic routine assumes a 32 bit bus. It does read32s
- and bundles interleved chips into the same grouping. This will work
-@@ -651,19 +692,19 @@
- or this is not really flash ;> */
- switch (map->buswidth) {
- case 1:
-- Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
-- Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 3:
-- Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-- Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count = 3;
-@@ -699,13 +740,13 @@
-
- switch (map->buswidth) {
- case 1:
-- Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
-- Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 4:
-- Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-+ Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count++;
-@@ -755,10 +796,10 @@
- size_t *retlen, const u_char *buf)
- {
- /* Does IO to the currently selected chip. It takes the bank addressing
-- base (which is divisable by the chip size) adds the necesary lower bits
-- of addrshift (interleve index) and then adds the control register index. */
-- #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-- #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-+ base (which is divisible by the chip size) adds the necessary lower bits
-+ of addrshift (interleave index) and then adds the control register index. */
-+ #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-+ #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
- struct map_info *map = (struct map_info *)mtd->priv;
- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
-@@ -794,7 +835,7 @@
- // Loop over this page
- for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
- {
-- unsigned char oldbyte = map->read8(map,base+off);
-+ unsigned char oldbyte = map_read8(map,base+off);
- unsigned char Last[4];
- unsigned long Count = 0;
-
-@@ -809,10 +850,10 @@
- flwrite(0xAA,0x555);
- flwrite(0x55,0x2AA);
- flwrite(0xA0,0x555);
-- map->write8(map,*buf,base + off);
-- Last[0] = map->read8(map,base + off);
-- Last[1] = map->read8(map,base + off);
-- Last[2] = map->read8(map,base + off);
-+ map_write8(map,*buf,base + off);
-+ Last[0] = map_read8(map,base + off);
-+ Last[1] = map_read8(map,base + off);
-+ Last[2] = map_read8(map,base + off);
-
- /* Wait for the flash to finish the operation. We store the last 4
- status bytes that have been retrieved so we can determine why
-@@ -820,7 +861,7 @@
- failure */
- for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
- Count < 10000; Count++)
-- Last[Count % 4] = map->read8(map,base + off);
-+ Last[Count % 4] = map_read8(map,base + off);
- if (Last[(Count - 1) % 4] != *buf)
- {
- jedec_flash_failed(Last[(Count - 3) % 4]);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/jedec_probe.c linux/drivers/mtd/chips/jedec_probe.c
---- linux-mips-2.4.27/drivers/mtd/chips/jedec_probe.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/jedec_probe.c 2004-11-19 10:25:11.774218792 +0100
-@@ -1,9 +1,11 @@
- /*
- Common Flash Interface probe code.
- (C) 2000 Red Hat. GPL'd.
-- $Id$
-+ $Id$
- See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
- for the standard this probe goes back to.
-+
-+ Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
- */
-
- #include <linux/config.h>
-@@ -15,7 +17,9 @@
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
-+#include <linux/init.h>
-
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
- #include <linux/mtd/gen_probe.h>
-@@ -26,20 +30,24 @@
- #define MANUFACTURER_FUJITSU 0x0004
- #define MANUFACTURER_INTEL 0x0089
- #define MANUFACTURER_MACRONIX 0x00C2
--#define MANUFACTURER_ST 0x0020
-+#define MANUFACTURER_PMC 0x009D
- #define MANUFACTURER_SST 0x00BF
-+#define MANUFACTURER_ST 0x0020
- #define MANUFACTURER_TOSHIBA 0x0098
-+#define MANUFACTURER_WINBOND 0x00da
-
-
- /* AMD */
- #define AM29F800BB 0x2258
- #define AM29F800BT 0x22D6
-+#define AM29LV400BB 0x22BA
-+#define AM29LV400BT 0x22B9
- #define AM29LV800BB 0x225B
- #define AM29LV800BT 0x22DA
- #define AM29LV160DT 0x22C4
- #define AM29LV160DB 0x2249
- #define AM29F017D 0x003D
--#define AM29F016 0x00AD
-+#define AM29F016D 0x00AD
- #define AM29F080 0x00D5
- #define AM29F040 0x00A4
- #define AM29LV040B 0x004F
-@@ -54,6 +62,7 @@
- #define AT49BV32XT 0x00C9
-
- /* Fujitsu */
-+#define MBM29F040C 0x00A4
- #define MBM29LV650UE 0x22D7
- #define MBM29LV320TE 0x22F6
- #define MBM29LV320BE 0x22F9
-@@ -61,6 +70,9 @@
- #define MBM29LV160BE 0x2249
- #define MBM29LV800BA 0x225B
- #define MBM29LV800TA 0x22DA
-+#define MBM29LV400TC 0x22B9
-+#define MBM29LV400BC 0x22BA
-+
-
- /* Intel */
- #define I28F004B3T 0x00d4
-@@ -93,8 +105,14 @@
- #define MX29F004T 0x0045
- #define MX29F004B 0x0046
-
-+/* PMC */
-+#define PM49FL002 0x006D
-+#define PM49FL004 0x006E
-+#define PM49FL008 0x006A
-+
- /* ST - www.st.com */
--#define M29W800T 0x00D7
-+#define M29W800DT 0x00D7
-+#define M29W800DB 0x005B
- #define M29W160DT 0x22C4
- #define M29W160DB 0x2249
- #define M29W040B 0x00E3
-@@ -110,6 +128,7 @@
- #define SST39LF040 0x00D7
- #define SST39SF010A 0x00B5
- #define SST39SF020A 0x00B6
-+#define SST49LF004B 0x0060
- #define SST49LF030A 0x001C
- #define SST49LF040A 0x0051
- #define SST49LF080A 0x005B
-@@ -122,15 +141,87 @@
- #define TC58FVT641 0x0093
- #define TC58FVB641 0x0095
-
-+/* Winbond */
-+#define W49V002A 0x00b0
-+
-+
-+/*
-+ * Unlock address sets for AMD command sets.
-+ * Intel command sets use the MTD_UADDR_UNNECESSARY.
-+ * Each identifier, except MTD_UADDR_UNNECESSARY, and
-+ * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
-+ * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
-+ * initialization need not require initializing all of the
-+ * unlock addresses for all bit widths.
-+ */
-+enum uaddr {
-+ MTD_UADDR_NOT_SUPPORTED = 0, /* data width not supported */
-+ MTD_UADDR_0x0555_0x02AA,
-+ MTD_UADDR_0x0555_0x0AAA,
-+ MTD_UADDR_0x5555_0x2AAA,
-+ MTD_UADDR_0x0AAA_0x0555,
-+ MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */
-+ MTD_UADDR_UNNECESSARY, /* Does not require any address */
-+};
-+
-+
-+struct unlock_addr {
-+ int addr1;
-+ int addr2;
-+};
-+
-+
-+/*
-+ * I don't like the fact that the first entry in unlock_addrs[]
-+ * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
-+ * should not be used. The problem is that structures with
-+ * initializers have extra fields initialized to 0. It is _very_
-+ * desireable to have the unlock address entries for unsupported
-+ * data widths automatically initialized - that means that
-+ * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
-+ * must go unused.
-+ */
-+static const struct unlock_addr unlock_addrs[] = {
-+ [MTD_UADDR_NOT_SUPPORTED] = {
-+ .addr1 = 0xffff,
-+ .addr2 = 0xffff
-+ },
-+
-+ [MTD_UADDR_0x0555_0x02AA] = {
-+ .addr1 = 0x0555,
-+ .addr2 = 0x02aa
-+ },
-+
-+ [MTD_UADDR_0x0555_0x0AAA] = {
-+ .addr1 = 0x0555,
-+ .addr2 = 0x0aaa
-+ },
-+
-+ [MTD_UADDR_0x5555_0x2AAA] = {
-+ .addr1 = 0x5555,
-+ .addr2 = 0x2aaa
-+ },
-+
-+ [MTD_UADDR_0x0AAA_0x0555] = {
-+ .addr1 = 0x0AAA,
-+ .addr2 = 0x0555
-+ },
-+
-+ [MTD_UADDR_DONT_CARE] = {
-+ .addr1 = 0x0000, /* Doesn't matter which address */
-+ .addr2 = 0x0000 /* is used - must be last entry */
-+ }
-+};
-+
-
- struct amd_flash_info {
- const __u16 mfr_id;
- const __u16 dev_id;
- const char *name;
- const int DevSize;
-- const int InterfaceDesc;
- const int NumEraseRegions;
- const int CmdSet;
-+ const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */
- const ulong regions[4];
- };
-
-@@ -145,760 +236,1214 @@
- #define SIZE_4MiB 22
- #define SIZE_8MiB 23
-
-+
-+/*
-+ * Please keep this list ordered by manufacturer!
-+ * Fortunately, the list isn't searched often and so a
-+ * slow, linear search isn't so bad.
-+ */
- static const struct amd_flash_info jedec_table[] = {
- {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F032B,
-- name: "AMD AM29F032B",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,64)
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DT,
-- name: "AMD AM29LV160DT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F032B,
-+ .name = "AMD AM29F032B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,64)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DT,
-+ .name = "AMD AM29LV160DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV160DB,
-- name: "AMD AM29LV160DB",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV160DB,
-+ .name = "AMD AM29LV160DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT160,
-- name: "Toshiba TC58FVT160",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV400BB,
-+ .name = "AMD AM29LV400BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,7)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV400BT,
-+ .name = "AMD AM29LV400BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB160,
-- name: "Toshiba TC58FVB160",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BB,
-+ .name = "AMD AM29LV800BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,31)
-+ ERASEINFO(0x10000,15),
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB321,
-- name: "Toshiba TC58FVB321",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,63)
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BB,
-+ .name = "AMD AM29F800BB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,15),
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT321,
-- name: "Toshiba TC58FVT321",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV800BT,
-+ .name = "AMD AM29LV800BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVB641,
-- name: "Toshiba TC58FVB641",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,127)
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F800BT,
-+ .name = "AMD AM29F800BT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_TOSHIBA,
-- dev_id: TC58FVT641,
-- name: "Toshiba TC58FVT641",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,127),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F017D,
-+ .name = "AMD AM29F017D",
-+ .uaddr = {
-+ [0] = MTD_UADDR_DONT_CARE /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F016D,
-+ .name = "AMD AM29F016D",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F080,
-+ .name = "AMD AM29F080",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29F040,
-+ .name = "AMD AM29F040",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_AMD,
-+ .dev_id = AM29LV040B,
-+ .name = "AMD AM29LV040B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV512,
-+ .name = "Atmel AT49BV512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,1)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT29LV512,
-+ .name = "Atmel AT29LV512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x80,256),
-+ ERASEINFO(0x80,256)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV16X,
-+ .name = "Atmel AT49BV16X",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV650UE,
-- name: "Fujitsu MBM29LV650UE",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,128)
-- }
-- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV320TE,
-- name: "Fujitsu MBM29LV320TE",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV16XT,
-+ .name = "Atmel AT49BV16XT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV320BE,
-- name: "Fujitsu MBM29LV320BE",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV32X,
-+ .name = "Atmel AT49BV32X",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
- ERASEINFO(0x10000,63)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160TE,
-- name: "Fujitsu MBM29LV160TE",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-+ .mfr_id = MANUFACTURER_ATMEL,
-+ .dev_id = AT49BV32XT,
-+ .name = "Atmel AT49BV32XT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
-+ ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV160BE,
-- name: "Fujitsu MBM29LV160BE",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,31)
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29F040C,
-+ .name = "Fujitsu MBM29F040C",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV650UE,
-+ .name = "Fujitsu MBM29LV650UE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_DONT_CARE /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,128)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV320TE,
-+ .name = "Fujitsu MBM29LV320TE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
-+ ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800BA,
-- name: "Fujitsu MBM29LV800BA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,15)
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV320BE,
-+ .name = "Fujitsu MBM29LV320BE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,63)
- }
- }, {
-- mfr_id: MANUFACTURER_FUJITSU,
-- dev_id: MBM29LV800TA,
-- name: "Fujitsu MBM29LV800TA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160TE,
-+ .name = "Fujitsu MBM29LV160TE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV160BE,
-+ .name = "Fujitsu MBM29LV160BE",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,15),
-+ ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BB,
-- name: "AMD AM29F800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800BA,
-+ .name = "Fujitsu MBM29LV800BA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,15),
-+ ERASEINFO(0x10000,15)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BT,
-- name: "AMD AM29LV800BT",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV800TA,
-+ .name = "Fujitsu MBM29LV800TA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F800BT,
-- name: "AMD AM29F800BT",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-- ERASEINFO(0x08000,1),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV400BC,
-+ .name = "Fujitsu MBM29LV400BC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,7)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV800BB,
-- name: "AMD AM29LV800BB",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_FUJITSU,
-+ .dev_id = MBM29LV400TC,
-+ .name = "Fujitsu MBM29LV400TC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F004B3B,
-- name: "Intel 28F004B3B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F004B3B,
-+ .name = "Intel 28F004B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 7),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F004B3T,
-- name: "Intel 28F004B3T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F004B3T,
-+ .name = "Intel 28F004B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 7),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F400B3B,
-- name: "Intel 28F400B3B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F400B3B,
-+ .name = "Intel 28F400B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 7),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F400B3T,
-- name: "Intel 28F400B3T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F400B3T,
-+ .name = "Intel 28F400B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 7),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008B3B,
-- name: "Intel 28F008B3B",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008B3B,
-+ .name = "Intel 28F008B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 15),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008B3T,
-- name: "Intel 28F008B3T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008B3T,
-+ .name = "Intel 28F008B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 15),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008S5,
-- name: "Intel 28F008S5",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-- }
-- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016S5,
-- name: "Intel 28F016S5",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F008SA,
-- name: "Intel 28F008SA",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 1,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008S5,
-+ .name = "Intel 28F008S5",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016S5,
-+ .name = "Intel 28F016S5",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F008SA,
-+ .name = "Intel 28F008SA",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
- ERASEINFO(0x10000, 16),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F800B3B,
-- name: "Intel 28F800B3B",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F800B3B,
-+ .name = "Intel 28F800B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 15),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F800B3T,
-- name: "Intel 28F800B3T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F800B3T,
-+ .name = "Intel 28F800B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 15),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016B3B,
-- name: "Intel 28F016B3B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016B3B,
-+ .name = "Intel 28F016B3B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 31),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016S3,
-- name: "Intel I28F016S3",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 1,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016S3,
-+ .name = "Intel I28F016S3",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
- ERASEINFO(0x10000, 32),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F016B3T,
-- name: "Intel 28F016B3T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F016B3T,
-+ .name = "Intel 28F016B3T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 31),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F160B3B,
-- name: "Intel 28F160B3B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F160B3B,
-+ .name = "Intel 28F160B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 31),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F160B3T,
-- name: "Intel 28F160B3T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F160B3T,
-+ .name = "Intel 28F160B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 31),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F320B3B,
-- name: "Intel 28F320B3B",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F320B3B,
-+ .name = "Intel 28F320B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 63),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F320B3T,
-- name: "Intel 28F320B3T",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F320B3T,
-+ .name = "Intel 28F320B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 63),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F640B3B,
-- name: "Intel 28F640B3B",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F640B3B,
-+ .name = "Intel 28F640B3B",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x02000, 8),
- ERASEINFO(0x10000, 127),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I28F640B3T,
-- name: "Intel 28F640B3T",
-- DevSize: SIZE_8MiB,
-- CmdSet: P_ID_INTEL_STD,
-- NumEraseRegions: 2,
-- regions: {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I28F640B3T,
-+ .name = "Intel 28F640B3T",
-+ .uaddr = {
-+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_INTEL_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
- ERASEINFO(0x10000, 127),
- ERASEINFO(0x02000, 8),
- }
- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I82802AB,
-- name: "Intel 82802AB",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-- }
-- }, {
-- mfr_id: MANUFACTURER_INTEL,
-- dev_id: I82802AC,
-- name: "Intel 82802AC",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_INTEL_EXT,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-- }
-- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W800T,
-- name: "ST M29W800T",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,15),
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I82802AB,
-+ .name = "Intel 82802AB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_INTEL,
-+ .dev_id = I82802AC,
-+ .name = "Intel 82802AC",
-+ .uaddr = {
-+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_INTEL_EXT,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,16),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29LV160T,
-+ .name = "MXIC MX29LV160T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DT,
-- name: "ST M29W160DT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-- ERASEINFO(0x08000,1),
-- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1)
-- }
-- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W160DB,
-- name: "ST M29W160DB",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29LV160B,
-+ .name = "MXIC MX29LV160B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV512,
-- name: "Atmel AT49BV512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,1)
-- }
-- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT29LV512,
-- name: "Atmel AT29LV512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {
-- ERASEINFO(0x80,256),
-- ERASEINFO(0x80,256)
-- }
-- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV16X,
-- name: "Atmel AT49BV16X",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,31)
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F016,
-+ .name = "Macronix MX29F016",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F004T,
-+ .name = "Macronix MX29F004T",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,7),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1),
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV16XT,
-- name: "Atmel AT49BV16XT",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,31),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_MACRONIX,
-+ .dev_id = MX29F004B,
-+ .name = "Macronix MX29F004B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,7),
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV32X,
-- name: "Atmel AT49BV32X",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x02000,8),
-- ERASEINFO(0x10000,63)
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL002,
-+ .name = "PMC Pm49FL002",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 64 )
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL004,
-+ .name = "PMC Pm49FL004",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 128 )
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_PMC,
-+ .dev_id = PM49FL008,
-+ .name = "PMC Pm49FL008",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO( 0x01000, 256 )
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF512,
-+ .name = "SST 39LF512",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_64KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,16),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF010,
-+ .name = "SST 39LF010",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_128KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF020,
-+ .name = "SST 39LF020",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,64),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39LF040,
-+ .name = "SST 39LF040",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39SF010A,
-+ .name = "SST 39SF010A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_128KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,32),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST39SF020A,
-+ .name = "SST 39SF020A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,64),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF004B,
-+ .name = "SST 49LF004B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF030A,
-+ .name = "SST 49LF030A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,96),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF040A,
-+ .name = "SST 49LF040A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,128),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_SST,
-+ .dev_id = SST49LF080A,
-+ .name = "SST 49LF080A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x01000,256),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W800DT,
-+ .name = "ST M29W800DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,15),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_ATMEL,
-- dev_id: AT49BV32XT,
-- name: "Atmel AT49BV32XT",
-- DevSize: SIZE_4MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 2,
-- regions: {ERASEINFO(0x10000,63),
-- ERASEINFO(0x02000,8)
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W800DB,
-+ .name = "ST M29W800DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
-+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
-+ },
-+ .DevSize = SIZE_1MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
-+ ERASEINFO(0x02000,2),
-+ ERASEINFO(0x08000,1),
-+ ERASEINFO(0x10000,15)
- }
- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F017D,
-- name: "AMD AM29F017D",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F016,
-- name: "AMD AM29F016",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F080,
-- name: "AMD AM29F080",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,16),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29F040,
-- name: "AMD AM29F040",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-- }
-- }, {
-- mfr_id: MANUFACTURER_AMD,
-- dev_id: AM29LV040B,
-- name: "AMD AM29LV040B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-- }
-- }, {
-- mfr_id: MANUFACTURER_ST,
-- dev_id: M29W040B,
-- name: "ST M29W040B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,8),
-- }
-- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29LV160T,
-- name: "MXIC MX29LV160T",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,31),
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W160DT,
-+ .name = "ST M29W160DT",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29LV160B,
-- name: "MXIC MX29LV160B",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
-+ .dev_id = M29W160DB,
-+ .name = "ST M29W160DB",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x10000,31)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F016,
-- name: "Macronix MX29F016",
-- DevSize: SIZE_2MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x10000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F004T,
-- name: "Macronix MX29F004T",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x10000,7),
-+ .mfr_id = MANUFACTURER_ST,
-+ .dev_id = M29W040B,
-+ .name = "ST M29W040B",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-+ },
-+ .DevSize = SIZE_512KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 1,
-+ .regions = {
-+ ERASEINFO(0x10000,8),
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT160,
-+ .name = "Toshiba TC58FVT160",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000,31),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
-- ERASEINFO(0x04000,1),
-+ ERASEINFO(0x04000,1)
- }
- }, {
-- mfr_id: MANUFACTURER_MACRONIX,
-- dev_id: MX29F004B,
-- name: "Macronix MX29F004B",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 4,
-- regions: {ERASEINFO(0x04000,1),
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB160,
-+ .name = "Toshiba TC58FVB160",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_2MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x04000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x08000,1),
-- ERASEINFO(0x10000,7),
-+ ERASEINFO(0x10000,31)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB321,
-+ .name = "Toshiba TC58FVB321",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,63)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT321,
-+ .name = "Toshiba TC58FVT321",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
-+ },
-+ .DevSize = SIZE_4MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,63),
-+ ERASEINFO(0x02000,8)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVB641,
-+ .name = "Toshiba TC58FVB641",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x02000,8),
-+ ERASEINFO(0x10000,127)
-+ }
-+ }, {
-+ .mfr_id = MANUFACTURER_TOSHIBA,
-+ .dev_id = TC58FVT641,
-+ .name = "Toshiba TC58FVT641",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-+ },
-+ .DevSize = SIZE_8MiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 2,
-+ .regions = {
-+ ERASEINFO(0x10000,127),
-+ ERASEINFO(0x02000,8)
- }
- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF512,
-- name: "SST 39LF512",
-- DevSize: SIZE_64KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,16),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF010,
-- name: "SST 39LF010",
-- DevSize: SIZE_128KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF020,
-- name: "SST 39LF020",
-- DevSize: SIZE_256KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,64),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39LF040,
-- name: "SST 39LF040",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,128),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39SF010A,
-- name: "SST 39SF010A",
-- DevSize: SIZE_128KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,32),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST39SF020A,
-- name: "SST 39SF020A",
-- DevSize: SIZE_256KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,64),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF030A,
-- name: "SST 49LF030A",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,96),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF040A,
-- name: "SST 49LF040A",
-- DevSize: SIZE_512KiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,128),
-- }
-- }, {
-- mfr_id: MANUFACTURER_SST,
-- dev_id: SST49LF080A,
-- name: "SST 49LF080A",
-- DevSize: SIZE_1MiB,
-- CmdSet: P_ID_AMD_STD,
-- NumEraseRegions: 1,
-- regions: {ERASEINFO(0x01000,256),
-+ .mfr_id = MANUFACTURER_WINBOND,
-+ .dev_id = W49V002A,
-+ .name = "Winbond W49V002A",
-+ .uaddr = {
-+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-+ },
-+ .DevSize = SIZE_256KiB,
-+ .CmdSet = P_ID_AMD_STD,
-+ .NumEraseRegions= 4,
-+ .regions = {
-+ ERASEINFO(0x10000, 3),
-+ ERASEINFO(0x08000, 1),
-+ ERASEINFO(0x02000, 2),
-+ ERASEINFO(0x04000, 1),
- }
- }
- };
-@@ -907,7 +1452,7 @@
- static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-
- static int jedec_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
-+ unsigned long *chip_map, struct cfi_private *cfi);
-
- struct mtd_info *jedec_probe(struct map_info *map);
-
-@@ -944,11 +1489,43 @@
- * this should be safe.
- */
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-+ /* FIXME - should have reset delay before continuing */
-+}
-
-+
-+static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type)
-+{
-+ int uaddr_idx;
-+ __u8 uaddr = MTD_UADDR_NOT_SUPPORTED;
-+
-+ switch ( device_type ) {
-+ case CFI_DEVICETYPE_X8: uaddr_idx = 0; break;
-+ case CFI_DEVICETYPE_X16: uaddr_idx = 1; break;
-+ case CFI_DEVICETYPE_X32: uaddr_idx = 2; break;
-+ default:
-+ printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n",
-+ __func__, device_type);
-+ goto uaddr_done;
-+ }
-+
-+ uaddr = finfo->uaddr[uaddr_idx];
-+
-+ if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
-+ /* ASSERT("The unlock addresses for non-8-bit mode
-+ are bollocks. We don't really need an array."); */
-+ uaddr = finfo->uaddr[0];
-+ }
-+
-+ uaddr_done:
-+ return uaddr;
- }
-+
-+
- static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
- {
- int i,num_erase_regions;
-+ unsigned long mask;
-+ __u8 uaddr;
-
- printk("Found: %s\n",jedec_table[index].name);
-
-@@ -971,41 +1548,170 @@
- p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
- }
- p_cfi->cmdset_priv = 0;
-+
-+ /* This may be redundant for some cases, but it doesn't hurt */
-+ p_cfi->mfr = jedec_table[index].mfr_id;
-+ p_cfi->id = jedec_table[index].dev_id;
-+
-+ uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-+ kfree( p_cfi->cfiq );
-+ return 0;
-+ }
-+
-+ /* Mask out address bits which are smaller than the device type */
-+ mask = ~(p_cfi->device_type-1);
-+ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask;
-+ p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask;
-+
- return 1; /* ok */
- }
-
--static int jedec_probe_chip(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi)
-+
-+/*
-+ * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
-+ * the mapped address, unlock addresses, and proper chip ID. This function
-+ * attempts to minimize errors. It is doubtfull that this probe will ever
-+ * be perfect - consequently there should be some module parameters that
-+ * could be manually specified to force the chip info.
-+ */
-+static inline int jedec_match( __u32 base,
-+ struct map_info *map,
-+ struct cfi_private *cfi,
-+ const struct amd_flash_info *finfo )
- {
-- int i;
-- int unlockpass = 0;
-+ int rc = 0; /* failure until all tests pass */
-+ u32 mfr, id;
-+ __u8 uaddr;
-+ unsigned long mask;
-
-- if (!cfi->numchips) {
-+ /*
-+ * The IDs must match. For X16 and X32 devices operating in
-+ * a lower width ( X8 or X16 ), the device ID's are usually just
-+ * the lower byte(s) of the larger device ID for wider mode. If
-+ * a part is found that doesn't fit this assumption (device id for
-+ * smaller width mode is completely unrealated to full-width mode)
-+ * then the jedec_table[] will have to be augmented with the IDs
-+ * for different widths.
-+ */
- switch (cfi->device_type) {
- case CFI_DEVICETYPE_X8:
-- cfi->addr_unlock1 = 0x555;
-- cfi->addr_unlock2 = 0x2aa;
-+ mfr = (__u8)finfo->mfr_id;
-+ id = (__u8)finfo->dev_id;
- break;
- case CFI_DEVICETYPE_X16:
-- cfi->addr_unlock1 = 0xaaa;
-- if (map->buswidth == cfi->interleave) {
-- /* X16 chip(s) in X8 mode */
-- cfi->addr_unlock2 = 0x555;
-- } else {
-- cfi->addr_unlock2 = 0x554;
-- }
-+ mfr = (__u16)finfo->mfr_id;
-+ id = (__u16)finfo->dev_id;
- break;
- case CFI_DEVICETYPE_X32:
-- cfi->addr_unlock1 = 0x1555;
-- cfi->addr_unlock2 = 0xaaa;
-+ mfr = (__u16)finfo->mfr_id;
-+ id = (__u32)finfo->dev_id;
- break;
- default:
-- printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
-- return 0;
-+ printk(KERN_WARNING
-+ "MTD %s(): Unsupported device type %d\n",
-+ __func__, cfi->device_type);
-+ goto match_done;
-+ }
-+ if ( cfi->mfr != mfr || cfi->id != id ) {
-+ goto match_done;
-+ }
-+
-+ /* the part size must fit in the memory window */
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
-+ __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-+ if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
-+ __func__, finfo->mfr_id, finfo->dev_id,
-+ 1 << finfo->DevSize );
-+ goto match_done;
-+ }
-+
-+ uaddr = finfo_uaddr(finfo, cfi->device_type);
-+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-+ goto match_done;
-+ }
-+
-+ mask = ~(cfi->device_type-1);
-+
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
-+ __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
-+ if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-+ && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 ||
-+ (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): 0x%.4x 0x%.4x did not match\n",
-+ __func__,
-+ unlock_addrs[uaddr].addr1 & mask,
-+ unlock_addrs[uaddr].addr2 & mask);
-+ goto match_done;
- }
-+
-+ /*
-+ * Make sure the ID's dissappear when the device is taken out of
-+ * ID mode. The only time this should fail when it should succeed
-+ * is when the ID's are written as data to the same
-+ * addresses. For this rare and unfortunate case the chip
-+ * cannot be probed correctly.
-+ * FIXME - write a driver that takes all of the chip info as
-+ * module parameters, doesn't probe but forces a load.
-+ */
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): check ID's disappear when not in ID mode\n",
-+ __func__ );
-+ jedec_reset( base, map, cfi );
-+ mfr = jedec_read_mfr( map, base, cfi );
-+ id = jedec_read_id( map, base, cfi );
-+ if ( mfr == cfi->mfr && id == cfi->id ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n"
-+ "You might need to manually specify JEDEC parameters.\n",
-+ __func__, cfi->mfr, cfi->id );
-+ goto match_done;
-+ }
-+
-+ /* all tests passed - mark as success */
-+ rc = 1;
-+
-+ /*
-+ * Put the device back in ID mode - only need to do this if we
-+ * were truly frobbing a real device.
-+ */
-+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
-+ if(cfi->addr_unlock1) {
-+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
-+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ /* FIXME - should have a delay before continuing */
-+
-+ match_done:
-+ return rc;
-+}
-+
-+
-+static int jedec_probe_chip(struct map_info *map, __u32 base,
-+ unsigned long *chip_map, struct cfi_private *cfi)
-+{
-+ int i;
-+ enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
-
- retry:
-+ if (!cfi->numchips) {
-+ unsigned long mask = ~(cfi->device_type-1);
-+
-+ uaddr_idx++;
-+
-+ if (MTD_UADDR_UNNECESSARY == uaddr_idx)
-+ return 0;
-+
-+ /* Mask out address bits which are smaller than the device type */
-+ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask;
-+ cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask;
-+ }
-+
- /* Make certain we aren't probing past the end of map */
- if (base >= map->size) {
- printk(KERN_NOTICE
-@@ -1038,6 +1744,7 @@
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+ /* FIXME - should have a delay before continuing */
-
- if (!cfi->numchips) {
- /* This is the first time we're called. Set up the CFI
-@@ -1045,26 +1752,21 @@
-
- cfi->mfr = jedec_read_mfr(map, base, cfi);
- cfi->id = jedec_read_id(map, base, cfi);
-- printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
- cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
- for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
-- if (cfi->mfr == jedec_table[i].mfr_id &&
-- cfi->id == jedec_table[i].dev_id) {
-+ if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
-+ DEBUG( MTD_DEBUG_LEVEL3,
-+ "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",
-+ __func__, cfi->mfr, cfi->id,
-+ cfi->addr_unlock1, cfi->addr_unlock2 );
- if (!cfi_jedec_setup(cfi, i))
- return 0;
- goto ok_out;
- }
- }
-- switch(unlockpass++) {
-- case 0:
-- cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
-- cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
-- goto retry;
-- case 1:
-- cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
- goto retry;
-- }
-- return 0;
- } else {
- __u16 mfr;
- __u16 id;
-@@ -1081,21 +1783,24 @@
- }
- }
-
-- /* Check each previous chip to see if it's an alias */
-- for (i=0; i<cfi->numchips; i++) {
-- /* This chip should be in read mode if it's one
-- we've already touched. */
-- if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
-- jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
-+ /* Check each previous chip locations to see if it's an alias */
-+ for (i=0; i < (base >> cfi->chipshift); i++) {
-+ unsigned long start;
-+ if(!test_bit(i, chip_map)) {
-+ continue; /* Skip location; no valid chip at this address */
-+ }
-+ start = i << cfi->chipshift;
-+ if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
-+ jedec_read_id(map, start, cfi) == cfi->id) {
- /* Eep. This chip also looks like it's in autoselect mode.
- Is it an alias for the new one? */
-- jedec_reset(chips[i].start, map, cfi);
-+ jedec_reset(start, map, cfi);
-
- /* If the device IDs go away, it's an alias */
- if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
- jedec_read_id(map, base, cfi) != cfi->id) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
-
-@@ -1107,7 +1812,7 @@
- if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
- jedec_read_id(map, base, cfi) == cfi->id) {
- printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-- map->name, base, chips[i].start);
-+ map->name, base, start);
- return 0;
- }
- }
-@@ -1115,13 +1820,7 @@
-
- /* OK, if we got to here, then none of the previous chips appear to
- be aliases for the current one. */
-- if (cfi->numchips == MAX_CFI_CHIPS) {
-- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-- return -1;
-- }
-- chips[cfi->numchips].start = base;
-- chips[cfi->numchips].state = FL_READY;
-+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
- cfi->numchips++;
-
- ok_out:
-@@ -1136,8 +1835,8 @@
- }
-
- static struct chip_probe jedec_chip_probe = {
-- name: "JEDEC",
-- probe_chip: jedec_probe_chip
-+ .name = "JEDEC",
-+ .probe_chip = jedec_probe_chip
- };
-
- struct mtd_info *jedec_probe(struct map_info *map)
-@@ -1150,9 +1849,9 @@
- }
-
- static struct mtd_chip_driver jedec_chipdrv = {
-- probe: jedec_probe,
-- name: "jedec_probe",
-- module: THIS_MODULE
-+ .probe = jedec_probe,
-+ .name = "jedec_probe",
-+ .module = THIS_MODULE
- };
-
- int __init jedec_probe_init(void)
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_absent.c linux/drivers/mtd/chips/map_absent.c
---- linux-mips-2.4.27/drivers/mtd/chips/map_absent.c 2001-11-05 21:15:51.000000000 +0100
-+++ linux/drivers/mtd/chips/map_absent.c 2004-11-19 10:25:11.776218488 +0100
-@@ -1,7 +1,7 @@
- /*
- * Common code to handle absent "placeholder" devices
- * Copyright 2001 Resilience Corporation <ebrower@resilience.com>
-- * $Id$
-+ * $Id$
- *
- * This map driver is used to allocate "placeholder" MTD
- * devices on systems that have socketed/removable media.
-@@ -23,9 +23,10 @@
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
--
-+#include <linux/mtd/compatmac.h>
-
- static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-@@ -36,10 +37,10 @@
-
-
- static struct mtd_chip_driver map_absent_chipdrv = {
-- probe: map_absent_probe,
-- destroy: map_absent_destroy,
-- name: "map_absent",
-- module: THIS_MODULE
-+ .probe = map_absent_probe,
-+ .destroy = map_absent_destroy,
-+ .name = "map_absent",
-+ .module = THIS_MODULE
- };
-
- static struct mtd_info *map_absent_probe(struct map_info *map)
-@@ -65,7 +66,7 @@
- mtd->flags = 0;
- mtd->erasesize = PAGE_SIZE;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_ram.c linux/drivers/mtd/chips/map_ram.c
---- linux-mips-2.4.27/drivers/mtd/chips/map_ram.c 2001-11-05 21:15:51.000000000 +0100
-+++ linux/drivers/mtd/chips/map_ram.c 2004-11-19 10:25:11.777218336 +0100
-@@ -1,7 +1,7 @@
- /*
- * Common code to handle map devices which are simple RAM
- * (C) 2000 Red Hat. GPL'd.
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
-@@ -11,8 +11,10 @@
- #include <asm/byteorder.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/compatmac.h>
-
-
- static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-@@ -23,9 +25,9 @@
-
-
- static struct mtd_chip_driver mapram_chipdrv = {
-- probe: map_ram_probe,
-- name: "map_ram",
-- module: THIS_MODULE
-+ .probe = map_ram_probe,
-+ .name = "map_ram",
-+ .module = THIS_MODULE
- };
-
- static struct mtd_info *map_ram_probe(struct map_info *map)
-@@ -34,21 +36,21 @@
-
- /* Check the first byte is RAM */
- #if 0
-- map->write8(map, 0x55, 0);
-- if (map->read8(map, 0) != 0x55)
-+ map_write8(map, 0x55, 0);
-+ if (map_read8(map, 0) != 0x55)
- return NULL;
-
-- map->write8(map, 0xAA, 0);
-- if (map->read8(map, 0) != 0xAA)
-+ map_write8(map, 0xAA, 0);
-+ if (map_read8(map, 0) != 0xAA)
- return NULL;
-
- /* Check the last byte is RAM */
-- map->write8(map, 0x55, map->size-1);
-- if (map->read8(map, map->size-1) != 0x55)
-+ map_write8(map, 0x55, map->size-1);
-+ if (map_read8(map, map->size-1) != 0x55)
- return NULL;
-
-- map->write8(map, 0xAA, map->size-1);
-- if (map->read8(map, map->size-1) != 0xAA)
-+ map_write8(map, 0xAA, map->size-1);
-+ if (map_read8(map, map->size-1) != 0xAA)
- return NULL;
- #endif
- /* OK. It seems to be RAM. */
-@@ -74,7 +76,7 @@
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-@@ -83,7 +85,7 @@
- {
- struct map_info *map = (struct map_info *)mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-@@ -92,7 +94,7 @@
- {
- struct map_info *map = (struct map_info *)mtd->priv;
-
-- map->copy_to(map, to, buf, len);
-+ map_copy_to(map, to, buf, len);
- *retlen = len;
- return 0;
- }
-@@ -105,7 +107,7 @@
- unsigned long i;
-
- for (i=0; i<instr->len; i++)
-- map->write8(map, 0xFF, instr->addr + i);
-+ map_write8(map, 0xFF, instr->addr + i);
-
- if (instr->callback)
- instr->callback(instr);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_rom.c linux/drivers/mtd/chips/map_rom.c
---- linux-mips-2.4.27/drivers/mtd/chips/map_rom.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/chips/map_rom.c 2004-11-19 10:25:11.778218184 +0100
-@@ -1,7 +1,7 @@
- /*
- * Common code to handle map devices which are simple ROM
- * (C) 2000 Red Hat. GPL'd.
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/version.h>
-@@ -12,8 +12,10 @@
- #include <asm/byteorder.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
--
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/compatmac.h>
-
- static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-@@ -21,9 +23,9 @@
- struct mtd_info *map_rom_probe(struct map_info *map);
-
- static struct mtd_chip_driver maprom_chipdrv = {
-- probe: map_rom_probe,
-- name: "map_rom",
-- module: THIS_MODULE
-+ .probe = map_rom_probe,
-+ .name = "map_rom",
-+ .module = THIS_MODULE
- };
-
- struct mtd_info *map_rom_probe(struct map_info *map)
-@@ -49,7 +51,7 @@
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
- return mtd;
- }
-
-@@ -58,7 +60,7 @@
- {
- struct map_info *map = (struct map_info *)mtd->priv;
-
-- map->copy_from(map, buf, from, len);
-+ map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/sharp.c linux/drivers/mtd/chips/sharp.c
---- linux-mips-2.4.27/drivers/mtd/chips/sharp.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/chips/sharp.c 2004-11-19 10:25:11.792216056 +0100
-@@ -4,7 +4,7 @@
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- * 2000,2001 Lineo, Inc.
- *
-- * $Id$
-+ * $Id$
- *
- * Devices supported:
- * LH28F016SCT Symmetrical block flash memory, 2Mx8
-@@ -28,6 +28,7 @@
- #include <linux/errno.h>
- #include <linux/interrupt.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/cfi.h>
- #include <linux/delay.h>
-
-@@ -98,10 +99,10 @@
- static void sharp_destroy(struct mtd_info *mtd);
-
- static struct mtd_chip_driver sharp_chipdrv = {
-- probe: sharp_probe,
-- destroy: sharp_destroy,
-- name: "sharp",
-- module: THIS_MODULE
-+ .probe = sharp_probe,
-+ .destroy = sharp_destroy,
-+ .name = "sharp",
-+ .module = THIS_MODULE
- };
-
-
-@@ -116,8 +117,10 @@
- return NULL;
-
- sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
-- if(!sharp)
-+ if(!sharp) {
-+ kfree(mtd);
- return NULL;
-+ }
-
- memset(mtd, 0, sizeof(*mtd));
-
-@@ -163,12 +166,12 @@
- u32 read0, read4;
- int width = 4;
-
-- tmp = map->read32(map, base+0);
-+ tmp = map_read32(map, base+0);
-
-- map->write32(map, CMD_READ_ID, base+0);
-+ map_write32(map, CMD_READ_ID, base+0);
-
-- read0=map->read32(map, base+0);
-- read4=map->read32(map, base+4);
-+ read0=map_read32(map, base+0);
-+ read4=map_read32(map, base+4);
- if(read0 == 0x89898989){
- printk("Looks like sharp flash\n");
- switch(read4){
-@@ -196,10 +199,10 @@
- printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n",
- read0,read4);
- }
-- }else if((map->read32(map, base+0) == CMD_READ_ID)){
-+ }else if((map_read32(map, base+0) == CMD_READ_ID)){
- /* RAM, probably */
- printk("Looks like RAM\n");
-- map->write32(map, tmp, base+0);
-+ map_write32(map, tmp, base+0);
- }else{
- printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n",
- read0,read4);
-@@ -221,10 +224,10 @@
-
- switch(chip->state){
- case FL_READY:
-- map->write32(map,CMD_READ_STATUS,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
- chip->state = FL_STATUS;
- case FL_STATUS:
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- //printk("status=%08x\n",status);
-
- udelay(100);
-@@ -252,7 +255,7 @@
- goto retry;
- }
-
-- map->write32(map,CMD_RESET, adr);
-+ map_write32(map,CMD_RESET, adr);
-
- chip->state = FL_READY;
-
-@@ -293,7 +296,7 @@
- if(ret<0)
- break;
-
-- map->copy_from(map,buf,ofs,thislen);
-+ map_copy_from(map,buf,ofs,thislen);
-
- sharp_release(&sharp->chips[chipnum]);
-
-@@ -354,17 +357,17 @@
- ret = sharp_wait(map,chip);
-
- for(try=0;try<10;try++){
-- map->write32(map,CMD_BYTE_WRITE,adr);
-+ map_write32(map,CMD_BYTE_WRITE,adr);
- /* cpu_to_le32 -> hack to fix the writel be->le conversion */
-- map->write32(map,cpu_to_le32(datum),adr);
-+ map_write32(map,cpu_to_le32(datum),adr);
-
- chip->state = FL_WRITING;
-
- timeo = jiffies + (HZ/2);
-
-- map->write32(map,CMD_READ_STATUS,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
- for(i=0;i<100;i++){
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY)
- break;
- }
-@@ -377,9 +380,9 @@
-
- printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status);
-
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
- }
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
-
- wake_up(&chip->wq);
-@@ -436,14 +439,14 @@
- int status;
- DECLARE_WAITQUEUE(wait, current);
-
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
-
- timeo = jiffies + HZ;
-
- while(time_before(jiffies, timeo)){
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY){
- ret = 0;
- goto out;
-@@ -485,26 +488,26 @@
- sharp_unlock_oneblock(map,chip,adr);
- #endif
-
-- map->write32(map,CMD_BLOCK_ERASE_1,adr);
-- map->write32(map,CMD_BLOCK_ERASE_2,adr);
-+ map_write32(map,CMD_BLOCK_ERASE_1,adr);
-+ map_write32(map,CMD_BLOCK_ERASE_2,adr);
-
- chip->state = FL_ERASING;
-
- ret = sharp_do_wait_for_ready(map,chip,adr);
- if(ret<0)return ret;
-
-- map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
-
- if(!(status&SR_ERRORS)){
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
- //spin_unlock_bh(chip->mutex);
- return 0;
- }
-
- printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status);
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
-
- //spin_unlock_bh(chip->mutex);
-
-@@ -518,17 +521,17 @@
- int i;
- int status;
-
-- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
-+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
-
- udelay(100);
-
-- status = map->read32(map,adr);
-+ status = map_read32(map,adr);
- printk("status=%08x\n",status);
-
- for(i=0;i<1000;i++){
-- //map->write32(map,CMD_READ_STATUS,adr);
-- status = map->read32(map,adr);
-+ //map_write32(map,CMD_READ_STATUS,adr);
-+ status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY)
- break;
- udelay(100);
-@@ -538,13 +541,13 @@
- }
-
- if(!(status&SR_ERRORS)){
-- map->write32(map,CMD_RESET,adr);
-+ map_write32(map,CMD_RESET,adr);
- chip->state = FL_READY;
- return;
- }
-
- printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status);
-- map->write32(map,CMD_CLEAR_STATUS,adr);
-+ map_write32(map,CMD_CLEAR_STATUS,adr);
- }
- #endif
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/cmdlinepart.c linux/drivers/mtd/cmdlinepart.c
---- linux-mips-2.4.27/drivers/mtd/cmdlinepart.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/cmdlinepart.c 2004-11-19 10:25:11.628240984 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Read flash partition table from command line
- *
-@@ -28,7 +28,7 @@
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
--#include <asm/setup.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/bootmem.h>
-
- /* error message prefix */
-@@ -178,8 +178,7 @@
- parts[this_part].mask_flags = mask_flags;
- if (name)
- {
-- strncpy(extra_mem, name, name_len);
-- extra_mem[name_len] = 0;
-+ strlcpy(extra_mem, name, name_len + 1);
- }
- else
- {
-@@ -258,8 +257,7 @@
- this_mtd->parts = parts;
- this_mtd->num_parts = num_parts;
- this_mtd->mtd_id = (char*)(this_mtd + 1);
-- strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
-- this_mtd->mtd_id[mtd_id_len] = 0;
-+ strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
-
- /* link into chain */
- this_mtd->next = partitions;
-@@ -291,13 +289,14 @@
- * information. It returns partitions for the requested mtd device, or
- * the first one in the chain if a NULL mtd_id is passed in.
- */
--int parse_cmdline_partitions(struct mtd_info *master,
-+static int parse_cmdline_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
-- const char *mtd_id)
-+ unsigned long origin)
- {
- unsigned long offset;
- int i;
- struct cmdline_mtd_partition *part;
-+ char *mtd_id = master->name;
-
- if(!cmdline)
- return -EINVAL;
-@@ -349,7 +348,25 @@
-
- __setup("mtdparts=", mtdpart_setup);
-
--EXPORT_SYMBOL(parse_cmdline_partitions);
-+static struct mtd_part_parser cmdline_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_cmdline_partitions,
-+ .name = "cmdlinepart",
-+};
-+
-+static int __init cmdline_parser_init(void)
-+{
-+ return register_mtd_parser(&cmdline_parser);
-+}
-+
-+static void __exit cmdline_parser_exit(void)
-+{
-+ deregister_mtd_parser(&cmdline_parser);
-+}
-+
-+module_init(cmdline_parser_init);
-+module_exit(cmdline_parser_exit);
-+
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/Config.in linux/drivers/mtd/devices/Config.in
---- linux-mips-2.4.27/drivers/mtd/devices/Config.in 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/Config.in 2004-11-19 10:25:11.811213168 +0100
-@@ -1,6 +1,6 @@
--# drivers/mtd/maps/Config.in
-+# drivers/mtd/devices/Config.in
-
--# $Id$
-+# $Id$
-
- mainmenu_option next_comment
-
-@@ -28,13 +28,13 @@
- dep_tristate ' MTD emulation using block device' CONFIG_MTD_BLKMTD $CONFIG_MTD
-
- comment 'Disk-On-Chip Device Drivers'
-- dep_tristate ' M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD
- dep_tristate ' M-Systems Disk-On-Chip 2000 and Millennium' CONFIG_MTD_DOC2000 $CONFIG_MTD
- dep_tristate ' M-Systems Disk-On-Chip Millennium-only alternative driver (see help)' CONFIG_MTD_DOC2001 $CONFIG_MTD
-- if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
-+ dep_tristate ' M-Systems Disk-On-Chip Millennium Plus driver (see help)' CONFIG_MTD_DOC2001PLUS $CONFIG_MTD
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
- define_bool CONFIG_MTD_DOCPROBE y
- else
-- if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
- define_bool CONFIG_MTD_DOCPROBE m
- else
- define_bool CONFIG_MTD_DOCPROBE n
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/Makefile linux/drivers/mtd/devices/Makefile
---- linux-mips-2.4.27/drivers/mtd/devices/Makefile 2002-03-30 09:15:50.000000000 +0100
-+++ linux/drivers/mtd/devices/Makefile 2004-11-19 10:25:11.813212864 +0100
-@@ -1,9 +1,12 @@
- #
- # linux/drivers/devices/Makefile
- #
--# $Id$
-+# $Id$
-
-+ifeq ($(PATCHLEVEL),4)
- O_TARGET := devlink.o
-+export-objs := docecc.o
-+endif
-
- # *** BIG UGLY NOTE ***
- #
-@@ -12,15 +15,16 @@
- # here where previously there was none. We now have to ensure that
- # doc200[01].o are linked before docprobe.o
-
--obj-$(CONFIG_MTD_DOC1000) += doc1000.o
- obj-$(CONFIG_MTD_DOC2000) += doc2000.o
- obj-$(CONFIG_MTD_DOC2001) += doc2001.o
-+obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
- obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o
- obj-$(CONFIG_MTD_SLRAM) += slram.o
-+obj-$(CONFIG_MTD_PHRAM) += phram.o
- obj-$(CONFIG_MTD_PMC551) += pmc551.o
- obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
- obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
- obj-$(CONFIG_MTD_LART) += lart.o
- obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
-
--include $(TOPDIR)/Rules.make
-+-include $(TOPDIR)/Rules.make
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/blkmtd-25.c linux/drivers/mtd/devices/blkmtd-25.c
---- linux-mips-2.4.27/drivers/mtd/devices/blkmtd-25.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/devices/blkmtd-25.c 2004-11-19 10:25:11.814212712 +0100
-@@ -0,0 +1,827 @@
-+/*
-+ * $Id$
-+ *
-+ * blkmtd.c - use a block device as a fake MTD
-+ *
-+ * Author: Simon Evans <spse@secret.org.uk>
-+ *
-+ * Copyright (C) 2001,2002 Simon Evans
-+ *
-+ * Licence: GPL
-+ *
-+ * How it works:
-+ * The driver uses raw/io to read/write the device and the page
-+ * cache to cache access. Writes update the page cache with the
-+ * new data and mark it dirty and add the page into a BIO which
-+ * is then written out.
-+ *
-+ * It can be loaded Read-Only to prevent erases and writes to the
-+ * medium.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/bio.h>
-+#include <linux/pagemap.h>
-+#include <linux/list.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+
-+
-+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
-+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
-+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
-+
-+
-+/* Default erase size in K, always make it a multiple of PAGE_SIZE */
-+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
-+#define VERSION "$Revision$"
-+
-+/* Info for the block device */
-+struct blkmtd_dev {
-+ struct list_head list;
-+ struct block_device *blkdev;
-+ struct mtd_info mtd_info;
-+ struct semaphore wrbuf_mutex;
-+};
-+
-+
-+/* Static info about the MTD, used in cleanup_module */
-+static LIST_HEAD(blkmtd_device_list);
-+
-+
-+static void blkmtd_sync(struct mtd_info *mtd);
-+
-+#define MAX_DEVICES 4
-+
-+/* Module parameters passed by insmod/modprobe */
-+char *device[MAX_DEVICES]; /* the block device to use */
-+int erasesz[MAX_DEVICES]; /* optional default erase size */
-+int ro[MAX_DEVICES]; /* optional read only flag */
-+int sync;
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-+MODULE_DESCRIPTION("Emulate an MTD using a block device");
-+MODULE_PARM(device, "1-4s");
-+MODULE_PARM_DESC(device, "block device to use");
-+MODULE_PARM(erasesz, "1-4i");
-+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-+MODULE_PARM(ro, "1-4i");
-+MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-+MODULE_PARM(sync, "i");
-+MODULE_PARM_DESC(sync, "1=Synchronous writes");
-+
-+
-+/* completion handler for BIO reads */
-+static int bi_read_complete(struct bio *bio, unsigned int bytes_done, int error)
-+{
-+ if (bio->bi_size)
-+ return 1;
-+
-+ complete((struct completion*)bio->bi_private);
-+ return 0;
-+}
-+
-+
-+/* completion handler for BIO writes */
-+static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error)
-+{
-+ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-+
-+ if (bio->bi_size)
-+ return 1;
-+
-+ if(!uptodate)
-+ err("bi_write_complete: not uptodate\n");
-+
-+ do {
-+ struct page *page = bvec->bv_page;
-+ DEBUG(3, "Cleaning up page %ld\n", page->index);
-+ if (--bvec >= bio->bi_io_vec)
-+ prefetchw(&bvec->bv_page->flags);
-+
-+ if (uptodate) {
-+ SetPageUptodate(page);
-+ } else {
-+ ClearPageUptodate(page);
-+ SetPageError(page);
-+ }
-+ ClearPageDirty(page);
-+ unlock_page(page);
-+ page_cache_release(page);
-+ } while (bvec >= bio->bi_io_vec);
-+
-+ complete((struct completion*)bio->bi_private);
-+ return 0;
-+}
-+
-+
-+/* read one page from the block device */
-+static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page)
-+{
-+ struct bio *bio;
-+ struct completion event;
-+ int err = -ENOMEM;
-+
-+ if(PageUptodate(page)) {
-+ DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
-+ unlock_page(page);
-+ return 0;
-+ }
-+
-+ ClearPageUptodate(page);
-+ ClearPageError(page);
-+
-+ bio = bio_alloc(GFP_KERNEL, 1);
-+ if(bio) {
-+ init_completion(&event);
-+ bio->bi_bdev = dev->blkdev;
-+ bio->bi_sector = page->index << (PAGE_SHIFT-9);
-+ bio->bi_private = &event;
-+ bio->bi_end_io = bi_read_complete;
-+ if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) {
-+ submit_bio(READ, bio);
-+ blk_run_queues();
-+ wait_for_completion(&event);
-+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
-+ bio_put(bio);
-+ }
-+ }
-+
-+ if(err)
-+ SetPageError(page);
-+ else
-+ SetPageUptodate(page);
-+ flush_dcache_page(page);
-+ unlock_page(page);
-+ return err;
-+}
-+
-+
-+/* write out the current BIO and wait for it to finish */
-+static int blkmtd_write_out(struct bio *bio)
-+{
-+ struct completion event;
-+ int err;
-+
-+ if(!bio->bi_vcnt) {
-+ bio_put(bio);
-+ return 0;
-+ }
-+
-+ init_completion(&event);
-+ bio->bi_private = &event;
-+ bio->bi_end_io = bi_write_complete;
-+ submit_bio(WRITE, bio);
-+ blk_run_queues();
-+ wait_for_completion(&event);
-+ DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt);
-+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
-+ bio_put(bio);
-+ return err;
-+}
-+
-+
-+/**
-+ * blkmtd_add_page - add a page to the current BIO
-+ * @bio: bio to add to (NULL to alloc initial bio)
-+ * @blkdev: block device
-+ * @page: page to add
-+ * @pagecnt: pages left to add
-+ *
-+ * Adds a page to the current bio, allocating it if necessary. If it cannot be
-+ * added, the current bio is written out and a new one is allocated. Returns
-+ * the new bio to add or NULL on error
-+ */
-+static struct bio *blkmtd_add_page(struct bio *bio, struct block_device *blkdev,
-+ struct page *page, int pagecnt)
-+{
-+
-+ retry:
-+ if(!bio) {
-+ bio = bio_alloc(GFP_KERNEL, pagecnt);
-+ if(!bio)
-+ return NULL;
-+ bio->bi_sector = page->index << (PAGE_SHIFT-9);
-+ bio->bi_bdev = blkdev;
-+ }
-+
-+ if(bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE) {
-+ blkmtd_write_out(bio);
-+ bio = NULL;
-+ goto retry;
-+ }
-+ return bio;
-+}
-+
-+
-+/**
-+ * write_pages - write block of data to device via the page cache
-+ * @dev: device to write to
-+ * @buf: data source or NULL if erase (output is set to 0xff)
-+ * @to: offset into output device
-+ * @len: amount to data to write
-+ * @retlen: amount of data written
-+ *
-+ * Grab pages from the page cache and fill them with the source data.
-+ * Non page aligned start and end result in a readin of the page and
-+ * part of the page being modified. Pages are added to the bio and then written
-+ * out.
-+ */
-+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
-+ size_t len, size_t *retlen)
-+{
-+ int pagenr, offset;
-+ size_t start_len = 0, end_len;
-+ int pagecnt = 0;
-+ int err = 0;
-+ struct bio *bio = NULL;
-+ size_t thislen = 0;
-+
-+ pagenr = to >> PAGE_SHIFT;
-+ offset = to & ~PAGE_MASK;
-+
-+ DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n",
-+ buf, (long)to, len, pagenr, offset);
-+
-+ /* see if we have to do a partial write at the start */
-+ if(offset) {
-+ start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
-+ len -= start_len;
-+ }
-+
-+ /* calculate the length of the other two regions */
-+ end_len = len & ~PAGE_MASK;
-+ len -= end_len;
-+
-+ if(start_len)
-+ pagecnt++;
-+
-+ if(len)
-+ pagecnt += len >> PAGE_SHIFT;
-+
-+ if(end_len)
-+ pagecnt++;
-+
-+ down(&dev->wrbuf_mutex);
-+
-+ DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n",
-+ start_len, len, end_len, pagecnt);
-+
-+ if(start_len) {
-+ /* do partial start region */
-+ struct page *page;
-+
-+ DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n",
-+ pagenr, start_len, offset);
-+
-+ BUG_ON(!buf);
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ lock_page(page);
-+ if(PageDirty(page)) {
-+ err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n",
-+ to, start_len, len, end_len, pagenr);
-+ BUG();
-+ }
-+ memcpy(page_address(page)+offset, buf, start_len);
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ buf += start_len;
-+ thislen = start_len;
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
-+ }
-+ pagecnt--;
-+ pagenr++;
-+ }
-+
-+ /* Now do the main loop to a page aligned, n page sized output */
-+ if(len) {
-+ int pagesc = len >> PAGE_SHIFT;
-+ DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
-+ pagenr, pagesc);
-+ while(pagesc) {
-+ struct page *page;
-+
-+ /* see if page is in the page cache */
-+ DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-+ page = grab_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr);
-+ if(PageDirty(page)) {
-+ BUG();
-+ }
-+ if(!page) {
-+ warn("write: cannot grab cache page %d", pagenr);
-+ err = -ENOMEM;
-+ goto write_err;
-+ }
-+ if(!buf) {
-+ memset(page_address(page), 0xff, PAGE_SIZE);
-+ } else {
-+ memcpy(page_address(page), buf, PAGE_SIZE);
-+ buf += PAGE_SIZE;
-+ }
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
-+ }
-+ pagenr++;
-+ pagecnt--;
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ pagesc--;
-+ thislen += PAGE_SIZE;
-+ }
-+ }
-+
-+ if(end_len) {
-+ /* do the third region */
-+ struct page *page;
-+ DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n",
-+ pagenr, end_len);
-+ BUG_ON(!buf);
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ lock_page(page);
-+ if(PageDirty(page)) {
-+ err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n",
-+ to, start_len, len, end_len, pagenr);
-+ BUG();
-+ }
-+ memcpy(page_address(page), buf, end_len);
-+ SetPageDirty(page);
-+ SetPageUptodate(page);
-+ DEBUG(3, "blkmtd: write: writing out partial end\n");
-+ thislen += end_len;
-+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
-+ if(!bio) {
-+ err = -ENOMEM;
-+ err("bio_add_page failed\n");
-+ goto write_err;
-+ }
-+ pagenr++;
-+ }
-+
-+ DEBUG(3, "blkmtd: write: got %d vectors to write\n", bio->bi_vcnt);
-+ write_err:
-+ if(bio)
-+ blkmtd_write_out(bio);
-+
-+ DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
-+ up(&dev->wrbuf_mutex);
-+
-+ if(retlen)
-+ *retlen = thislen;
-+ return err;
-+}
-+
-+
-+/* erase a specified part of the device */
-+static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ struct mtd_erase_region_info *einfo = mtd->eraseregions;
-+ int numregions = mtd->numeraseregions;
-+ size_t from;
-+ u_long len;
-+ int err = -EIO;
-+ int retlen;
-+
-+ instr->state = MTD_ERASING;
-+ from = instr->addr;
-+ len = instr->len;
-+
-+ /* check erase region has valid start and length */
-+ DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
-+ mtd->name+9, from, len);
-+ while(numregions) {
-+ DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-+ einfo->offset, einfo->erasesize, einfo->numblocks);
-+ if(from >= einfo->offset
-+ && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-+ if(len == einfo->erasesize
-+ && ( (from - einfo->offset) % einfo->erasesize == 0))
-+ break;
-+ }
-+ numregions--;
-+ einfo++;
-+ }
-+
-+ if(!numregions) {
-+ /* Not a valid erase block */
-+ err("erase: invalid erase request 0x%lX @ 0x%08X", len, from);
-+ instr->state = MTD_ERASE_FAILED;
-+ err = -EIO;
-+ }
-+
-+ if(instr->state != MTD_ERASE_FAILED) {
-+ /* do the erase */
-+ DEBUG(3, "Doing erase from = %d len = %ld\n", from, len);
-+ err = write_pages(dev, NULL, from, len, &retlen);
-+ if(err || retlen != len) {
-+ err("erase failed err = %d", err);
-+ instr->state = MTD_ERASE_FAILED;
-+ } else {
-+ instr->state = MTD_ERASE_DONE;
-+ }
-+ }
-+
-+ DEBUG(3, "blkmtd: erase: checking callback\n");
-+ if (instr->callback) {
-+ (*(instr->callback))(instr);
-+ }
-+ DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
-+ return err;
-+}
-+
-+
-+/* read a range of the data via the page cache */
-+static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ int err = 0;
-+ int offset;
-+ int pagenr, pages;
-+ size_t thislen = 0;
-+
-+ DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
-+ mtd->name+9, (long int)from, len, buf);
-+
-+ if(from > mtd->size)
-+ return -EINVAL;
-+ if(from + len > mtd->size)
-+ len = mtd->size - from;
-+
-+ pagenr = from >> PAGE_SHIFT;
-+ offset = from - (pagenr << PAGE_SHIFT);
-+
-+ pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
-+ DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
-+ pagenr, offset, pages);
-+
-+ while(pages) {
-+ struct page *page;
-+ int cpylen;
-+
-+ DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
-+ if(IS_ERR(page)) {
-+ err = -EIO;
-+ goto readerr;
-+ }
-+
-+ cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
-+ if(offset+cpylen > PAGE_SIZE)
-+ cpylen = PAGE_SIZE-offset;
-+
-+ memcpy(buf + thislen, page_address(page) + offset, cpylen);
-+ offset = 0;
-+ len -= cpylen;
-+ thislen += cpylen;
-+ pagenr++;
-+ pages--;
-+ if(!PageDirty(page))
-+ page_cache_release(page);
-+ }
-+
-+ readerr:
-+ if(retlen)
-+ *retlen = thislen;
-+ DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", thislen, err);
-+ return err;
-+}
-+
-+
-+/* write data to the underlying device */
-+static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ struct blkmtd_dev *dev = mtd->priv;
-+ int err;
-+
-+ if(!len)
-+ return 0;
-+
-+ DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
-+ mtd->name+9, (long int)to, len, buf);
-+
-+ if(to >= mtd->size) {
-+ return -ENOSPC;
-+ }
-+
-+ if(to + len > mtd->size) {
-+ len = mtd->size - to;
-+ }
-+
-+ err = write_pages(dev, buf, to, len, retlen);
-+ if(err > 0)
-+ err = 0;
-+ DEBUG(2, "blkmtd: write: end, err = %d\n", err);
-+ return err;
-+}
-+
-+
-+/* sync the device - wait until the write queue is empty */
-+static void blkmtd_sync(struct mtd_info *mtd)
-+{
-+ /* Currently all writes are synchronous */
-+}
-+
-+
-+static void free_device(struct blkmtd_dev *dev)
-+{
-+ DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
-+ if(dev) {
-+ if(dev->mtd_info.eraseregions)
-+ kfree(dev->mtd_info.eraseregions);
-+ if(dev->mtd_info.name)
-+ kfree(dev->mtd_info.name);
-+
-+ if(dev->blkdev) {
-+ invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
-+ close_bdev_excl(dev->blkdev, BDEV_RAW);
-+ }
-+ kfree(dev);
-+ }
-+}
-+
-+
-+/* For a given size and initial erase size, calculate the number
-+ * and size of each erase region. Goes round the loop twice,
-+ * once to find out how many regions, then allocates space,
-+ * then round the loop again to fill it in.
-+ */
-+static struct mtd_erase_region_info *calc_erase_regions(
-+ size_t erase_size, size_t total_size, int *regions)
-+{
-+ struct mtd_erase_region_info *info = NULL;
-+
-+ DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n",
-+ erase_size, total_size, *regions);
-+ /* Make any user specified erasesize be a power of 2
-+ and at least PAGE_SIZE */
-+ if(erase_size) {
-+ int es = erase_size;
-+ erase_size = 1;
-+ while(es != 1) {
-+ es >>= 1;
-+ erase_size <<= 1;
-+ }
-+ if(erase_size < PAGE_SIZE)
-+ erase_size = PAGE_SIZE;
-+ } else {
-+ erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-+ }
-+
-+ *regions = 0;
-+
-+ do {
-+ int tot_size = total_size;
-+ int er_size = erase_size;
-+ int count = 0, offset = 0, regcnt = 0;
-+
-+ while(tot_size) {
-+ count = tot_size / er_size;
-+ if(count) {
-+ tot_size = tot_size % er_size;
-+ if(info) {
-+ DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
-+ offset, er_size, count);
-+ (info+regcnt)->offset = offset;
-+ (info+regcnt)->erasesize = er_size;
-+ (info+regcnt)->numblocks = count;
-+ (*regions)++;
-+ }
-+ regcnt++;
-+ offset += (count * er_size);
-+ }
-+ while(er_size > tot_size)
-+ er_size >>= 1;
-+ }
-+ if(info == NULL) {
-+ info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-+ if(!info)
-+ break;
-+ }
-+ } while(!(*regions));
-+ DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n",
-+ erase_size, total_size, *regions);
-+ return info;
-+}
-+
-+
-+extern dev_t __init name_to_dev_t(const char *line);
-+
-+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
-+{
-+ struct block_device *bdev;
-+ int mode;
-+ struct blkmtd_dev *dev;
-+
-+ if(!devname)
-+ return NULL;
-+
-+ /* Get a handle on the device */
-+
-+
-+#ifdef MODULE
-+ mode = (readonly) ? O_RDONLY : O_RDWR;
-+ bdev = open_bdev_excl(devname, mode, BDEV_RAW, NULL);
-+#else
-+ mode = (readonly) ? FMODE_READ : FMODE_WRITE;
-+ bdev = open_by_devnum(name_to_dev_t(devname), mode, BDEV_RAW);
-+#endif
-+ if(IS_ERR(bdev)) {
-+ err("error: cannot open device %s", devname);
-+ DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
-+ return NULL;
-+ }
-+
-+ DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-+ MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-+
-+ if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-+ err("attempting to use an MTD device as a block device");
-+ blkdev_put(bdev, BDEV_RAW);
-+ return NULL;
-+ }
-+
-+ dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-+ if(dev == NULL) {
-+ blkdev_put(bdev, BDEV_RAW);
-+ return NULL;
-+ }
-+
-+ memset(dev, 0, sizeof(struct blkmtd_dev));
-+ if(!readonly) {
-+ init_MUTEX(&dev->wrbuf_mutex);
-+ }
-+
-+ dev->blkdev = bdev;
-+ dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
-+
-+ /* Setup the MTD structure */
-+ /* make the name contain the block device in */
-+ dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
-+ if(dev->mtd_info.name == NULL)
-+ goto devinit_err;
-+
-+ sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
-+ dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
-+ &dev->mtd_info.numeraseregions);
-+ if(dev->mtd_info.eraseregions == NULL)
-+ goto devinit_err;
-+
-+ dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
-+ DEBUG(1, "blkmtd: init: found %d erase regions\n",
-+ dev->mtd_info.numeraseregions);
-+
-+ if(readonly) {
-+ dev->mtd_info.type = MTD_ROM;
-+ dev->mtd_info.flags = MTD_CAP_ROM;
-+ } else {
-+ dev->mtd_info.type = MTD_RAM;
-+ dev->mtd_info.flags = MTD_CAP_RAM;
-+ dev->mtd_info.erase = blkmtd_erase;
-+ dev->mtd_info.write = blkmtd_write;
-+ dev->mtd_info.writev = default_mtd_writev;
-+ dev->mtd_info.sync = blkmtd_sync;
-+ }
-+ dev->mtd_info.read = blkmtd_read;
-+ dev->mtd_info.readv = default_mtd_readv;
-+ dev->mtd_info.priv = dev;
-+ dev->mtd_info.owner = THIS_MODULE;
-+
-+ list_add(&dev->list, &blkmtd_device_list);
-+ if (add_mtd_device(&dev->mtd_info)) {
-+ /* Device didnt get added, so free the entry */
-+ list_del(&dev->list);
-+ goto devinit_err;
-+ } else {
-+ info("mtd%d: [%s] erase_size = %dKiB %s",
-+ dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
-+ dev->mtd_info.erasesize >> 10,
-+ readonly ? "(read-only)" : "");
-+ }
-+
-+ return dev;
-+
-+ devinit_err:
-+ free_device(dev);
-+ return NULL;
-+}
-+
-+
-+/* Cleanup and exit - sync the device and kill of the kernel thread */
-+static void __devexit cleanup_blkmtd(void)
-+{
-+ struct list_head *temp1, *temp2;
-+
-+ /* Remove the MTD devices */
-+ list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-+ struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-+ list);
-+ blkmtd_sync(&dev->mtd_info);
-+ del_mtd_device(&dev->mtd_info);
-+ info("mtd%d: [%s] removed", dev->mtd_info.index,
-+ dev->mtd_info.name + strlen("blkmtd: "));
-+ list_del(&dev->list);
-+ free_device(dev);
-+ }
-+}
-+
-+#ifndef MODULE
-+
-+/* Handle kernel boot params */
-+
-+
-+static int __init param_blkmtd_device(char *str)
-+{
-+ int i;
-+
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ device[i] = str;
-+ DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
-+ strsep(&str, ",");
-+ }
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_erasesz(char *str)
-+{
-+ int i;
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ char *val = strsep(&str, ",");
-+ if(val)
-+ erasesz[i] = simple_strtoul(val, NULL, 0);
-+ DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
-+ }
-+
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_ro(char *str)
-+{
-+ int i;
-+ for(i = 0; i < MAX_DEVICES; i++) {
-+ char *val = strsep(&str, ",");
-+ if(val)
-+ ro[i] = simple_strtoul(val, NULL, 0);
-+ DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
-+ }
-+
-+ return 1;
-+}
-+
-+
-+static int __init param_blkmtd_sync(char *str)
-+{
-+ if(str[0] == '1')
-+ sync = 1;
-+ return 1;
-+}
-+
-+__setup("blkmtd_device=", param_blkmtd_device);
-+__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-+__setup("blkmtd_ro=", param_blkmtd_ro);
-+__setup("blkmtd_sync=", param_blkmtd_sync);
-+
-+#endif
-+
-+
-+/* Startup */
-+static int __init init_blkmtd(void)
-+{
-+ int i;
-+
-+ info("version " VERSION);
-+ /* Check args - device[0] is the bare minimum*/
-+ if(!device[0]) {
-+ err("error: missing `device' name\n");
-+ return -EINVAL;
-+ }
-+
-+ for(i = 0; i < MAX_DEVICES; i++)
-+ add_device(device[i], ro[i], erasesz[i] << 10);
-+
-+ if(list_empty(&blkmtd_device_list))
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+module_init(init_blkmtd);
-+module_exit(cleanup_blkmtd);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/blkmtd.c linux/drivers/mtd/devices/blkmtd.c
---- linux-mips-2.4.27/drivers/mtd/devices/blkmtd.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/blkmtd.c 2004-11-19 10:25:11.816212408 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * blkmtd.c - use a block device as a fake MTD
- *
-@@ -143,7 +143,7 @@
- for(cnt = 0; cnt < pages; cnt++) {
- page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
- pagelst[cnt] = page;
-- if(!PageUptodate(page)) {
-+ if(!Page_Uptodate(page)) {
- iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
- iobuf->maplist[iobuf->nr_pages++] = page;
- }
-@@ -912,7 +912,7 @@
- dev->mtd_info.point = 0;
- dev->mtd_info.unpoint = 0;
- dev->mtd_info.priv = dev;
-- dev->mtd_info.module = THIS_MODULE;
-+ dev->mtd_info.owner = THIS_MODULE;
-
- list_add(&dev->list, &blkmtd_device_list);
- if (add_mtd_device(&dev->mtd_info)) {
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c
---- linux-mips-2.4.27/drivers/mtd/devices/doc2000.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/doc2000.c 2004-11-19 10:25:11.818212104 +0100
-@@ -4,7 +4,7 @@
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/kernel.h>
-@@ -25,6 +25,7 @@
- #include <linux/mtd/doc2000.h>
-
- #define DOC_SUPPORT_2000
-+#define DOC_SUPPORT_2000TSOP
- #define DOC_SUPPORT_MILLENNIUM
-
- #ifdef DOC_SUPPORT_2000
-@@ -33,7 +34,7 @@
- #define DoC_is_2000(doc) (0)
- #endif
-
--#ifdef DOC_SUPPORT_MILLENNIUM
-+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
- #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
- #else
- #define DoC_is_Millennium(doc) (0)
-@@ -56,6 +57,9 @@
- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
- static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen,
-+ u_char *eccbuf, struct nand_oobinfo *oobsel);
- static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, u_char *buf);
- static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-@@ -92,6 +96,10 @@
-
- /* Out-of-line routine to wait for chip response */
- while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+ /* issue 2 read from NOP register after reading from CDSNControl register
-+ see Software Requirement 11.4 item 2. */
-+ DoC_Delay(doc, 2);
-+
- if (time_after(jiffies, timeo)) {
- DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
- return -EIO;
-@@ -145,6 +153,8 @@
-
- /* Send the command */
- WriteDOC_(command, docptr, doc->ioreg);
-+ if (DoC_is_Millennium(doc))
-+ WriteDOC(command, docptr, WritePipeTerm);
-
- /* Lower the CLE line */
- WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
-@@ -206,6 +216,9 @@
- }
- }
-
-+ if (DoC_is_Millennium(doc))
-+ WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
-+
- DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */
-
- /* FIXME: The SlowIO's for millennium could be replaced by
-@@ -344,15 +357,25 @@
-
- /* Read the manufacturer and device id codes from the device */
-
-- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-+ if (DoC_is_Millennium(doc)) {
-+ DoC_Delay(doc, 2);
-+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
-+ mfr = ReadDOC(doc->virtadr, LastDataRead);
-+
-+ DoC_Delay(doc, 2);
-+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
-+ id = ReadDOC(doc->virtadr, LastDataRead);
-+ } else {
-+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- mfr = ReadDOC_(doc->virtadr, doc->ioreg);
-
-- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- id = ReadDOC_(doc->virtadr, doc->ioreg);
-+ }
-
- /* No response - return failure */
- if (mfr == 0xff || mfr == 0)
-@@ -410,20 +433,16 @@
-
- /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
-
--static void DoC_ScanChips(struct DiskOnChip *this)
-+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
- {
- int floor, chip;
- int numchips[MAX_FLOORS];
-- int maxchips = MAX_CHIPS;
- int ret = 1;
-
- this->numchips = 0;
- this->mfr = 0;
- this->id = 0;
-
-- if (DoC_is_Millennium(this))
-- maxchips = MAX_CHIPS_MIL;
--
- /* For each floor, find the number of valid chips it contains */
- for (floor = 0; floor < MAX_FLOORS; floor++) {
- ret = 1;
-@@ -515,6 +534,7 @@
- {
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
- struct DiskOnChip *old = NULL;
-+ int maxchips;
-
- /* We must avoid being called twice for the same device. */
-
-@@ -538,14 +558,28 @@
-
-
- switch (this->ChipID) {
-+ case DOC_ChipID_Doc2kTSOP:
-+ mtd->name = "DiskOnChip 2000 TSOP";
-+ this->ioreg = DoC_Mil_CDSN_IO;
-+ /* Pretend it's a Millennium */
-+ this->ChipID = DOC_ChipID_DocMil;
-+ maxchips = MAX_CHIPS;
-+ break;
- case DOC_ChipID_Doc2k:
- mtd->name = "DiskOnChip 2000";
- this->ioreg = DoC_2k_CDSN_IO;
-+ maxchips = MAX_CHIPS;
- break;
- case DOC_ChipID_DocMil:
- mtd->name = "DiskOnChip Millennium";
- this->ioreg = DoC_Mil_CDSN_IO;
-+ maxchips = MAX_CHIPS_MIL;
- break;
-+ default:
-+ printk("Unknown ChipID 0x%02x\n", this->ChipID);
-+ kfree(mtd);
-+ iounmap((void *) this->virtadr);
-+ return;
- }
-
- printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
-@@ -553,11 +587,12 @@
-
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
- mtd->size = 0;
- mtd->erasesize = 0;
- mtd->oobblock = 512;
- mtd->oobsize = 16;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = doc_erase;
- mtd->point = NULL;
- mtd->unpoint = NULL;
-@@ -565,6 +600,7 @@
- mtd->write = doc_write;
- mtd->read_ecc = doc_read_ecc;
- mtd->write_ecc = doc_write_ecc;
-+ mtd->writev_ecc = doc_writev_ecc;
- mtd->read_oob = doc_read_oob;
- mtd->write_oob = doc_write_oob;
- mtd->sync = NULL;
-@@ -577,7 +613,7 @@
- init_MUTEX(&this->lock);
-
- /* Ident all the chips present. */
-- DoC_ScanChips(this);
-+ DoC_ScanChips(this, maxchips);
-
- if (!this->totlen) {
- kfree(mtd);
-@@ -608,6 +644,7 @@
- unsigned char syndrome[6];
- volatile char dummy;
- int i, len256 = 0, ret=0;
-+ size_t left = len;
-
- docptr = this->virtadr;
-
-@@ -617,6 +654,10 @@
-
- down(&this->lock);
-
-+ *retlen = 0;
-+ while (left) {
-+ len = left;
-+
- /* Don't allow a single read to cross a 512-byte block boundary */
- if (from + len > ((from | 0x1ff) + 1))
- len = ((from | 0x1ff) + 1) - from;
-@@ -673,7 +714,7 @@
- DoC_ReadBuf(this, &buf[len256], len - len256);
-
- /* Let the caller know we completed it */
-- *retlen = len;
-+ *retlen += len;
-
- if (eccbuf) {
- /* Read the ECC data through the DiskOnChip ECC logic */
-@@ -730,11 +771,16 @@
-
- /* according to 11.4.1, we need to wait for the busy line
- * drop if we read to the end of the page. */
-- if(0 == ((from + *retlen) & 0x1ff))
-+ if(0 == ((from + len) & 0x1ff))
- {
- DoC_WaitReady(this);
- }
-
-+ from += len;
-+ left -= len;
-+ buf += len;
-+ }
-+
- up(&this->lock);
-
- return ret;
-@@ -757,6 +803,8 @@
- volatile char dummy;
- int len256 = 0;
- struct Nand *mychip;
-+ size_t left = len;
-+ int status;
-
- docptr = this->virtadr;
-
-@@ -766,15 +814,21 @@
-
- down(&this->lock);
-
-+ *retlen = 0;
-+ while (left) {
-+ len = left;
-+
- /* Don't allow a single write to cross a 512-byte block boundary */
- if (to + len > ((to | 0x1ff) + 1))
- len = ((to | 0x1ff) + 1) - to;
-
- /* The ECC will not be calculated correctly if less than 512 is written */
-+/* DBB-
- if (len != 0x200 && eccbuf)
- printk(KERN_WARNING
- "ECC needs a full sector write (adr: %lx size %lx)\n",
- (long) to, (long) len);
-+ -DBB */
-
- /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
-
-@@ -853,6 +907,9 @@
- WriteDOC_(0, docptr, this->ioreg);
- }
-
-+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
-+ CDSNControl);
-+
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (di = 0; di < 6; di++) {
- eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-@@ -874,10 +931,16 @@
- DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
- /* There's an implicit DoC_WaitReady() in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming flash\n");
- /* Error in programming */
- *retlen = 0;
-@@ -886,7 +949,7 @@
- }
-
- /* Let the caller know we completed it */
-- *retlen = len;
-+ *retlen += len;
-
- if (eccbuf) {
- unsigned char x[8];
-@@ -901,13 +964,81 @@
- x[7]=0x55;
-
- ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
-+ if (ret) {
- up(&this->lock);
- return ret;
- }
-+ }
-+
-+ to += len;
-+ left -= len;
-+ buf += len;
-+ }
-+
- up(&this->lock);
- return 0;
- }
-
-+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen,
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
-+{
-+ static char static_buf[512];
-+ static DECLARE_MUTEX(writev_buf_sem);
-+
-+ size_t totretlen = 0;
-+ size_t thisvecofs = 0;
-+ int ret= 0;
-+
-+ down(&writev_buf_sem);
-+
-+ while(count) {
-+ size_t thislen, thisretlen;
-+ unsigned char *buf;
-+
-+ buf = vecs->iov_base + thisvecofs;
-+ thislen = vecs->iov_len - thisvecofs;
-+
-+
-+ if (thislen >= 512) {
-+ thislen = thislen & ~(512-1);
-+ thisvecofs += thislen;
-+ } else {
-+ /* Not enough to fill a page. Copy into buf */
-+ memcpy(static_buf, buf, thislen);
-+ buf = &static_buf[thislen];
-+
-+ while(count && thislen < 512) {
-+ vecs++;
-+ count--;
-+ thisvecofs = min((512-thislen), vecs->iov_len);
-+ memcpy(buf, vecs->iov_base, thisvecofs);
-+ thislen += thisvecofs;
-+ buf += thisvecofs;
-+ }
-+ buf = static_buf;
-+ }
-+ if (count && thisvecofs == vecs->iov_len) {
-+ thisvecofs = 0;
-+ vecs++;
-+ count--;
-+ }
-+ ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
-+
-+ totretlen += thisretlen;
-+
-+ if (ret || thisretlen != thislen)
-+ break;
-+
-+ to += thislen;
-+ }
-+
-+ up(&writev_buf_sem);
-+ *retlen = totretlen;
-+ return ret;
-+}
-+
-+
- static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t * retlen, u_char * buf)
- {
-@@ -977,6 +1108,7 @@
- unsigned long docptr = this->virtadr;
- struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- volatile int dummy;
-+ int status;
-
- // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
- // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
-@@ -1025,10 +1157,16 @@
- DoC_Command(this, NAND_CMD_STATUS, 0);
- /* DoC_WaitReady() is implicit in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming oob data\n");
- /* There was an error */
- *retlen = 0;
-@@ -1044,10 +1182,16 @@
- DoC_Command(this, NAND_CMD_STATUS, 0);
- /* DoC_WaitReady() is implicit in DoC_Command */
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error programming oob data\n");
- /* There was an error */
- *retlen = 0;
-@@ -1080,6 +1224,7 @@
- volatile int dummy;
- unsigned long docptr;
- struct Nand *mychip;
-+ int status;
-
- down(&this->lock);
-
-@@ -1111,10 +1256,16 @@
-
- DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-
-+ if (DoC_is_Millennium(this)) {
-+ ReadDOC(docptr, ReadPipeInit);
-+ status = ReadDOC(docptr, LastDataRead);
-+ } else {
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-+ status = ReadDOC_(docptr, this->ioreg);
-+ }
-
-- if (ReadDOC_(docptr, this->ioreg) & 1) {
-+ if (status & 1) {
- printk(KERN_ERR "Error erasing at 0x%x\n", ofs);
- /* There was an error */
- instr->state = MTD_ERASE_FAILED;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2001.c linux/drivers/mtd/devices/doc2001.c
---- linux-mips-2.4.27/drivers/mtd/devices/doc2001.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/doc2001.c 2004-11-19 10:25:11.835209520 +0100
-@@ -4,7 +4,7 @@
- * (c) 1999 Machine Vision Holdings, Inc.
- * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/kernel.h>
-@@ -359,14 +359,15 @@
-
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
- mtd->size = 0;
-
-- /* FIXME: erase size is not always 8kB */
-+ /* FIXME: erase size is not always 8KiB */
- mtd->erasesize = 0x2000;
-
- mtd->oobblock = 512;
- mtd->oobsize = 16;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = doc_erase;
- mtd->point = NULL;
- mtd->unpoint = NULL;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2001plus.c linux/drivers/mtd/devices/doc2001plus.c
---- linux-mips-2.4.27/drivers/mtd/devices/doc2001plus.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/devices/doc2001plus.c 2004-11-19 10:25:11.837209216 +0100
-@@ -0,0 +1,1154 @@
-+/*
-+ * Linux driver for Disk-On-Chip Millennium Plus
-+ *
-+ * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com>
-+ * (c) 2002-2003 SnapGear Inc
-+ * (c) 1999 Machine Vision Holdings, Inc.
-+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * $Id$
-+ *
-+ * Released under GPL
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+#include <linux/miscdevice.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/doc2000.h>
-+
-+/* #define ECC_DEBUG */
-+
-+/* I have no idea why some DoC chips can not use memcop_form|to_io().
-+ * This may be due to the different revisions of the ASIC controller built-in or
-+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
-+ * this:*/
-+#undef USE_MEMCPY
-+
-+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf);
-+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf);
-+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel);
-+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel);
-+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, u_char *buf);
-+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, const u_char *buf);
-+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
-+
-+static struct mtd_info *docmilpluslist = NULL;
-+
-+
-+/* Perform the required delay cycles by writing to the NOP register */
-+static void DoC_Delay(unsigned long docptr, int cycles)
-+{
-+ int i;
-+
-+ for (i = 0; (i < cycles); i++)
-+ WriteDOC(0, docptr, Mplus_NOP);
-+}
-+
-+#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
-+
-+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
-+static int _DoC_WaitReady(unsigned long docptr)
-+{
-+ unsigned int c = 0xffff;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3,
-+ "_DoC_WaitReady called for out-of-line wait\n");
-+
-+ /* Out-of-line routine to wait for chip response */
-+ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c)
-+ ;
-+
-+ if (c == 0)
-+ DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
-+
-+ return (c == 0);
-+}
-+
-+static inline int DoC_WaitReady(unsigned long docptr)
-+{
-+ /* This is inline, to optimise the common case, where it's ready instantly */
-+ int ret = 0;
-+
-+ /* read form NOP register should be issued prior to the read from CDSNControl
-+ see Software Requirement 11.4 item 2. */
-+ DoC_Delay(docptr, 4);
-+
-+ if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
-+ /* Call the out-of-line routine to wait */
-+ ret = _DoC_WaitReady(docptr);
-+
-+ return ret;
-+}
-+
-+/* For some reason the Millennium Plus seems to occassionally put itself
-+ * into reset mode. For me this happens randomly, with no pattern that I
-+ * can detect. M-systems suggest always check this on any block level
-+ * operation and setting to normal mode if in reset mode.
-+ */
-+static inline void DoC_CheckASIC(unsigned long docptr)
-+{
-+ /* Make sure the DoC is in normal mode */
-+ if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) {
-+ WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl);
-+ WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm);
-+ }
-+}
-+
-+/* DoC_Command: Send a flash command to the flash chip through the Flash
-+ * command register. Need 2 Write Pipeline Terminates to complete send.
-+ */
-+static inline void DoC_Command(unsigned long docptr, unsigned char command,
-+ unsigned char xtraflags)
-+{
-+ WriteDOC(command, docptr, Mplus_FlashCmd);
-+ WriteDOC(command, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(command, docptr, Mplus_WritePipeTerm);
-+}
-+
-+/* DoC_Address: Set the current address for the flash chip through the Flash
-+ * Address register. Need 2 Write Pipeline Terminates to complete send.
-+ */
-+static inline void DoC_Address(struct DiskOnChip *doc, int numbytes,
-+ unsigned long ofs, unsigned char xtraflags1,
-+ unsigned char xtraflags2)
-+{
-+ unsigned long docptr = doc->virtadr;
-+
-+ /* Allow for possible Mill Plus internal flash interleaving */
-+ ofs >>= doc->interleave;
-+
-+ switch (numbytes) {
-+ case 1:
-+ /* Send single byte, bits 0-7. */
-+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ case 2:
-+ /* Send bits 9-16 followed by 17-23 */
-+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ case 3:
-+ /* Send 0-7, 9-16, then 17-23 */
-+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress);
-+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+}
-+
-+/* DoC_SelectChip: Select a given flash chip within the current floor */
-+static int DoC_SelectChip(unsigned long docptr, int chip)
-+{
-+ /* No choice for flash chip on Millennium Plus */
-+ return 0;
-+}
-+
-+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
-+static int DoC_SelectFloor(unsigned long docptr, int floor)
-+{
-+ WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect);
-+ return 0;
-+}
-+
-+/*
-+ * Translate the given offset into the appropriate command and offset.
-+ * This does the mapping using the 16bit interleave layout defined by
-+ * M-Systems, and looks like this for a sector pair:
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055|
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 |
-+ * +-----------+-------+-------+-------+--------------+---------+-----------+
-+ */
-+/* FIXME: This lives in INFTL not here. Other users of flash devices
-+ may not want it */
-+static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+
-+ if (this->interleave) {
-+ unsigned int ofs = *from & 0x3ff;
-+ unsigned int cmd;
-+
-+ if (ofs < 512) {
-+ cmd = NAND_CMD_READ0;
-+ ofs &= 0x1ff;
-+ } else if (ofs < 1014) {
-+ cmd = NAND_CMD_READ1;
-+ ofs = (ofs & 0x1ff) + 10;
-+ } else {
-+ cmd = NAND_CMD_READOOB;
-+ ofs = ofs - 1014;
-+ }
-+
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+ } else {
-+ /* No interleave */
-+ if ((*from) & 0x100)
-+ return NAND_CMD_READ1;
-+ return NAND_CMD_READ0;
-+ }
-+}
-+
-+static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ if (*from & 0x200) {
-+ cmd = NAND_CMD_READOOB;
-+ ofs = 10 + (*from & 0xf);
-+ } else {
-+ cmd = NAND_CMD_READ1;
-+ ofs = (*from & 0xf);
-+ }
-+
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ cmd = NAND_CMD_READ1;
-+ ofs = (*from & 0x200) ? 8 : 6;
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from)
-+{
-+ unsigned int ofs, cmd;
-+
-+ cmd = NAND_CMD_READOOB;
-+ ofs = (*from & 0x200) ? 24 : 16;
-+ *from = (*from & ~0x3ff) | ofs;
-+ return cmd;
-+}
-+
-+static inline void MemReadDOC(unsigned long docptr, unsigned char *buf, int len)
-+{
-+#ifndef USE_MEMCPY
-+ int i;
-+ for (i = 0; i < len; i++)
-+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
-+#else
-+ memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len);
-+#endif
-+}
-+
-+static inline void MemWriteDOC(unsigned long docptr, unsigned char *buf, int len)
-+{
-+#ifndef USE_MEMCPY
-+ int i;
-+ for (i = 0; i < len; i++)
-+ WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
-+#else
-+ memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
-+#endif
-+}
-+
-+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
-+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
-+{
-+ int mfr, id, i, j;
-+ volatile char dummy;
-+ unsigned long docptr = doc->virtadr;
-+
-+ /* Page in the required floor/chip */
-+ DoC_SelectFloor(docptr, floor);
-+ DoC_SelectChip(docptr, chip);
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the NAND chip ID: 1. Send ReadID command */
-+ DoC_Command(docptr, NAND_CMD_READID, 0);
-+
-+ /* Read the NAND chip ID: 2. Send address byte zero */
-+ DoC_Address(doc, 1, 0x00, 0, 0x00);
-+
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the manufacturer and device id codes of the flash device through
-+ CDSN IO register see Software Requirement 11.4 item 5.*/
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ mfr = ReadDOC(docptr, Mil_CDSN_IO);
-+ if (doc->interleave)
-+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
-+
-+ id = ReadDOC(docptr, Mil_CDSN_IO);
-+ if (doc->interleave)
-+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
-+
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ /* No response - return failure */
-+ if (mfr == 0xff || mfr == 0)
-+ return 0;
-+
-+ for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-+ if (id == nand_flash_ids[i].id) {
-+ /* Try to identify manufacturer */
-+ for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-+ if (nand_manuf_ids[j].id == mfr)
-+ break;
-+ }
-+ printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-+ "Chip ID: %2.2X (%s:%s)\n", mfr, id,
-+ nand_manuf_ids[j].name, nand_flash_ids[i].name);
-+ doc->mfr = mfr;
-+ doc->id = id;
-+ doc->chipshift = nand_flash_ids[i].chipshift;
-+ doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
-+ break;
-+ }
-+ }
-+
-+ if (nand_flash_ids[i].name == NULL)
-+ return 0;
-+ return 1;
-+}
-+
-+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
-+static void DoC_ScanChips(struct DiskOnChip *this)
-+{
-+ int floor, chip;
-+ int numchips[MAX_FLOORS_MPLUS];
-+ int ret;
-+
-+ this->numchips = 0;
-+ this->mfr = 0;
-+ this->id = 0;
-+
-+ /* Work out the intended interleave setting */
-+ this->interleave = 0;
-+ if (this->ChipID == DOC_ChipID_DocMilPlus32)
-+ this->interleave = 1;
-+
-+ /* Check the ASIC agrees */
-+ if ( (this->interleave << 2) !=
-+ (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
-+ u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
-+ printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
-+ this->interleave?"on (16-bit)":"off (8-bit)");
-+ conf ^= 4;
-+ WriteDOC(this->virtadr, conf, Mplus_Configuration);
-+ }
-+
-+ /* For each floor, find the number of valid chips it contains */
-+ for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
-+ numchips[floor] = 0;
-+ for (chip = 0; chip < MAX_CHIPS_MPLUS && 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("MTD: No memory for allocating chip info structures\n");
-+ return;
-+ }
-+
-+ /* Fill out the chip array with {floor, chipno} for each
-+ * detected chip in the device. */
-+ for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
-+ for (chip = 0 ; chip < numchips[floor] ; chip++) {
-+ 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 MiB\n",
-+ this->numchips ,this->totlen >> 20);
-+}
-+
-+static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
-+{
-+ int tmp1, tmp2, retval;
-+
-+ if (doc1->physadr == doc2->physadr)
-+ return 1;
-+
-+ /* Use the alias resolution register which was set aside for this
-+ * purpose. If it's value is the same on both chips, they might
-+ * be the same chip, and we write to one and check for a change in
-+ * the other. It's unclear if this register is usuable in the
-+ * DoC 2000 (it's in the Millennium docs), but it seems to work. */
-+ tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution);
-+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
-+ if (tmp1 != tmp2)
-+ return 0;
-+
-+ WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
-+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
-+ if (tmp2 == (tmp1+1) % 0xff)
-+ retval = 1;
-+ else
-+ retval = 0;
-+
-+ /* Restore register contents. May not be necessary, but do it just to
-+ * be safe. */
-+ WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution);
-+
-+ return retval;
-+}
-+
-+static const char im_name[] = "DoCMilPlus_init";
-+
-+/* This routine is made available to other mtd code via
-+ * inter_module_register. It must only be accessed through
-+ * inter_module_get which will bump the use count of this module. The
-+ * addresses passed back in mtd are valid as long as the use count of
-+ * this module is non-zero, i.e. between inter_module_get and
-+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
-+ */
-+static void DoCMilPlus_init(struct mtd_info *mtd)
-+{
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ struct DiskOnChip *old = NULL;
-+
-+ /* We must avoid being called twice for the same device. */
-+ if (docmilpluslist)
-+ old = (struct DiskOnChip *)docmilpluslist->priv;
-+
-+ while (old) {
-+ if (DoCMilPlus_is_alias(this, old)) {
-+ printk(KERN_NOTICE "Ignoring DiskOnChip Millennium "
-+ "Plus at 0x%lX - already configured\n",
-+ this->physadr);
-+ iounmap((void *)this->virtadr);
-+ kfree(mtd);
-+ return;
-+ }
-+ if (old->nextdoc)
-+ old = (struct DiskOnChip *)old->nextdoc->priv;
-+ else
-+ old = NULL;
-+ }
-+
-+ mtd->name = "DiskOnChip Millennium Plus";
-+ printk(KERN_NOTICE "DiskOnChip Millennium Plus found at "
-+ "address 0x%lX\n", this->physadr);
-+
-+ mtd->type = MTD_NANDFLASH;
-+ mtd->flags = MTD_CAP_NANDFLASH;
-+ mtd->ecctype = MTD_ECC_RS_DiskOnChip;
-+ mtd->size = 0;
-+
-+ mtd->erasesize = 0;
-+ mtd->oobblock = 512;
-+ mtd->oobsize = 16;
-+ mtd->owner = THIS_MODULE;
-+ mtd->erase = doc_erase;
-+ 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 = doc_write_oob;
-+ mtd->sync = NULL;
-+
-+ 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);
-+ iounmap((void *)this->virtadr);
-+ } else {
-+ this->nextdoc = docmilpluslist;
-+ docmilpluslist = mtd;
-+ mtd->size = this->totlen;
-+ mtd->erasesize = this->erasesize;
-+ add_mtd_device(mtd);
-+ return;
-+ }
-+}
-+
-+#if 0
-+static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
-+{
-+ int i;
-+ loff_t fofs;
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[from >> (this->chipshift)];
-+ unsigned char *bp, buf[1056];
-+ char c[32];
-+
-+ from &= ~0x3ff;
-+
-+ /* Don't allow read past end of device */
-+ if (from >= this->totlen)
-+ return -EINVAL;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ fofs = from;
-+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, 1054);
-+ buf[1054] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[1055] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ memset(&c[0], 0, sizeof(c));
-+ printk("DUMP OFFSET=%x:\n", (int)from);
-+
-+ for (i = 0, bp = &buf[0]; (i < 1056); i++) {
-+ if ((i % 16) == 0)
-+ printk("%08x: ", i);
-+ printk(" %02x", *bp);
-+ c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.';
-+ bp++;
-+ if (((i + 1) % 16) == 0)
-+ printk(" %s\n", c);
-+ }
-+ printk("\n");
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ return 0;
-+}
-+#endif
-+
-+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ /* Just a special case of doc_read_ecc */
-+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-+}
-+
-+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel)
-+{
-+ int ret, i;
-+ volatile char dummy;
-+ loff_t fofs;
-+ unsigned char syndrome[6];
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[from >> (this->chipshift)];
-+
-+ /* 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;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ fofs = from;
-+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ if (eccbuf) {
-+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-+ } else {
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ }
-+
-+ /* Let the caller know we completed it */
-+ *retlen = len;
-+ ret = 0;
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+ if (eccbuf) {
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, len);
-+
-+ /* Read the ECC data following raw data */
-+ MemReadDOC(docptr, eccbuf, 4);
-+ eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
-+ eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Flush the pipeline */
-+ dummy = ReadDOC(docptr, Mplus_ECCConf);
-+ dummy = ReadDOC(docptr, Mplus_ECCConf);
-+
-+ /* Check the ECC Status */
-+ if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
-+ int nb_errors;
-+ /* There was an ECC error */
-+#ifdef ECC_DEBUG
-+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
-+#endif
-+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
-+ These syndrome will be all ZERO when there is no error */
-+ for (i = 0; i < 6; i++)
-+ syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
-+
-+ nb_errors = doc_decode_ecc(buf, syndrome);
-+#ifdef ECC_DEBUG
-+ printk("ECC Errors corrected: %x\n", nb_errors);
-+#endif
-+ if (nb_errors < 0) {
-+ /* We return error, but have actually done the read. Not that
-+ this can be told to user-space, via sys_read(), but at least
-+ MTD-aware stuff can know about it by checking *retlen */
-+#ifdef ECC_DEBUG
-+ printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
-+ __FILE__, __LINE__, (int)from);
-+ printk(" syndrome= %02x:%02x:%02x:%02x:%02x:"
-+ "%02x\n",
-+ syndrome[0], syndrome[1], syndrome[2],
-+ syndrome[3], syndrome[4], syndrome[5]);
-+ printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:"
-+ "%02x\n",
-+ eccbuf[0], eccbuf[1], eccbuf[2],
-+ eccbuf[3], eccbuf[4], eccbuf[5]);
-+#endif
-+ ret = -EIO;
-+ }
-+ }
-+
-+#ifdef PSYCHO_DEBUG
-+ printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-+ eccbuf[4], eccbuf[5]);
-+#endif
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
-+ } else {
-+ /* Read the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Read Operations 11.3 */
-+ MemReadDOC(docptr, buf, len-2);
-+ buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ return ret;
-+}
-+
-+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ char eccbuf[6];
-+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-+}
-+
-+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf, u_char *eccbuf,
-+ struct nand_oobinfo *oobsel)
-+{
-+ int i, before, ret = 0;
-+ loff_t fto;
-+ volatile char dummy;
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[to >> (this->chipshift)];
-+
-+ /* Don't allow write past end of device */
-+ if (to >= this->totlen)
-+ return -EINVAL;
-+
-+ /* Don't allow writes which aren't exactly one block (512 bytes) */
-+ if ((to & 0x1ff) || (len != 0x200))
-+ return -EINVAL;
-+
-+ /* Determine position of OOB flags, before or after data */
-+ before = (this->interleave && (to & 0x200));
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Set device to appropriate plane of flash */
-+ fto = to;
-+ WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd);
-+
-+ /* On interleaved devices the flags for 2nd half 512 are before data */
-+ if (eccbuf && before)
-+ fto -= 2;
-+
-+ /* issue the Serial Data In command to initial the Page Program process */
-+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-+ DoC_Address(this, 3, fto, 0x00, 0x00);
-+
-+ /* Disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ if (eccbuf) {
-+ if (before) {
-+ /* Write the block status BLOCK_USED (0x5555) */
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
-+ }
-+
-+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
-+ }
-+
-+ MemWriteDOC(docptr, (unsigned char *) buf, len);
-+
-+ if (eccbuf) {
-+ /* Write ECC data to flash, the ECC info is generated by
-+ the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
-+ DoC_Delay(docptr, 3);
-+
-+ /* Read the ECC data through the DiskOnChip ECC logic */
-+ for (i = 0; i < 6; i++)
-+ eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-+
-+ /* Write the ECC data to flash */
-+ MemWriteDOC(docptr, eccbuf, 6);
-+
-+ if (!before) {
-+ /* Write the block status BLOCK_USED (0x5555) */
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
-+ WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
-+ }
-+
-+#ifdef PSYCHO_DEBUG
-+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-+ eccbuf[4], eccbuf[5]);
-+#endif
-+ }
-+
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+
-+ /* Commit the Page Program command and wait for ready
-+ see Software Requirement 11.4 item 1.*/
-+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5.*/
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ DoC_Delay(docptr, 2);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
-+ /* Error in programming
-+ FIXME: implement Bad Block Replacement (in nftl.c ??) */
-+ *retlen = 0;
-+ ret = -EIO;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ /* Let the caller know we completed it */
-+ *retlen = len;
-+
-+ return ret;
-+}
-+
-+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ loff_t fofs, base;
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+ size_t i, size, got, want;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
-+
-+ /* disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+ DoC_WaitReady(docptr);
-+
-+ /* Maximum of 16 bytes in the OOB region, so limit read to that */
-+ if (len > 16)
-+ len = 16;
-+ got = 0;
-+ want = len;
-+
-+ for (i = 0; ((i < 3) && (want > 0)); i++) {
-+ /* Figure out which region we are accessing... */
-+ fofs = ofs;
-+ base = ofs & 0xf;
-+ if (!this->interleave) {
-+ DoC_Command(docptr, NAND_CMD_READOOB, 0);
-+ size = 16 - base;
-+ } else if (base < 6) {
-+ DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
-+ size = 6 - base;
-+ } else if (base < 8) {
-+ DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0);
-+ size = 8 - base;
-+ } else {
-+ DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0);
-+ size = 16 - base;
-+ }
-+ if (size > want)
-+ size = want;
-+
-+ /* Issue read command */
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+ WriteDOC(0, docptr, Mplus_FlashControl);
-+ DoC_WaitReady(docptr);
-+
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ ReadDOC(docptr, Mplus_ReadPipeInit);
-+ MemReadDOC(docptr, &buf[got], size - 2);
-+ buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead);
-+ buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ ofs += size;
-+ got += size;
-+ want -= size;
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ volatile char dummy;
-+ loff_t fofs, base;
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+ size_t i, size, got, want;
-+ int ret = 0;
-+
-+ DoC_CheckASIC(docptr);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+
-+ /* Maximum of 16 bytes in the OOB region, so limit write to that */
-+ if (len > 16)
-+ len = 16;
-+ got = 0;
-+ want = len;
-+
-+ for (i = 0; ((i < 3) && (want > 0)); i++) {
-+ /* Reset the chip, see Software Requirement 11.4 item 1. */
-+ DoC_Command(docptr, NAND_CMD_RESET, 0);
-+ DoC_WaitReady(docptr);
-+
-+ /* Figure out which region we are accessing... */
-+ fofs = ofs;
-+ base = ofs & 0x0f;
-+ if (!this->interleave) {
-+ WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
-+ size = 16 - base;
-+ } else if (base < 6) {
-+ WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 6 - base;
-+ } else if (base < 8) {
-+ WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 8 - base;
-+ } else {
-+ WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
-+ size = 16 - base;
-+ }
-+ if (size > want)
-+ size = want;
-+
-+ /* Issue the Serial Data In command to initial the Page Program process */
-+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
-+ DoC_Address(this, 3, fofs, 0, 0x00);
-+
-+ /* Disable the ECC engine */
-+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+
-+ /* Write the data via the internal pipeline through CDSN IO
-+ register, see Pipelined Write Operations 11.2 */
-+ MemWriteDOC(docptr, (unsigned char *) &buf[got], size);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+
-+ /* Commit the Page Program command and wait for ready
-+ see Software Requirement 11.4 item 1.*/
-+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5.*/
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ DoC_Delay(docptr, 2);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x programming oob at 0x%x\n",
-+ dummy, (int)ofs);
-+ /* FIXME: implement Bad Block Replacement */
-+ *retlen = 0;
-+ ret = -EIO;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ ofs += size;
-+ got += size;
-+ want -= size;
-+ }
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ *retlen = len;
-+ return ret;
-+}
-+
-+int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ volatile char dummy;
-+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
-+ __u32 ofs = instr->addr;
-+ __u32 len = instr->len;
-+ unsigned long docptr = this->virtadr;
-+ struct Nand *mychip = &this->chips[ofs >> this->chipshift];
-+
-+ DoC_CheckASIC(docptr);
-+
-+ if (len != mtd->erasesize)
-+ printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
-+ len, mtd->erasesize);
-+
-+ /* Find the chip which is to be used and select it */
-+ 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;
-+
-+ instr->state = MTD_ERASE_PENDING;
-+
-+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
-+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
-+
-+ DoC_Command(docptr, NAND_CMD_RESET, 0x00);
-+ DoC_WaitReady(docptr);
-+
-+ DoC_Command(docptr, NAND_CMD_ERASE1, 0);
-+ DoC_Address(this, 2, ofs, 0, 0x00);
-+ DoC_Command(docptr, NAND_CMD_ERASE2, 0);
-+ DoC_WaitReady(docptr);
-+ instr->state = MTD_ERASING;
-+
-+ /* Read the status of the flash device through CDSN IO register
-+ see Software Requirement 11.4 item 5. */
-+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
-+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
-+ printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs);
-+ /* FIXME: implement Bad Block Replacement (in nftl.c ??) */
-+ instr->state = MTD_ERASE_FAILED;
-+ } else {
-+ instr->state = MTD_ERASE_DONE;
-+ }
-+ dummy = ReadDOC(docptr, Mplus_LastDataRead);
-+
-+ /* Disable flash internally */
-+ WriteDOC(0, docptr, Mplus_FlashSelect);
-+
-+ if (instr->callback)
-+ instr->callback(instr);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+ *
-+ * Module stuff
-+ *
-+ ****************************************************************************/
-+
-+int __init init_doc2001plus(void)
-+{
-+ inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
-+ return 0;
-+}
-+
-+static void __exit cleanup_doc2001plus(void)
-+{
-+ struct mtd_info *mtd;
-+ struct DiskOnChip *this;
-+
-+ while ((mtd=docmilpluslist)) {
-+ this = (struct DiskOnChip *)mtd->priv;
-+ docmilpluslist = this->nextdoc;
-+
-+ del_mtd_device(mtd);
-+
-+ iounmap((void *)this->virtadr);
-+ kfree(this->chips);
-+ kfree(mtd);
-+ }
-+ inter_module_unregister(im_name);
-+}
-+
-+module_exit(cleanup_doc2001plus);
-+module_init(init_doc2001plus);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
-+MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/docecc.c linux/drivers/mtd/devices/docecc.c
---- linux-mips-2.4.27/drivers/mtd/devices/docecc.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/devices/docecc.c 2004-11-19 10:25:11.851207088 +0100
-@@ -7,7 +7,7 @@
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
- * Copyright (C) 2000 Netgem S.A.
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -519,6 +519,8 @@
- return nb_errors;
- }
-
-+EXPORT_SYMBOL_GPL(doc_decode_ecc);
-+
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
- MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/docprobe.c linux/drivers/mtd/devices/docprobe.c
---- linux-mips-2.4.27/drivers/mtd/devices/docprobe.c 2003-06-16 01:42:21.000000000 +0200
-+++ linux/drivers/mtd/devices/docprobe.c 2004-11-19 10:25:11.853206784 +0100
-@@ -4,7 +4,7 @@
- /* (C) 1999 Machine Vision Holdings, Inc. */
- /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */
-
--/* $Id$ */
-+/* $Id$ */
-
-
-
-@@ -31,14 +31,12 @@
- /* DOC_SINGLE_DRIVER:
- Millennium driver has been merged into DOC2000 driver.
-
-- The newly-merged driver doesn't appear to work for writing. It's the
-- same with the DiskOnChip 2000 and the Millennium. If you have a
-- Millennium and you want write support to work, remove the definition
-- of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver.
--
-- Otherwise, it's left on in the hope that it'll annoy someone with
-- a Millennium enough that they go through and work out what the
-- difference is :)
-+ The old Millennium-only driver has been retained just in case there
-+ are problems with the new code. If the combined driver doesn't work
-+ for you, you can try the old one by undefining DOC_SINGLE_DRIVER
-+ below and also enabling it in your configuration. If this fixes the
-+ problems, please send a report to the MTD mailing list at
-+ <linux-mtd@lists.infradead.org>.
- */
- #define DOC_SINGLE_DRIVER
-
-@@ -47,18 +45,15 @@
- #include <linux/module.h>
- #include <asm/errno.h>
- #include <asm/io.h>
--#include <asm/uaccess.h>
--#include <linux/miscdevice.h>
--#include <linux/pci.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
--#include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/types.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/doc2000.h>
-+#include <linux/mtd/compatmac.h>
-
- /* Where to look for the devices? */
- #ifndef CONFIG_MTD_DOCPROBE_ADDRESS
-@@ -92,17 +87,17 @@
- 0xff000000,
- #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
- 0xff000000,
--#else
-+##else
- #warning Unknown architecture for DiskOnChip. No default probe locations defined
- #endif
-- 0 };
-+ 0xffffffff };
-
- /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
-
- static inline int __init doccheck(unsigned long potential, unsigned long physadr)
- {
- unsigned long window=potential;
-- unsigned char tmp, ChipID;
-+ unsigned char tmp, tmpb, tmpc, ChipID;
- #ifndef DOC_PASSIVE_PROBE
- unsigned char tmp2;
- #endif
-@@ -140,26 +135,80 @@
- window, DOCControl);
- #endif /* !DOC_PASSIVE_PROBE */
-
-+ /* We need to read the ChipID register four times. For some
-+ newer DiskOnChip 2000 units, the first three reads will
-+ return the DiskOnChip Millennium ident. Don't ask. */
- ChipID = ReadDOC(window, ChipID);
-
- switch (ChipID) {
- case DOC_ChipID_Doc2k:
- /* 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)
-+ tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
- return ChipID;
- break;
-
- case DOC_ChipID_DocMil:
-+ /* Check for the new 2000 with Millennium ASIC */
-+ ReadDOC(window, ChipID);
-+ ReadDOC(window, ChipID);
-+ if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
-+ ChipID = DOC_ChipID_Doc2kTSOP;
-+
- /* Check the TOGGLE bit in the ECC register */
- tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-- if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
-+ tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
-+ return ChipID;
-+ break;
-+
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ case 0:
-+ /* Possible Millennium+, need to do more checks */
-+#ifndef DOC_PASSIVE_PROBE
-+ /* Possibly release from power down mode */
-+ for (tmp = 0; (tmp < 4); tmp++)
-+ ReadDOC(window, Mplus_Power);
-+
-+ /* Reset the DiskOnChip ASIC */
-+ tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+ DOC_MODE_BDECT;
-+ WriteDOC(tmp, window, Mplus_DOCControl);
-+ WriteDOC(~tmp, window, Mplus_CtrlConfirm);
-+
-+ mdelay(1);
-+ /* Enable the DiskOnChip ASIC */
-+ tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+ DOC_MODE_BDECT;
-+ WriteDOC(tmp, window, Mplus_DOCControl);
-+ WriteDOC(~tmp, window, Mplus_CtrlConfirm);
-+ mdelay(1);
-+#endif /* !DOC_PASSIVE_PROBE */
-+
-+ ChipID = ReadDOC(window, ChipID);
-+
-+ switch (ChipID) {
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ /* Check the TOGGLE bit in the toggle register */
-+ tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
-+ if (tmp != tmpb && tmp == tmpc)
- return ChipID;
-+ default:
- break;
-+ }
-+ /* FALL TRHU */
-
- default:
--#ifndef CONFIG_MTD_DOCPROBE_55AA
-- printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
-+
-+#ifdef CONFIG_MTD_DOCPROBE_55AA
-+ printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
- ChipID, physadr);
- #endif
- #ifndef DOC_PASSIVE_PROBE
-@@ -200,6 +249,12 @@
- return;
-
- if ((ChipID = doccheck(docptr, physadr))) {
-+ if (ChipID == DOC_ChipID_Doc2kTSOP) {
-+ /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
-+ printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
-+ iounmap((void *)docptr);
-+ return;
-+ }
- docfound = 1;
- mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
-
-@@ -221,6 +276,12 @@
- sprintf(namebuf, "with ChipID %2.2X", ChipID);
-
- switch(ChipID) {
-+ case DOC_ChipID_Doc2kTSOP:
-+ name="2000 TSOP";
-+ im_funcname = "DoC2k_init";
-+ im_modname = "doc2000";
-+ break;
-+
- case DOC_ChipID_Doc2k:
- name="2000";
- im_funcname = "DoC2k_init";
-@@ -237,6 +298,13 @@
- im_modname = "doc2001";
- #endif /* DOC_SINGLE_DRIVER */
- break;
-+
-+ case DOC_ChipID_DocMilPlus16:
-+ case DOC_ChipID_DocMilPlus32:
-+ name="MillenniumPlus";
-+ im_funcname = "DoCMilPlus_init";
-+ im_modname = "doc2001plus";
-+ break;
- }
-
- if (im_funcname)
-@@ -248,6 +316,7 @@
- return;
- }
- printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
-+ kfree(mtd);
- }
- iounmap((void *)docptr);
- }
-@@ -267,7 +336,7 @@
- printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
- DoC_Probe(doc_config_location);
- } else {
-- for (i=0; doc_locations[i]; i++) {
-+ for (i=0; (doc_locations[i] != 0xffffffff); i++) {
- DoC_Probe(doc_locations[i]);
- }
- }
-@@ -275,11 +344,7 @@
- found, so the user knows we at least tried. */
- if (!docfound)
- printk(KERN_INFO "No recognised DiskOnChip devices found\n");
-- /* So it looks like we've been used and we get unloaded */
-- MOD_INC_USE_COUNT;
-- MOD_DEC_USE_COUNT;
-- return 0;
--
-+ return -EAGAIN;
- }
-
- module_init(init_doc);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/lart.c linux/drivers/mtd/devices/lart.c
---- linux-mips-2.4.27/drivers/mtd/devices/lart.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/devices/lart.c 2004-11-19 10:25:11.854206632 +0100
-@@ -2,7 +2,7 @@
- /*
- * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
- *
-- * $Id$
-+ * $Id$
- *
- * Author: Abraham vd Merwe <abraham@2d3d.co.za>
- *
-@@ -584,45 +584,40 @@
-
- static struct mtd_info mtd;
-
--static struct mtd_erase_region_info erase_regions[] =
--{
-+static struct mtd_erase_region_info erase_regions[] = {
- /* parameter blocks */
- {
-- offset: 0x00000000,
-- erasesize: FLASH_BLOCKSIZE_PARAM,
-- numblocks: FLASH_NUMBLOCKS_16m_PARAM
-+ .offset = 0x00000000,
-+ .erasesize = FLASH_BLOCKSIZE_PARAM,
-+ .numblocks = FLASH_NUMBLOCKS_16m_PARAM,
- },
- /* main blocks */
- {
-- offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
-- erasesize: FLASH_BLOCKSIZE_MAIN,
-- numblocks: FLASH_NUMBLOCKS_16m_MAIN
-+ .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
-+ .erasesize = FLASH_BLOCKSIZE_MAIN,
-+ .numblocks = FLASH_NUMBLOCKS_16m_MAIN,
- }
- };
-
- #ifdef HAVE_PARTITIONS
--static struct mtd_partition lart_partitions[] =
--{
-+static struct mtd_partition lart_partitions[] = {
- /* blob */
- {
-- name: "blob",
-- offset: BLOB_START,
-- size: BLOB_LEN,
-- mask_flags: 0
-+ .name = "blob",
-+ .offset = BLOB_START,
-+ .size = BLOB_LEN,
- },
- /* kernel */
- {
-- name: "kernel",
-- offset: KERNEL_START, /* MTDPART_OFS_APPEND */
-- size: KERNEL_LEN,
-- mask_flags: 0
-+ .name = "kernel",
-+ .offset = KERNEL_START, /* MTDPART_OFS_APPEND */
-+ .size = KERNEL_LEN,
- },
- /* initial ramdisk / file system */
- {
-- name: "file system",
-- offset: INITRD_START, /* MTDPART_OFS_APPEND */
-- size: INITRD_LEN, /* MTDPART_SIZ_FULL */
-- mask_flags: 0
-+ .name = "file system",
-+ .offset = INITRD_START, /* MTDPART_OFS_APPEND */
-+ .size = INITRD_LEN, /* MTDPART_SIZ_FULL */
- }
- };
- #endif
-@@ -646,10 +641,10 @@
- mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
- mtd.numeraseregions = NB_OF (erase_regions);
- mtd.eraseregions = erase_regions;
-- mtd.module = THIS_MODULE;
- mtd.erase = flash_erase;
- mtd.read = flash_read;
- mtd.write = flash_write;
-+ mtd.owner = THIS_MODULE;
-
- #ifdef LART_DEBUG
- printk (KERN_DEBUG
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/ms02-nv.c linux/drivers/mtd/devices/ms02-nv.c
---- linux-mips-2.4.27/drivers/mtd/devices/ms02-nv.c 2004-07-30 12:22:40.000000000 +0200
-+++ linux/drivers/mtd/devices/ms02-nv.c 2004-11-19 10:25:11.856206328 +0100
-@@ -6,7 +6,7 @@
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/init.h>
-@@ -31,7 +31,7 @@
- static char version[] __initdata =
- "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
-
--MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
-+MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
- MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
- MODULE_LICENSE("GPL");
-
-@@ -222,7 +222,7 @@
- mtd->flags = MTD_CAP_RAM | MTD_XIP;
- mtd->size = fixsize;
- mtd->name = (char *)ms02nv_name;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->read = ms02nv_read;
- mtd->write = ms02nv_write;
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/mtdram.c linux/drivers/mtd/devices/mtdram.c
---- linux-mips-2.4.27/drivers/mtd/devices/mtdram.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/mtdram.c 2004-11-19 10:25:11.859205872 +0100
-@@ -1,6 +1,6 @@
- /*
- * mtdram - a test mtd device
-- * $Id$
-+ * $Id$
- * Author: Alexander Larsson <alex@cendio.se>
- *
- * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
-@@ -13,6 +13,8 @@
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/ioport.h>
-+#include <linux/vmalloc.h>
-+#include <linux/init.h>
- #include <linux/mtd/compatmac.h>
- #include <linux/mtd/mtd.h>
-
-@@ -136,7 +138,7 @@
- mtd->erasesize = MTDRAM_ERASE_SIZE;
- mtd->priv = mapped_address;
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->erase = ram_erase;
- mtd->point = ram_point;
- mtd->unpoint = ram_unpoint;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/phram.c linux/drivers/mtd/devices/phram.c
---- linux-mips-2.4.27/drivers/mtd/devices/phram.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/devices/phram.c 2004-11-19 10:25:11.860205720 +0100
-@@ -0,0 +1,362 @@
-+/**
-+ *
-+ * $Id$
-+ *
-+ * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
-+ * 07/2003 rewritten by Joern Engel <joern@wh.fh-wedel.de>
-+ *
-+ * DISCLAIMER: This driver makes use of Rusty's excellent module code,
-+ * so it will not work for 2.4 without changes and it wont work for 2.4
-+ * as a module without major changes. Oh well!
-+ *
-+ * Usage:
-+ *
-+ * one commend line parameter per device, each in the form:
-+ * phram=<name>,<start>,<len>
-+ * <name> may be up to 63 characters.
-+ * <start> and <len> can be octal, decimal or hexadecimal. If followed
-+ * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
-+ * gigabytes.
-+ *
-+ */
-+
-+#include <asm/io.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/mtd/mtd.h>
-+
-+#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
-+
-+struct phram_mtd_list {
-+ struct list_head list;
-+ struct mtd_info *mtdinfo;
-+};
-+
-+static LIST_HEAD(phram_list);
-+
-+
-+
-+int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ u_char *start = (u_char *)mtd->priv;
-+
-+ if (instr->addr + instr->len > mtd->size)
-+ return -EINVAL;
-+
-+ memset(start + instr->addr, 0xff, instr->len);
-+
-+ /* This'll catch a few races. Free the thing before returning :)
-+ * I don't feel at all ashamed. This kind of thing is possible anyway
-+ * with flash, but unlikely.
-+ */
-+
-+ instr->state = MTD_ERASE_DONE;
-+
-+ if (instr->callback)
-+ (*(instr->callback))(instr);
-+ else
-+ kfree(instr);
-+
-+ return 0;
-+}
-+
-+int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char **mtdbuf)
-+{
-+ u_char *start = (u_char *)mtd->priv;
-+
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-+
-+ *mtdbuf = start + from;
-+ *retlen = len;
-+ return 0;
-+}
-+
-+void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
-+{
-+}
-+
-+int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t *retlen, u_char *buf)
-+{
-+ u_char *start = (u_char *)mtd->priv;
-+
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-+
-+ memcpy(buf, start + from, len);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t *retlen, const u_char *buf)
-+{
-+ u_char *start = (u_char *)mtd->priv;
-+
-+ if (to + len > mtd->size)
-+ return -EINVAL;
-+
-+ memcpy(start + to, buf, len);
-+
-+ *retlen = len;
-+ return 0;
-+}
-+
-+
-+
-+static void unregister_devices(void)
-+{
-+ struct phram_mtd_list *this;
-+
-+ list_for_each_entry(this, &phram_list, list) {
-+ del_mtd_device(this->mtdinfo);
-+ iounmap(this->mtdinfo->priv);
-+ kfree(this->mtdinfo);
-+ kfree(this);
-+ }
-+}
-+
-+static int register_device(char *name, unsigned long start, unsigned long len)
-+{
-+ struct phram_mtd_list *new;
-+ int ret = -ENOMEM;
-+
-+ new = kmalloc(sizeof(*new), GFP_KERNEL);
-+ if (!new)
-+ goto out0;
-+
-+ new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-+ if (!new->mtdinfo)
-+ goto out1;
-+
-+ memset(new->mtdinfo, 0, sizeof(struct mtd_info));
-+
-+ ret = -EIO;
-+ new->mtdinfo->priv = ioremap(start, len);
-+ if (!new->mtdinfo->priv) {
-+ ERROR("ioremap failed\n");
-+ goto out2;
-+ }
-+
-+
-+ new->mtdinfo->name = name;
-+ new->mtdinfo->size = len;
-+ new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
-+ new->mtdinfo->erase = phram_erase;
-+ new->mtdinfo->point = phram_point;
-+ new->mtdinfo->unpoint = phram_unpoint;
-+ new->mtdinfo->read = phram_read;
-+ new->mtdinfo->write = phram_write;
-+ new->mtdinfo->owner = THIS_MODULE;
-+ new->mtdinfo->type = MTD_RAM;
-+ new->mtdinfo->erasesize = 0x0;
-+
-+ ret = -EAGAIN;
-+ if (add_mtd_device(new->mtdinfo)) {
-+ ERROR("Failed to register new device\n");
-+ goto out3;
-+ }
-+
-+ list_add_tail(&new->list, &phram_list);
-+ return 0;
-+
-+out3:
-+ iounmap(new->mtdinfo->priv);
-+out2:
-+ kfree(new->mtdinfo);
-+out1:
-+ kfree(new);
-+out0:
-+ return ret;
-+}
-+
-+static int ustrtoul(const char *cp, char **endp, unsigned int base)
-+{
-+ unsigned long result = simple_strtoul(cp, endp, base);
-+
-+ switch (**endp) {
-+ case 'G':
-+ result *= 1024;
-+ case 'M':
-+ result *= 1024;
-+ case 'k':
-+ result *= 1024;
-+ endp++;
-+ }
-+ return result;
-+}
-+
-+static int parse_num32(uint32_t *num32, const char *token)
-+{
-+ char *endp;
-+ unsigned long n;
-+
-+ n = ustrtoul(token, &endp, 0);
-+ if (*endp)
-+ return -EINVAL;
-+
-+ *num32 = n;
-+ return 0;
-+}
-+
-+static int parse_name(char **pname, const char *token)
-+{
-+ size_t len;
-+ char *name;
-+
-+ len = strlen(token) + 1;
-+ if (len > 64)
-+ return -ENOSPC;
-+
-+ name = kmalloc(len, GFP_KERNEL);
-+ if (!name)
-+ return -ENOMEM;
-+
-+ strcpy(name, token);
-+
-+ *pname = name;
-+ return 0;
-+}
-+
-+#define parse_err(fmt, args...) do { \
-+ ERROR(fmt , ## args); \
-+ return 0; \
-+} while (0)
-+
-+static int phram_setup(const char *val, struct kernel_param *kp)
-+{
-+ char buf[64+12+12], *str = buf;
-+ char *token[3];
-+ char *name;
-+ uint32_t start;
-+ uint32_t len;
-+ int i, ret;
-+
-+ if (strnlen(val, sizeof(str)) >= sizeof(str))
-+ parse_err("parameter too long\n");
-+
-+ strcpy(str, val);
-+
-+ for (i=0; i<3; i++)
-+ token[i] = strsep(&str, ",");
-+
-+ if (str)
-+ parse_err("too many arguments\n");
-+
-+ if (!token[2])
-+ parse_err("not enough arguments\n");
-+
-+ ret = parse_name(&name, token[0]);
-+ if (ret == -ENOMEM)
-+ parse_err("out of memory\n");
-+ if (ret == -ENOSPC)
-+ parse_err("name too long\n");
-+ if (ret)
-+ return 0;
-+
-+ ret = parse_num32(&start, token[1]);
-+ if (ret)
-+ parse_err("illegal start address\n");
-+
-+ ret = parse_num32(&len, token[2]);
-+ if (ret)
-+ parse_err("illegal device length\n");
-+
-+ register_device(name, start, len);
-+
-+ return 0;
-+}
-+
-+module_param_call(phram, phram_setup, NULL, NULL, 000);
-+MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\"");
-+
-+/*
-+ * Just for compatibility with slram, this is horrible and should go someday.
-+ */
-+static int __init slram_setup(const char *val, struct kernel_param *kp)
-+{
-+ char buf[256], *str = buf;
-+
-+ if (!val || !val[0])
-+ parse_err("no arguments to \"slram=\"\n");
-+
-+ if (strnlen(val, sizeof(str)) >= sizeof(str))
-+ parse_err("parameter too long\n");
-+
-+ strcpy(str, val);
-+
-+ while (str) {
-+ char *token[3];
-+ char *name;
-+ uint32_t start;
-+ uint32_t len;
-+ int i, ret;
-+
-+ for (i=0; i<3; i++) {
-+ token[i] = strsep(&str, ",");
-+ if (token[i])
-+ continue;
-+ parse_err("wrong number of arguments to \"slram=\"\n");
-+ }
-+
-+ /* name */
-+ ret = parse_name(&name, token[0]);
-+ if (ret == -ENOMEM)
-+ parse_err("of memory\n");
-+ if (ret == -ENOSPC)
-+ parse_err("too long\n");
-+ if (ret)
-+ return 1;
-+
-+ /* start */
-+ ret = parse_num32(&start, token[1]);
-+ if (ret)
-+ parse_err("illegal start address\n");
-+
-+ /* len */
-+ if (token[2][0] == '+')
-+ ret = parse_num32(&len, token[2] + 1);
-+ else
-+ ret = parse_num32(&len, token[2]);
-+
-+ if (ret)
-+ parse_err("illegal device length\n");
-+
-+ if (token[2][0] != '+') {
-+ if (len < start)
-+ parse_err("end < start\n");
-+ len -= start;
-+ }
-+
-+ register_device(name, start, len);
-+ }
-+ return 1;
-+}
-+
-+module_param_call(slram, slram_setup, NULL, NULL, 000);
-+MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
-+
-+
-+int __init init_phram(void)
-+{
-+ printk(KERN_ERR "phram loaded\n");
-+ return 0;
-+}
-+
-+static void __exit cleanup_phram(void)
-+{
-+ unregister_devices();
-+}
-+
-+module_init(init_phram);
-+module_exit(cleanup_phram);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
-+MODULE_DESCRIPTION("MTD driver for physical RAM");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/pmc551.c linux/drivers/mtd/devices/pmc551.c
---- linux-mips-2.4.27/drivers/mtd/devices/pmc551.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/pmc551.c 2004-11-19 10:25:11.862205416 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * PMC551 PCI Mezzanine Ram Device
- *
-@@ -681,11 +681,6 @@
-
- printk(KERN_INFO PMC551_VERSION);
-
-- if(!pci_present()) {
-- printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
-- return -ENODEV;
-- }
--
- /*
- * PCU-bus chipset probe.
- */
-@@ -787,10 +782,10 @@
- mtd->write = pmc551_write;
- mtd->point = pmc551_point;
- mtd->unpoint = pmc551_unpoint;
-- mtd->module = THIS_MODULE;
- mtd->type = MTD_RAM;
- mtd->name = "PMC551 RAM board";
- mtd->erasesize = 0x10000;
-+ mtd->owner = THIS_MODULE;
-
- if (add_mtd_device(mtd)) {
- printk(KERN_NOTICE "pmc551: Failed to register new device\n");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/slram.c linux/drivers/mtd/devices/slram.c
---- linux-mips-2.4.27/drivers/mtd/devices/slram.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/devices/slram.c 2004-11-19 10:25:11.863205264 +0100
-@@ -1,6 +1,6 @@
- /*======================================================================
-
-- $Id$
-+ $Id$
-
- This driver provides a method to access memory not used by the kernel
- itself (i.e. if the kernel commandline mem=xxx is used). To actually
-@@ -199,7 +199,7 @@
- (*curmtd)->mtdinfo->unpoint = slram_unpoint;
- (*curmtd)->mtdinfo->read = slram_read;
- (*curmtd)->mtdinfo->write = slram_write;
-- (*curmtd)->mtdinfo->module = THIS_MODULE;
-+ (*curmtd)->mtdinfo->owner = THIS_MODULE;
- (*curmtd)->mtdinfo->type = MTD_RAM;
- (*curmtd)->mtdinfo->erasesize = 0x0;
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
---- linux-mips-2.4.27/drivers/mtd/ftl.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/ftl.c 2004-11-19 10:25:11.630240680 +0100
-@@ -1,5 +1,5 @@
- /* This version ported to the Linux-MTD system by dwmw2@infradead.org
-- * $Id$
-+ * $Id$
- *
- * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
-@@ -55,8 +55,8 @@
- contact M-Systems (http://www.m-sys.com) directly.
-
- ======================================================================*/
-+#include <linux/mtd/blktrans.h>
- #include <linux/module.h>
--#include <linux/mtd/compatmac.h>
- #include <linux/mtd/mtd.h>
- /*#define PSYCHO_DEBUG */
-
-@@ -68,43 +68,13 @@
- #include <linux/timer.h>
- #include <linux/major.h>
- #include <linux/fs.h>
--#include <linux/ioctl.h>
-+#include <linux/init.h>
- #include <linux/hdreg.h>
--
--#if (LINUX_VERSION_CODE >= 0x20100)
- #include <linux/vmalloc.h>
--#endif
--#if (LINUX_VERSION_CODE >= 0x20303)
- #include <linux/blkpg.h>
--#endif
-+#include <asm/uaccess.h>
-
- #include <linux/mtd/ftl.h>
--/*====================================================================*/
--/* Stuff which really ought to be in compatmac.h */
--
--#if (LINUX_VERSION_CODE < 0x20328)
--#define register_disk(dev, drive, minors, ops, size) \
-- do { (dev)->part[(drive)*(minors)].nr_sects = size; \
-- if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
-- resetup_one_dev(dev, drive); } while (0)
--#endif
--
--#if (LINUX_VERSION_CODE < 0x20320)
--#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn
--#define blk_init_queue(q, req) q = (req)
--#define blk_cleanup_queue(q) q = NULL
--#define request_arg_t void
--#else
--#define request_arg_t request_queue_t *q
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
-
- /*====================================================================*/
-
-@@ -119,19 +89,6 @@
- #define FTL_MAJOR 44
- #endif
-
--/* Funky stuff for setting up a block device */
--#define MAJOR_NR FTL_MAJOR
--#define DEVICE_NAME "ftl"
--#define DEVICE_REQUEST do_ftl_request
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--
--#define DEVICE_NR(minor) ((minor)>>5)
--#define REGION_NR(minor) (((minor)>>3)&3)
--#define PART_NR(minor) ((minor)&7)
--#define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
--
--#include <linux/blk.h>
-
- /*====================================================================*/
-
-@@ -142,8 +99,7 @@
- #define MAX_REGION 4
-
- /* Maximum number of partitions in an FTL region */
--#define PART_BITS 3
--#define MAX_PART 8
-+#define PART_BITS 4
-
- /* Maximum number of outstanding erase requests per socket */
- #define MAX_ERASE 8
-@@ -154,7 +110,7 @@
-
- /* Each memory region corresponds to a minor device */
- typedef struct partition_t {
-- struct mtd_info *mtd;
-+ struct mtd_blktrans_dev mbd;
- u_int32_t state;
- u_int32_t *VirtualBlockMap;
- u_int32_t *VirtualPageMap;
-@@ -179,21 +135,10 @@
- region_info_t region;
- memory_handle_t handle;
- #endif
-- atomic_t open;
- } partition_t;
-
--partition_t *myparts[MAX_MTD_DEVICES];
--
--static void ftl_notify_add(struct mtd_info *mtd);
--static void ftl_notify_remove(struct mtd_info *mtd);
--
- void ftl_freepart(partition_t *part);
-
--static struct mtd_notifier ftl_notifier = {
-- add: ftl_notify_add,
-- remove: ftl_notify_remove,
--};
--
- /* Partition state flags */
- #define FTL_FORMATTED 0x01
-
-@@ -204,51 +149,11 @@
- #define XFER_PREPARED 0x03
- #define XFER_FAILED 0x04
-
--static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
--static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
--static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
--
--static struct gendisk ftl_gendisk = {
-- major: FTL_MAJOR,
-- major_name: "ftl",
-- minor_shift: PART_BITS,
-- max_p: MAX_PART,
--#if (LINUX_VERSION_CODE < 0x20328)
-- max_nr: MAX_DEV*MAX_PART,
--#endif
-- part: ftl_hd,
-- sizes: ftl_sizes,
--};
--
- /*====================================================================*/
-
--static int ftl_ioctl(struct inode *inode, struct file *file,
-- u_int cmd, u_long arg);
--static int ftl_open(struct inode *inode, struct file *file);
--static release_t ftl_close(struct inode *inode, struct file *file);
--static int ftl_reread_partitions(int minor);
-
- static void ftl_erase_callback(struct erase_info *done);
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations ftl_blk_fops = {
-- open: ftl_open,
-- release: ftl_close,
-- ioctl: ftl_ioctl,
-- read: block_read,
-- write: block_write,
-- fsync: block_fsync
--};
--#else
--static struct block_device_operations ftl_blk_fops = {
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: ftl_open,
-- release: ftl_close,
-- ioctl: ftl_ioctl,
--};
--#endif
-
- /*======================================================================
-
-@@ -264,13 +169,13 @@
- loff_t offset, max_offset;
- int ret;
- part->header.FormattedSize = 0;
-- max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
-+ max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
- /* Search first megabyte for a valid FTL header */
- for (offset = 0;
- (offset + sizeof(header)) < max_offset;
-- offset += part->mtd->erasesize ? : 0x2000) {
-+ offset += part->mbd.mtd->erasesize ? : 0x2000) {
-
-- ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
- (unsigned char *)&header);
-
- if (ret)
-@@ -283,15 +188,15 @@
- printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
- return -ENOENT;
- }
-- if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
-+ if (header.BlockSize != 9 ||
- (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
- (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
- printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
- return -1;
- }
-- if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
-+ if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
- printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
-- 1 << header.EraseUnitSize,part->mtd->erasesize);
-+ 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
- return -1;
- }
- part->header = header;
-@@ -326,7 +231,7 @@
- for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
- offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
- << part->header.EraseUnitSize);
-- ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
- (unsigned char *)&header);
-
- if (ret)
-@@ -391,7 +296,7 @@
- part->EUNInfo[i].Deleted = 0;
- offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
-
-- ret = part->mtd->read(part->mtd, offset,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t), &retval,
- (unsigned char *)part->bam_cache);
-
-@@ -456,7 +361,7 @@
- erase->len = 1 << part->header.EraseUnitSize;
- erase->priv = (u_long)part;
-
-- ret = part->mtd->erase(part->mtd, erase);
-+ ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
-
- if (!ret)
- xfer->EraseCount++;
-@@ -523,7 +428,7 @@
- header.LogicalEUN = cpu_to_le16(0xffff);
- header.EraseCount = cpu_to_le32(xfer->EraseCount);
-
-- ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
- &retlen, (u_char *)&header);
-
- if (ret) {
-@@ -539,7 +444,7 @@
-
- for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
-
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&ctl);
-
- if (ret)
-@@ -586,7 +491,7 @@
-
- offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
-
-- ret = part->mtd->read(part->mtd, offset,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t),
- &retlen, (u_char *) (part->bam_cache));
-
-@@ -604,7 +509,7 @@
- offset = xfer->Offset + 20; /* Bad! */
- unit = cpu_to_le16(0x7fff);
-
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
- &retlen, (u_char *) &unit);
-
- if (ret) {
-@@ -624,7 +529,7 @@
- break;
- case BLOCK_DATA:
- case BLOCK_REPLACEMENT:
-- ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
- &retlen, (u_char *) buf);
- if (ret) {
- printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
-@@ -632,7 +537,7 @@
- }
-
-
-- ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
-+ ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
- &retlen, (u_char *) buf);
- if (ret) {
- printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
-@@ -651,7 +556,7 @@
- }
-
- /* Write the BAM to the transfer unit */
-- ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
- part->BlocksPerUnit * sizeof(int32_t), &retlen,
- (u_char *)part->bam_cache);
- if (ret) {
-@@ -661,7 +566,7 @@
-
-
- /* All clear? Then update the LogicalEUN again */
-- ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
- &retlen, (u_char *)&srcunitswap);
-
- if (ret) {
-@@ -749,8 +654,8 @@
- if (queued) {
- DEBUG(1, "ftl_cs: waiting for transfer "
- "unit to be prepared...\n");
-- if (part->mtd->sync)
-- part->mtd->sync(part->mtd);
-+ if (part->mbd.mtd->sync)
-+ part->mbd.mtd->sync(part->mbd.mtd);
- } else {
- static int ne = 0;
- if (++ne < 5)
-@@ -848,7 +753,7 @@
- /* Invalidate cache */
- part->bam_index = 0xffff;
-
-- ret = part->mtd->read(part->mtd,
-+ ret = part->mbd.mtd->read(part->mbd.mtd,
- part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
- part->BlocksPerUnit * sizeof(u_int32_t),
- &retlen, (u_char *) (part->bam_cache));
-@@ -877,78 +782,6 @@
-
- } /* find_free */
-
--/*======================================================================
--
-- This gets a memory handle for the region corresponding to the
-- minor device number.
--
--======================================================================*/
--
--static int ftl_open(struct inode *inode, struct file *file)
--{
-- int minor = MINOR(inode->i_rdev);
-- partition_t *partition;
--
-- if (minor>>4 >= MAX_MTD_DEVICES)
-- return -ENODEV;
--
-- partition = myparts[minor>>4];
--
-- if (!partition)
-- return -ENODEV;
--
-- if (partition->state != FTL_FORMATTED)
-- return -ENXIO;
--
-- if (ftl_gendisk.part[minor].nr_sects == 0)
-- return -ENXIO;
--
-- BLK_INC_USE_COUNT;
--
-- if (!get_mtd_device(partition->mtd, -1)) {
-- BLK_DEC_USE_COUNT;
-- return -ENXIO;
-- }
--
-- if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
-- put_mtd_device(partition->mtd);
-- BLK_DEC_USE_COUNT;
-- return -EROFS;
-- }
--
-- DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
--
-- atomic_inc(&partition->open);
--
-- return 0;
--}
--
--/*====================================================================*/
--
--static release_t ftl_close(struct inode *inode, struct file *file)
--{
-- int minor = MINOR(inode->i_rdev);
-- partition_t *part = myparts[minor >> 4];
-- int i;
--
-- DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
--
-- /* Wait for any pending erase operations to complete */
-- if (part->mtd->sync)
-- part->mtd->sync(part->mtd);
--
-- for (i = 0; i < part->header.NumTransferUnits; i++) {
-- if (part->XferInfo[i].state == XFER_ERASED)
-- prepare_xfer(part, i);
-- }
--
-- atomic_dec(&part->open);
--
-- put_mtd_device(part->mtd);
-- BLK_DEC_USE_COUNT;
-- release_return(0);
--} /* ftl_close */
--
-
- /*======================================================================
-
-@@ -983,7 +816,7 @@
- else {
- offset = (part->EUNInfo[log_addr / bsize].Offset
- + (log_addr % bsize));
-- ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
- &retlen, (u_char *) buffer);
-
- if (ret) {
-@@ -1022,7 +855,7 @@
- le32_to_cpu(part->header.BAMOffset));
-
- #ifdef PSYCHO_DEBUG
-- ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&old_addr);
- if (ret) {
- printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
-@@ -1059,7 +892,7 @@
- #endif
- part->bam_cache[blk] = le_virt_addr;
- }
-- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
- &retlen, (u_char *)&le_virt_addr);
-
- if (ret) {
-@@ -1119,7 +952,7 @@
- part->EUNInfo[part->bam_index].Deleted++;
- offset = (part->EUNInfo[part->bam_index].Offset +
- blk * SECTOR_SIZE);
-- ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen,
-+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
- buffer);
-
- if (ret) {
-@@ -1151,164 +984,32 @@
- return 0;
- } /* ftl_write */
-
--/*======================================================================
--
-- IOCTL calls for getting device parameters.
--
--======================================================================*/
--
--static int ftl_ioctl(struct inode *inode, struct file *file,
-- u_int cmd, u_long arg)
-+static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
- {
-- struct hd_geometry *geo = (struct hd_geometry *)arg;
-- int ret = 0, minor = MINOR(inode->i_rdev);
-- partition_t *part= myparts[minor >> 4];
-+ partition_t *part = (void *)dev;
- u_long sect;
-
-- if (!part)
-- return -ENODEV; /* How? */
--
-- switch (cmd) {
-- case HDIO_GETGEO:
-- ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
-- if (ret) return ret;
-- /* Sort of arbitrary: round size down to 4K boundary */
-+ /* Sort of arbitrary: round size down to 4KiB boundary */
- sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
-- put_user(1, (char *)&geo->heads);
-- put_user(8, (char *)&geo->sectors);
-- put_user((sect>>3), (short *)&geo->cylinders);
-- put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
-- break;
-- case BLKGETSIZE:
-- ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
-- break;
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
-- break;
--#endif
-- case BLKRRPART:
-- ret = ftl_reread_partitions(minor);
-- break;
--#if (LINUX_VERSION_CODE < 0x20303)
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- break;
-- RO_IOCTLS(inode->i_rdev, arg);
--#else
-- case BLKROSET:
-- case BLKROGET:
-- case BLKFLSBUF:
-- ret = blk_ioctl(inode->i_rdev, cmd, arg);
-- break;
--#endif
-- default:
-- ret = -EINVAL;
-- }
--
-- return ret;
--} /* ftl_ioctl */
--
--/*======================================================================
-
-- Handler for block device requests
-+ geo->heads = 1;
-+ geo->sectors = 8;
-+ geo->cylinders = sect >> 3;
-
--======================================================================*/
--
--static int ftl_reread_partitions(int minor)
--{
-- partition_t *part = myparts[minor >> 4];
-- int i, whole;
--
-- DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
-- if ((atomic_read(&part->open) > 1)) {
-- return -EBUSY;
-- }
-- whole = minor & ~(MAX_PART-1);
--
-- i = MAX_PART - 1;
-- while (i-- > 0) {
-- if (ftl_hd[whole+i].nr_sects > 0) {
-- kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
--
-- invalidate_device(rdev, 1);
-- }
-- ftl_hd[whole+i].start_sect = 0;
-- ftl_hd[whole+i].nr_sects = 0;
-- }
--
-- scan_header(part);
--
-- register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
-- &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
--
--#ifdef PCMCIA_DEBUG
-- for (i = 0; i < MAX_PART; i++) {
-- if (ftl_hd[whole+i].nr_sects > 0)
-- printk(KERN_INFO " %d: start %ld size %ld\n", i,
-- ftl_hd[whole+i].start_sect,
-- ftl_hd[whole+i].nr_sects);
-- }
--#endif
- return 0;
- }
-
--/*======================================================================
--
-- Handler for block device requests
--
--======================================================================*/
--
--static void do_ftl_request(request_arg_t)
-+static int ftl_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- int ret, minor;
-- partition_t *part;
--
-- do {
-- // sti();
-- INIT_REQUEST;
--
-- minor = MINOR(CURRENT->rq_dev);
--
-- part = myparts[minor >> 4];
-- if (part) {
-- ret = 0;
--
-- switch (CURRENT->cmd) {
-- case READ:
-- ret = ftl_read(part, CURRENT->buffer,
-- CURRENT->sector+ftl_hd[minor].start_sect,
-- CURRENT->current_nr_sectors);
-- if (ret) printk("ftl_read returned %d\n", ret);
-- break;
--
-- case WRITE:
-- ret = ftl_write(part, CURRENT->buffer,
-- CURRENT->sector+ftl_hd[minor].start_sect,
-- CURRENT->current_nr_sectors);
-- if (ret) printk("ftl_write returned %d\n", ret);
-- break;
--
-- default:
-- panic("ftl_cs: unknown block command!\n");
--
-- }
-- } else {
-- ret = 1;
-- printk("NULL part in ftl_request\n");
-- }
--
-- if (!ret) {
-- CURRENT->sector += CURRENT->current_nr_sectors;
-- }
-+ return ftl_read((void *)dev, buf, block, 1);
-+}
-
-- end_request((ret == 0) ? 1 : 0);
-- } while (1);
--} /* do_ftl_request */
-+static int ftl_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ return ftl_write((void *)dev, buf, block, 1);
-+}
-
- /*====================================================================*/
-
-@@ -1337,19 +1038,9 @@
-
- } /* ftl_freepart */
-
--static void ftl_notify_add(struct mtd_info *mtd)
-+static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
- partition_t *partition;
-- int device;
--
-- for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
-- ;
--
-- if (device == MAX_MTD_DEVICES) {
-- printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
-- "Not scanning <%s>\n", mtd->name);
-- return;
-- }
-
- partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-
-@@ -1361,92 +1052,55 @@
-
- memset(partition, 0, sizeof(partition_t));
-
-- partition->mtd = mtd;
-+ partition->mbd.mtd = mtd;
-
- if ((scan_header(partition) == 0) &&
- (build_maps(partition) == 0)) {
-
- partition->state = FTL_FORMATTED;
-- atomic_set(&partition->open, 0);
-- myparts[device] = partition;
-- ftl_reread_partitions(device << 4);
- #ifdef PCMCIA_DEBUG
-- printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
-+ printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
- le32_to_cpu(partition->header.FormattedSize) >> 10);
- #endif
-+ partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
-+ partition->mbd.blksize = SECTOR_SIZE;
-+ partition->mbd.tr = tr;
-+ partition->mbd.devnum = -1;
-+ if (add_mtd_blktrans_dev((void *)partition))
-+ kfree(partition);
-+
- } else
- kfree(partition);
- }
-
--static void ftl_notify_remove(struct mtd_info *mtd)
-+static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- int i,j;
--
-- /* Q: What happens if you try to remove a device which has
-- * a currently-open FTL partition on it?
-- *
-- * A: You don't. The ftl_open routine is responsible for
-- * increasing the use count of the driver module which
-- * it uses.
-- */
--
-- /* That's the theory, anyway :) */
--
-- for (i=0; i< MAX_MTD_DEVICES; i++)
-- if (myparts[i] && myparts[i]->mtd == mtd) {
--
-- if (myparts[i]->state == FTL_FORMATTED)
-- ftl_freepart(myparts[i]);
--
-- myparts[i]->state = 0;
-- for (j=0; j<16; j++) {
-- ftl_gendisk.part[j].nr_sects=0;
-- ftl_gendisk.part[j].start_sect=0;
-- }
-- kfree(myparts[i]);
-- myparts[i] = NULL;
-- }
-+ del_mtd_blktrans_dev(dev);
-+ kfree(dev);
- }
-
-+struct mtd_blktrans_ops ftl_tr = {
-+ .name = "ftl",
-+ .major = FTL_MAJOR,
-+ .part_bits = PART_BITS,
-+ .readsect = ftl_readsect,
-+ .writesect = ftl_writesect,
-+ .getgeo = ftl_getgeo,
-+ .add_mtd = ftl_add_mtd,
-+ .remove_dev = ftl_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-+
- int init_ftl(void)
- {
-- int i;
--
-- memset(myparts, 0, sizeof(myparts));
-+ DEBUG(0, "$Id$\n");
-
-- DEBUG(0, "$Id$\n");
--
-- if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
-- printk(KERN_NOTICE "ftl_cs: unable to grab major "
-- "device number!\n");
-- return -EAGAIN;
-- }
--
-- for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
-- ftl_blocksizes[i] = 1024;
-- for (i = 0; i < MAX_DEV*MAX_PART; i++) {
-- ftl_hd[i].nr_sects = 0;
-- ftl_hd[i].start_sect = 0;
-- }
-- blksize_size[FTL_MAJOR] = ftl_blocksizes;
-- ftl_gendisk.major = FTL_MAJOR;
-- blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
-- add_gendisk(&ftl_gendisk);
--
-- register_mtd_user(&ftl_notifier);
--
-- return 0;
-+ return register_mtd_blktrans(&ftl_tr);
- }
-
- static void __exit cleanup_ftl(void)
- {
-- unregister_mtd_user(&ftl_notifier);
--
-- unregister_blkdev(FTL_MAJOR, "ftl");
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
-- blksize_size[FTL_MAJOR] = NULL;
--
-- del_gendisk(&ftl_gendisk);
-+ deregister_mtd_blktrans(&ftl_tr);
- }
-
- module_init(init_ftl);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/inftlcore.c linux/drivers/mtd/inftlcore.c
---- linux-mips-2.4.27/drivers/mtd/inftlcore.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/inftlcore.c 2004-11-19 10:25:11.632240376 +0100
-@@ -0,0 +1,900 @@
-+/*
-+ * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
-+ *
-+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * Based heavily on the nftlcore.c code which is:
-+ * (c) 1999 Machine Vision Holdings, Inc.
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * $Id$
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/kmod.h>
-+#include <linux/hdreg.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+#include <linux/mtd/inftl.h>
-+#include <asm/uaccess.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+
-+/*
-+ * Maximum number of loops while examining next block, to have a
-+ * chance to detect consistency problems (they should never happen
-+ * because of the checks done in the mounting.
-+ */
-+#define MAX_LOOPS 10000
-+
-+extern void INFTL_dumptables(struct INFTLrecord *inftl);
-+extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
-+
-+static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
-+{
-+ struct INFTLrecord *inftl;
-+ unsigned long temp;
-+
-+ if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
-+ return;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
-+
-+ inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
-+
-+ if (!inftl) {
-+ printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
-+ return;
-+ }
-+ memset(inftl, 0, sizeof(*inftl));
-+
-+ inftl->mbd.mtd = mtd;
-+ inftl->mbd.devnum = -1;
-+ inftl->mbd.blksize = 512;
-+ inftl->mbd.tr = tr;
-+
-+ if (INFTL_mount(inftl) < 0) {
-+ printk(KERN_WARNING "INFTL: could not mount device\n");
-+ kfree(inftl);
-+ return;
-+ }
-+
-+ /* OK, it's a new one. Set up all the data structures. */
-+
-+ /* Calculate geometry */
-+ inftl->cylinders = 1024;
-+ inftl->heads = 16;
-+
-+ temp = inftl->cylinders * inftl->heads;
-+ inftl->sectors = inftl->mbd.size / temp;
-+ if (inftl->mbd.size % temp) {
-+ inftl->sectors++;
-+ temp = inftl->cylinders * inftl->sectors;
-+ inftl->heads = inftl->mbd.size / temp;
-+
-+ if (inftl->mbd.size % temp) {
-+ inftl->heads++;
-+ temp = inftl->heads * inftl->sectors;
-+ inftl->cylinders = inftl->mbd.size / temp;
-+ }
-+ }
-+
-+ if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
-+ /*
-+ Oh no we don't have
-+ mbd.size == heads * cylinders * sectors
-+ */
-+ printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
-+ "match size of 0x%lx.\n", inftl->mbd.size);
-+ printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
-+ "(== 0x%lx sects)\n",
-+ inftl->cylinders, inftl->heads , inftl->sectors,
-+ (long)inftl->cylinders * (long)inftl->heads *
-+ (long)inftl->sectors );
-+ }
-+
-+ if (add_mtd_blktrans_dev(&inftl->mbd)) {
-+ if (inftl->PUtable)
-+ kfree(inftl->PUtable);
-+ if (inftl->VUtable)
-+ kfree(inftl->VUtable);
-+ kfree(inftl);
-+ return;
-+ }
-+#ifdef PSYCHO_DEBUG
-+ printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
-+#endif
-+ return;
-+}
-+
-+static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
-+{
-+ struct INFTLrecord *inftl = (void *)dev;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum);
-+
-+ del_mtd_blktrans_dev(dev);
-+
-+ if (inftl->PUtable)
-+ kfree(inftl->PUtable);
-+ if (inftl->VUtable)
-+ kfree(inftl->VUtable);
-+ kfree(inftl);
-+}
-+
-+/*
-+ * Actual INFTL access routines.
-+ */
-+
-+/*
-+ * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
-+ * This function is used when the give Virtual Unit Chain.
-+ */
-+static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
-+{
-+ u16 pot = inftl->LastFreeEUN;
-+ int silly = inftl->nb_blocks;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x,"
-+ "desperate=%d)\n", (int)inftl, desperate);
-+
-+ /*
-+ * Normally, we force a fold to happen before we run out of free
-+ * blocks completely.
-+ */
-+ if (!desperate && inftl->numfreeEUNs < 2) {
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
-+ "EUNs (%d)\n", inftl->numfreeEUNs);
-+ return 0xffff;
-+ }
-+
-+ /* Scan for a free block */
-+ do {
-+ if (inftl->PUtable[pot] == BLOCK_FREE) {
-+ inftl->LastFreeEUN = pot;
-+ return pot;
-+ }
-+
-+ if (++pot > inftl->lastEUN)
-+ pot = 0;
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: no free blocks found! "
-+ "EUN range = %d - %d\n", 0, inftl->LastFreeEUN);
-+ return BLOCK_NIL;
-+ }
-+ } while (pot != inftl->LastFreeEUN);
-+
-+ return BLOCK_NIL;
-+}
-+
-+static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
-+{
-+ u16 BlockMap[MAX_SECTORS_PER_UNIT];
-+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
-+ unsigned int thisEUN, prevEUN, status;
-+ int block, silly;
-+ unsigned int targetEUN;
-+ struct inftl_oob oob;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d,"
-+ "pending=%d)\n", (int)inftl, thisVUC, pendingblock);
-+
-+ memset(BlockMap, 0xff, sizeof(BlockMap));
-+ memset(BlockDeleted, 0, sizeof(BlockDeleted));
-+
-+ thisEUN = targetEUN = inftl->VUtable[thisVUC];
-+
-+ if (thisEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "INFTL: trying to fold non-existent "
-+ "Virtual Unit Chain %d!\n", thisVUC);
-+ return BLOCK_NIL;
-+ }
-+
-+ /*
-+ * Scan to find the Erase Unit which holds the actual data for each
-+ * 512-byte block within the Chain.
-+ */
-+ silly = MAX_LOOPS;
-+ while (thisEUN < inftl->nb_blocks) {
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
-+ if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
-+ continue;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
-+ + (block * SECTORSIZE), 16 , &retlen,
-+ (char *)&oob) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = oob.b.Status | oob.b.Status1;
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_USED:
-+ BlockMap[block] = thisEUN;
-+ continue;
-+ case SECTOR_DELETED:
-+ BlockDeleted[block] = 1;
-+ continue;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status "
-+ "for block %d in EUN %d: %x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return BLOCK_NIL;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ /*
-+ * OK. We now know the location of every block in the Virtual Unit
-+ * Chain, and the Erase Unit into which we are supposed to be copying.
-+ * Go for it.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n",
-+ thisVUC, targetEUN);
-+
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
-+ unsigned char movebuf[SECTORSIZE];
-+ int ret;
-+
-+ /*
-+ * If it's in the target EUN already, or if it's pending write,
-+ * do nothing.
-+ */
-+ if (BlockMap[block] == targetEUN || (pendingblock ==
-+ (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
-+ continue;
-+ }
-+
-+ /*
-+ * Copy only in non free block (free blocks can only
-+ * happen in case of media errors or deleted blocks).
-+ */
-+ if (BlockMap[block] == BLOCK_NIL)
-+ continue;
-+
-+ ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
-+ BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-+ &retlen, movebuf, (char *)&oob, NULL);
-+ if (ret < 0) {
-+ ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
-+ BlockMap[block]) + (block * SECTORSIZE),
-+ SECTORSIZE, &retlen, movebuf, (char *)&oob,
-+ NULL);
-+ if (ret != -EIO)
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
-+ "away on retry?\n");
-+ }
-+ MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
-+ (block * SECTORSIZE), SECTORSIZE, &retlen,
-+ movebuf, (char *)&oob, NULL);
-+ }
-+
-+ /*
-+ * Newest unit in chain now contains data from _all_ older units.
-+ * So go through and erase each unit in chain, oldest first. (This
-+ * is important, by doing oldest first if we crash/reboot then it
-+ * it is relatively simple to clean up the mess).
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n",
-+ thisVUC);
-+
-+ for (;;) {
-+ /* Find oldest unit in chain. */
-+ thisEUN = inftl->VUtable[thisVUC];
-+ prevEUN = BLOCK_NIL;
-+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
-+ prevEUN = thisEUN;
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ /* Check if we are all done */
-+ if (thisEUN == targetEUN)
-+ break;
-+
-+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
-+ /*
-+ * Could not erase : mark block as reserved.
-+ * FixMe: Update Bad Unit Table on disk.
-+ */
-+ inftl->PUtable[thisEUN] = BLOCK_RESERVED;
-+ } else {
-+ /* Correctly erased : mark it as free */
-+ inftl->PUtable[thisEUN] = BLOCK_FREE;
-+ inftl->PUtable[prevEUN] = BLOCK_NIL;
-+ inftl->numfreeEUNs++;
-+ }
-+ }
-+
-+ return targetEUN;
-+}
-+
-+u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
-+{
-+ /*
-+ * This is the part that needs some cleverness applied.
-+ * For now, I'm doing the minimum applicable to actually
-+ * get the thing to work.
-+ * Wear-levelling and other clever stuff needs to be implemented
-+ * and we also need to do some assessment of the results when
-+ * the system loses power half-way through the routine.
-+ */
-+ u16 LongestChain = 0;
-+ u16 ChainLength = 0, thislen;
-+ u16 chain, EUN;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x,"
-+ "pending=%d)\n", (int)inftl, pendingblock);
-+
-+ for (chain = 0; chain < inftl->nb_blocks; chain++) {
-+ EUN = inftl->VUtable[chain];
-+ thislen = 0;
-+
-+ while (EUN <= inftl->lastEUN) {
-+ thislen++;
-+ EUN = inftl->PUtable[EUN];
-+ if (thislen > 0xff00) {
-+ printk(KERN_WARNING "INFTL: endless loop in "
-+ "Virtual Chain %d: Unit %x\n",
-+ chain, EUN);
-+ /*
-+ * Actually, don't return failure.
-+ * Just ignore this chain and get on with it.
-+ */
-+ thislen = 0;
-+ break;
-+ }
-+ }
-+
-+ if (thislen > ChainLength) {
-+ ChainLength = thislen;
-+ LongestChain = chain;
-+ }
-+ }
-+
-+ if (ChainLength < 2) {
-+ printk(KERN_WARNING "INFTL: no Virtual Unit Chains available "
-+ "for folding. Failing request\n");
-+ return BLOCK_NIL;
-+ }
-+
-+ return INFTL_foldchain(inftl, LongestChain, pendingblock);
-+}
-+
-+static int nrbits(unsigned int val, int bitcount)
-+{
-+ int i, total = 0;
-+
-+ for (i = 0; (i < bitcount); i++)
-+ total += (((0x1 << i) & val) ? 1 : 0);
-+ return total;
-+}
-+
-+/*
-+ * INFTL_findwriteunit: Return the unit number into which we can write
-+ * for this block. Make it available if it isn't already.
-+ */
-+static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
-+{
-+ unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
-+ unsigned int thisEUN, writeEUN, prev_block, status;
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
-+ struct inftl_oob oob;
-+ struct inftl_bci bci;
-+ unsigned char anac, nacs, parity;
-+ size_t retlen;
-+ int silly, silly2 = 3;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x,"
-+ "block=%d)\n", (int)inftl, block);
-+
-+ do {
-+ /*
-+ * Scan the media to find a unit in the VUC which has
-+ * a free space for the block in question.
-+ */
-+ writeEUN = BLOCK_NIL;
-+ thisEUN = inftl->VUtable[thisVUC];
-+ silly = MAX_LOOPS;
-+
-+ while (thisEUN <= inftl->lastEUN) {
-+ MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci);
-+
-+ status = bci.Status | bci.Status1;
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
-+ "EUN %d is %x\n", block , writeEUN, status);
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ writeEUN = thisEUN;
-+ break;
-+ case SECTOR_DELETED:
-+ case SECTOR_USED:
-+ /* Can't go any further */
-+ goto hitused;
-+ case SECTOR_IGNORE:
-+ break;
-+ default:
-+ /*
-+ * Invalid block. Don't use it any more.
-+ * Must implement.
-+ */
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in "
-+ "Virtual Unit Chain 0x%x\n", thisVUC);
-+ return 0xffff;
-+ }
-+
-+ /* Skip to next block in chain */
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+hitused:
-+ if (writeEUN != BLOCK_NIL)
-+ return writeEUN;
-+
-+
-+ /*
-+ * OK. We didn't find one in the existing chain, or there
-+ * is no existing chain. Allocate a new one.
-+ */
-+ writeEUN = INFTL_findfreeblock(inftl, 0);
-+
-+ if (writeEUN == BLOCK_NIL) {
-+ /*
-+ * That didn't work - there were no free blocks just
-+ * waiting to be picked up. We're going to have to fold
-+ * a chain to make room.
-+ */
-+ thisEUN = INFTL_makefreeblock(inftl, 0xffff);
-+
-+ /*
-+ * Hopefully we free something, lets try again.
-+ * This time we are desperate...
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 "
-+ "to find free EUN to accommodate write to "
-+ "VUC %d\n", thisVUC);
-+ writeEUN = INFTL_findfreeblock(inftl, 1);
-+ if (writeEUN == BLOCK_NIL) {
-+ /*
-+ * Ouch. This should never happen - we should
-+ * always be able to make some room somehow.
-+ * If we get here, we've allocated more storage
-+ * space than actual media, or our makefreeblock
-+ * routine is missing something.
-+ */
-+ printk(KERN_WARNING "INFTL: cannot make free "
-+ "space.\n");
-+#ifdef DEBUG
-+ INFTL_dumptables(inftl);
-+ INFTL_dumpVUchains(inftl);
-+#endif
-+ return BLOCK_NIL;
-+ }
-+ }
-+
-+ /*
-+ * Insert new block into virtual chain. Firstly update the
-+ * block headers in flash...
-+ */
-+ anac = 0;
-+ nacs = 0;
-+ thisEUN = inftl->VUtable[thisVUC];
-+ if (thisEUN != BLOCK_NIL) {
-+ MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize
-+ + 8, 8, &retlen, (char *)&oob.u);
-+ anac = oob.u.a.ANAC + 1;
-+ nacs = oob.u.a.NACs + 1;
-+ }
-+
-+ prev_block = inftl->VUtable[thisVUC];
-+ if (prev_block < inftl->nb_blocks)
-+ prev_block -= inftl->firstEUN;
-+
-+ parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;
-+ parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
-+ parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
-+ parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
-+
-+ oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
-+ oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
-+ oob.u.a.ANAC = anac;
-+ oob.u.a.NACs = nacs;
-+ oob.u.a.parityPerField = parity;
-+ oob.u.a.discarded = 0xaa;
-+
-+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8,
-+ &retlen, (char *)&oob.u);
-+
-+ /* Also back up header... */
-+ oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
-+ oob.u.b.prevUnitNo = cpu_to_le16(prev_block);
-+ oob.u.b.ANAC = anac;
-+ oob.u.b.NACs = nacs;
-+ oob.u.b.parityPerField = parity;
-+ oob.u.b.discarded = 0xaa;
-+
-+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
-+ SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
-+
-+ inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
-+ inftl->VUtable[thisVUC] = writeEUN;
-+
-+ inftl->numfreeEUNs--;
-+ return writeEUN;
-+
-+ } while (silly2--);
-+
-+ printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return 0xffff;
-+}
-+
-+/*
-+ * Given a Virtual Unit Chain, see if it can be deleted, and if so do it.
-+ */
-+static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
-+{
-+ unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
-+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
-+ unsigned int thisEUN, status;
-+ int block, silly;
-+ struct inftl_bci bci;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x,"
-+ "thisVUC=%d)\n", (int)inftl, thisVUC);
-+
-+ memset(BlockUsed, 0, sizeof(BlockUsed));
-+ memset(BlockDeleted, 0, sizeof(BlockDeleted));
-+
-+ thisEUN = inftl->VUtable[thisVUC];
-+ if (thisEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "INFTL: trying to delete non-existent "
-+ "Virtual Unit Chain %d!\n", thisVUC);
-+ return;
-+ }
-+
-+ /*
-+ * Scan through the Erase Units to determine whether any data is in
-+ * each of the 512-byte blocks within the Chain.
-+ */
-+ silly = MAX_LOOPS;
-+ while (thisEUN < inftl->nb_blocks) {
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {
-+ if (BlockUsed[block] || BlockDeleted[block])
-+ continue;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
-+ + (block * SECTORSIZE), 8 , &retlen,
-+ (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch(status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_USED:
-+ BlockUsed[block] = 1;
-+ continue;
-+ case SECTOR_DELETED:
-+ BlockDeleted[block] = 1;
-+ continue;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status "
-+ "for block %d in EUN %d: 0x%x\n",
-+ block, thisEUN, status);
-+ }
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n", thisVUC);
-+ return;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)
-+ if (BlockUsed[block])
-+ return;
-+
-+ /*
-+ * For each block in the chain free it and make it available
-+ * for future use. Erase from the oldest unit first.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC);
-+
-+ for (;;) {
-+ u16 *prevEUN = &inftl->VUtable[thisVUC];
-+ thisEUN = *prevEUN;
-+
-+ /* If the chain is all gone already, we're done */
-+ if (thisEUN == BLOCK_NIL) {
-+ DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);
-+ return;
-+ }
-+
-+ /* Find oldest unit in chain. */
-+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
-+ BUG_ON(thisEUN >= inftl->nb_blocks);
-+
-+ prevEUN = &inftl->PUtable[thisEUN];
-+ thisEUN = *prevEUN;
-+ }
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
-+ thisEUN, thisVUC);
-+
-+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
-+ /*
-+ * Could not erase : mark block as reserved.
-+ * FixMe: Update Bad Unit Table on medium.
-+ */
-+ inftl->PUtable[thisEUN] = BLOCK_RESERVED;
-+ } else {
-+ /* Correctly erased : mark it as free */
-+ inftl->PUtable[thisEUN] = BLOCK_FREE;
-+ inftl->numfreeEUNs++;
-+ }
-+
-+ /* Now sort out whatever was pointing to it... */
-+ *prevEUN = BLOCK_NIL;
-+
-+ /* Ideally we'd actually be responsive to new
-+ requests while we're doing this -- if there's
-+ free space why should others be made to wait? */
-+ cond_resched();
-+ }
-+
-+ inftl->VUtable[thisVUC] = BLOCK_NIL;
-+}
-+
-+static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
-+{
-+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ unsigned int status;
-+ int silly = MAX_LOOPS;
-+ size_t retlen;
-+ struct inftl_bci bci;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x,"
-+ "block=%d)\n", (int)inftl, block);
-+
-+ while (thisEUN < inftl->nb_blocks) {
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch (status) {
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ case SECTOR_DELETED:
-+ thisEUN = BLOCK_NIL;
-+ goto foundit;
-+ case SECTOR_USED:
-+ goto foundit;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status for "
-+ "block %d in EUN %d: 0x%x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in Virtual "
-+ "Unit Chain 0x%x\n",
-+ block / (inftl->EraseSize / SECTORSIZE));
-+ return 1;
-+ }
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+foundit:
-+ if (thisEUN != BLOCK_NIL) {
-+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-+
-+ if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
-+ return -EIO;
-+ bci.Status = bci.Status1 = SECTOR_DELETED;
-+ if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
-+ return -EIO;
-+ INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
-+ }
-+ return 0;
-+}
-+
-+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
-+{
-+ struct INFTLrecord *inftl = (void *)mbd;
-+ unsigned int writeEUN;
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ size_t retlen;
-+ u8 eccbuf[6];
-+ char *p, *pend;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%d,"
-+ "buffer=0x%x)\n", (int)inftl, block, (int)buffer);
-+
-+ /* Is block all zero? */
-+ pend = buffer + SECTORSIZE;
-+ for (p = buffer; p < pend && !*p; p++)
-+ ;
-+
-+ if (p < pend) {
-+ writeEUN = INFTL_findwriteunit(inftl, block);
-+
-+ if (writeEUN == BLOCK_NIL) {
-+ printk(KERN_WARNING "inftl_writeblock(): cannot find "
-+ "block to write to\n");
-+ /*
-+ * If we _still_ haven't got a block to use,
-+ * we're screwed.
-+ */
-+ return 1;
-+ }
-+
-+ MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
-+ blockofs, SECTORSIZE, &retlen, (char *)buffer,
-+ (char *)eccbuf, NULL);
-+ /*
-+ * No need to write SECTOR_USED flags since they are written
-+ * in mtd_writeecc
-+ */
-+ } else {
-+ INFTL_deleteblock(inftl, block);
-+ }
-+
-+ return 0;
-+}
-+
-+static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
-+{
-+ struct INFTLrecord *inftl = (void *)mbd;
-+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
-+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
-+ unsigned int status;
-+ int silly = MAX_LOOPS;
-+ struct inftl_bci bci;
-+ size_t retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%d,"
-+ "buffer=0x%x)\n", (int)inftl, block, (int)buffer);
-+
-+ while (thisEUN < inftl->nb_blocks) {
-+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-+ blockofs, 8, &retlen, (char *)&bci) < 0)
-+ status = SECTOR_IGNORE;
-+ else
-+ status = bci.Status | bci.Status1;
-+
-+ switch (status) {
-+ case SECTOR_DELETED:
-+ thisEUN = BLOCK_NIL;
-+ goto foundit;
-+ case SECTOR_USED:
-+ goto foundit;
-+ case SECTOR_FREE:
-+ case SECTOR_IGNORE:
-+ break;
-+ default:
-+ printk(KERN_WARNING "INFTL: unknown status for "
-+ "block %ld in EUN %d: 0x%04x\n",
-+ block, thisEUN, status);
-+ break;
-+ }
-+
-+ if (!silly--) {
-+ printk(KERN_WARNING "INFTL: infinite loop in "
-+ "Virtual Unit Chain 0x%lx\n",
-+ block / (inftl->EraseSize / SECTORSIZE));
-+ return 1;
-+ }
-+
-+ thisEUN = inftl->PUtable[thisEUN];
-+ }
-+
-+foundit:
-+ if (thisEUN == BLOCK_NIL) {
-+ /* The requested block is not on the media, return all 0x00 */
-+ memset(buffer, 0, SECTORSIZE);
-+ } else {
-+ size_t retlen;
-+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-+ u_char eccbuf[6];
-+ if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
-+ buffer, eccbuf, NULL))
-+ return -EIO;
-+ }
-+ return 0;
-+}
-+
-+static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
-+{
-+ struct INFTLrecord *inftl = (void *)dev;
-+
-+ geo->heads = inftl->heads;
-+ geo->sectors = inftl->sectors;
-+ geo->cylinders = inftl->cylinders;
-+
-+ return 0;
-+}
-+
-+struct mtd_blktrans_ops inftl_tr = {
-+ .name = "inftl",
-+ .major = INFTL_MAJOR,
-+ .part_bits = INFTL_PARTN_BITS,
-+ .getgeo = inftl_getgeo,
-+ .readsect = inftl_readblock,
-+ .writesect = inftl_writeblock,
-+ .add_mtd = inftl_add_mtd,
-+ .remove_dev = inftl_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-+
-+extern char inftlmountrev[];
-+
-+int __init init_inftl(void)
-+{
-+ printk(KERN_INFO "INFTL: inftlcore.c $Revision$, "
-+ "inftlmount.c %s\n", inftlmountrev);
-+
-+ return register_mtd_blktrans(&inftl_tr);
-+}
-+
-+static void __exit cleanup_inftl(void)
-+{
-+ deregister_mtd_blktrans(&inftl_tr);
-+}
-+
-+module_init(init_inftl);
-+module_exit(cleanup_inftl);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
-+MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/inftlmount.c linux/drivers/mtd/inftlmount.c
---- linux-mips-2.4.27/drivers/mtd/inftlmount.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/inftlmount.c 2004-11-19 10:25:11.633240224 +0100
-@@ -0,0 +1,817 @@
-+/*
-+ * inftlmount.c -- INFTL mount code with extensive checks.
-+ *
-+ * Author: Greg Ungerer (gerg@snapgear.com)
-+ * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * Based heavily on the nftlmount.c code which is:
-+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
-+ * Copyright (C) 2000 Netgem S.A.
-+ *
-+ * $Id$
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+#include <linux/miscdevice.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+#include <linux/mtd/inftl.h>
-+#include <linux/mtd/compatmac.h>
-+
-+char inftlmountrev[]="$Revision$";
-+
-+/*
-+ * find_boot_record: Find the INFTL Media Header and its Spare copy which
-+ * contains the various device information of the INFTL partition and
-+ * Bad Unit Table. Update the PUtable[] table according to the Bad
-+ * Unit Table. PUtable[] is used for management of Erase Unit in
-+ * other routines in inftlcore.c and inftlmount.c.
-+ */
-+static int find_boot_record(struct INFTLrecord *inftl)
-+{
-+ struct inftl_unittail h1;
-+ //struct inftl_oob oob;
-+ unsigned int i, block, boot_record_count = 0;
-+ u8 buf[SECTORSIZE];
-+ struct INFTLMediaHeader *mh = &inftl->MediaHdr;
-+ struct INFTLPartition *ip;
-+ int retlen;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n",
-+ (int)inftl);
-+
-+ /*
-+ * Assume logical EraseSize == physical erasesize for starting the
-+ * scan. We'll sort it out later if we find a MediaHeader which says
-+ * otherwise.
-+ */
-+ inftl->EraseSize = inftl->mbd.mtd->erasesize;
-+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
-+
-+ inftl->MediaUnit = BLOCK_NIL;
-+ inftl->SpareMediaUnit = BLOCK_NIL;
-+
-+ /* Search for a valid boot record */
-+ for (block = 0; block < inftl->nb_blocks; block++) {
-+ int ret;
-+
-+ /*
-+ * Check for BNAND header first. Then whinge if it's found
-+ * but later checks fail.
-+ */
-+ if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
-+ SECTORSIZE, &retlen, buf))) {
-+ static int warncount = 5;
-+
-+ if (warncount) {
-+ printk(KERN_WARNING "INFTL: block read at 0x%x "
-+ "of mtd%d failed: %d\n",
-+ block * inftl->EraseSize,
-+ inftl->mbd.mtd->index, ret);
-+ if (!--warncount)
-+ printk(KERN_WARNING "INFTL: further "
-+ "failures for this block will "
-+ "not be printed\n");
-+ }
-+ continue;
-+ }
-+
-+ if (retlen < 6 || memcmp(buf, "BNAND", 6)) {
-+ /* BNAND\0 not found. Continue */
-+ continue;
-+ }
-+
-+ /* To be safer with BIOS, also use erase mark as discriminant */
-+ if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +
-+ SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {
-+ printk(KERN_WARNING "INFTL: ANAND header found at "
-+ "0x%x in mtd%d, but OOB data read failed "
-+ "(err %d)\n", block * inftl->EraseSize,
-+ inftl->mbd.mtd->index, ret);
-+ continue;
-+ }
-+
-+ if (boot_record_count) {
-+ /*
-+ * We've already processed one. So we just check if
-+ * this one is the same as the first one we found.
-+ */
-+ if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
-+ printk(KERN_WARNING "INFTL: Media Headers at "
-+ "0x%x and 0x%x disagree.\n",
-+ inftl->MediaUnit * inftl->EraseSize,
-+ block * inftl->EraseSize);
-+ return -1;
-+ }
-+ if (boot_record_count == 1)
-+ inftl->SpareMediaUnit = block;
-+
-+ /*
-+ * Mark this boot record (INFTL MediaHeader) block as
-+ * reserved.
-+ */
-+ inftl->PUtable[block] = BLOCK_RESERVED;
-+
-+ boot_record_count++;
-+ continue;
-+ }
-+
-+ /*
-+ * This is the first we've seen.
-+ * Copy the media header structure into place.
-+ */
-+ memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
-+ mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
-+ mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
-+ mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
-+ mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
-+ mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
-+ mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {
-+ printk("INFTL: Media Header ->\n"
-+ " bootRecordID = %s\n"
-+ " NoOfBootImageBlocks = %d\n"
-+ " NoOfBinaryPartitions = %d\n"
-+ " NoOfBDTLPartitions = %d\n"
-+ " BlockMultiplerBits = %d\n"
-+ " FormatFlgs = %d\n"
-+ " OsakVersion = 0x%x\n"
-+ " PercentUsed = %d\n",
-+ mh->bootRecordID, mh->NoOfBootImageBlocks,
-+ mh->NoOfBinaryPartitions,
-+ mh->NoOfBDTLPartitions,
-+ mh->BlockMultiplierBits, mh->FormatFlags,
-+ mh->OsakVersion, mh->PercentUsed);
-+ }
-+#endif
-+
-+ if (mh->NoOfBDTLPartitions == 0) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed: NoOfBDTLPartitions (%d) == 0, "
-+ "must be at least 1\n", mh->NoOfBDTLPartitions);
-+ return -1;
-+ }
-+
-+ if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed: Total Partitions (%d) > 4, "
-+ "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +
-+ mh->NoOfBinaryPartitions,
-+ mh->NoOfBDTLPartitions,
-+ mh->NoOfBinaryPartitions);
-+ return -1;
-+ }
-+
-+ if (mh->BlockMultiplierBits > 1) {
-+ printk(KERN_WARNING "INFTL: sorry, we don't support "
-+ "UnitSizeFactor 0x%02x\n",
-+ mh->BlockMultiplierBits);
-+ return -1;
-+ } else if (mh->BlockMultiplierBits == 1) {
-+ printk(KERN_WARNING "INFTL: support for INFTL with "
-+ "UnitSizeFactor 0x%02x is experimental\n",
-+ mh->BlockMultiplierBits);
-+ inftl->EraseSize = inftl->mbd.mtd->erasesize <<
-+ (0xff - mh->BlockMultiplierBits);
-+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
-+ }
-+
-+ /* Scan the partitions */
-+ for (i = 0; (i < 4); i++) {
-+ ip = &mh->Partitions[i];
-+ ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
-+ ip->firstUnit = le32_to_cpu(ip->firstUnit);
-+ ip->lastUnit = le32_to_cpu(ip->lastUnit);
-+ ip->flags = le32_to_cpu(ip->flags);
-+ ip->spareUnits = le32_to_cpu(ip->spareUnits);
-+ ip->Reserved0 = le32_to_cpu(ip->Reserved0);
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {
-+ printk(" PARTITION[%d] ->\n"
-+ " virtualUnits = %d\n"
-+ " firstUnit = %d\n"
-+ " lastUnit = %d\n"
-+ " flags = 0x%x\n"
-+ " spareUnits = %d\n",
-+ i, ip->virtualUnits, ip->firstUnit,
-+ ip->lastUnit, ip->flags,
-+ ip->spareUnits);
-+ }
-+#endif
-+
-+ if (ip->Reserved0 != ip->firstUnit) {
-+ struct erase_info *instr = &inftl->instr;
-+
-+ /*
-+ * Most likely this is using the
-+ * undocumented qiuck mount feature.
-+ * We don't support that, we will need
-+ * to erase the hidden block for full
-+ * compatibility.
-+ */
-+ instr->addr = ip->Reserved0 * inftl->EraseSize;
-+ instr->len = inftl->EraseSize;
-+ MTD_ERASE(inftl->mbd.mtd, instr);
-+ }
-+ if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
-+ printk(KERN_WARNING "INFTL: Media Header "
-+ "Partition %d sanity check failed\n"
-+ " firstUnit %d : lastUnit %d > "
-+ "virtualUnits %d\n", i, ip->lastUnit,
-+ ip->firstUnit, ip->Reserved0);
-+ return -1;
-+ }
-+ if (ip->Reserved1 != 0) {
-+ printk(KERN_WARNING "INFTL: Media Header "
-+ "Partition %d sanity check failed: "
-+ "Reserved1 %d != 0\n",
-+ i, ip->Reserved1);
-+ return -1;
-+ }
-+
-+ if (ip->flags & INFTL_BDTL)
-+ break;
-+ }
-+
-+ if (i >= 4) {
-+ printk(KERN_WARNING "INFTL: Media Header Partition "
-+ "sanity check failed:\n No partition "
-+ "marked as Disk Partition\n");
-+ return -1;
-+ }
-+
-+ inftl->nb_boot_blocks = ip->firstUnit;
-+ inftl->numvunits = ip->virtualUnits;
-+ if (inftl->numvunits > (inftl->nb_blocks -
-+ inftl->nb_boot_blocks - 2)) {
-+ printk(KERN_WARNING "INFTL: Media Header sanity check "
-+ "failed:\n numvunits (%d) > nb_blocks "
-+ "(%d) - nb_boot_blocks(%d) - 2\n",
-+ inftl->numvunits, inftl->nb_blocks,
-+ inftl->nb_boot_blocks);
-+ return -1;
-+ }
-+
-+ inftl->mbd.size = inftl->numvunits *
-+ (inftl->EraseSize / SECTORSIZE);
-+
-+ /*
-+ * Block count is set to last used EUN (we won't need to keep
-+ * any meta-data past that point).
-+ */
-+ inftl->firstEUN = ip->firstUnit;
-+ inftl->lastEUN = ip->lastUnit;
-+ inftl->nb_blocks = ip->lastUnit + 1;
-+
-+ /* Memory alloc */
-+ inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
-+ if (!inftl->PUtable) {
-+ printk(KERN_WARNING "INFTL: allocation of PUtable "
-+ "failed (%d bytes)\n",
-+ inftl->nb_blocks * sizeof(u16));
-+ return -ENOMEM;
-+ }
-+
-+ inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
-+ if (!inftl->VUtable) {
-+ kfree(inftl->PUtable);
-+ printk(KERN_WARNING "INFTL: allocation of VUtable "
-+ "failed (%d bytes)\n",
-+ inftl->nb_blocks * sizeof(u16));
-+ return -ENOMEM;
-+ }
-+
-+ /* Mark the blocks before INFTL MediaHeader as reserved */
-+ for (i = 0; i < inftl->nb_boot_blocks; i++)
-+ inftl->PUtable[i] = BLOCK_RESERVED;
-+ /* Mark all remaining blocks as potentially containing data */
-+ for (; i < inftl->nb_blocks; i++)
-+ inftl->PUtable[i] = BLOCK_NOTEXPLORED;
-+
-+ /* Mark this boot record (NFTL MediaHeader) block as reserved */
-+ inftl->PUtable[block] = BLOCK_RESERVED;
-+
-+#if 0
-+ /* Read Bad Erase Unit Table and modify PUtable[] accordingly */
-+ for (i = 0; i < inftl->nb_blocks; i++) {
-+ if ((i & (SECTORSIZE - 1)) == 0) {
-+ /* read one sector for every SECTORSIZE of blocks */
-+ if ((ret = MTD_READECC(inftl->mbd.mtd,
-+ block * inftl->EraseSize + i + SECTORSIZE,
-+ SECTORSIZE, &retlen, buf,
-+ (char *)&oob, NULL)) < 0) {
-+ printk(KERN_WARNING "INFTL: read of "
-+ "bad sector table failed "
-+ "(err %d)\n", ret);
-+ kfree(inftl->VUtable);
-+ kfree(inftl->PUtable);
-+ return -1;
-+ }
-+ }
-+ /* Mark the Bad Erase Unit as RESERVED in PUtable */
-+ if (buf[i & (SECTORSIZE - 1)] != 0xff)
-+ inftl->PUtable[i] = BLOCK_RESERVED;
-+ }
-+#endif
-+
-+ inftl->MediaUnit = block;
-+ boot_record_count++;
-+ }
-+
-+ return boot_record_count ? 0 : -1;
-+}
-+
-+static int memcmpb(void *a, int c, int n)
-+{
-+ int i;
-+ for (i = 0; i < n; i++) {
-+ if (c != ((unsigned char *)a)[i])
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * check_free_sector: check if a free sector is actually FREE,
-+ * i.e. All 0xff in data and oob area.
-+ */
-+static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
-+ int len, int check_oob)
-+{
-+ int i, retlen;
-+ u8 buf[SECTORSIZE];
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
-+ "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
-+ address, len, check_oob);
-+
-+ for (i = 0; i < len; i += SECTORSIZE) {
-+ /*
-+ * We want to read the sector without ECC check here since a
-+ * free sector does not have ECC syndrome on it yet.
-+ */
-+ if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
-+ return -1;
-+ if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
-+ return -1;
-+
-+ if (check_oob) {
-+ if (MTD_READOOB(inftl->mbd.mtd, address,
-+ inftl->mbd.mtd->oobsize, &retlen, buf) < 0)
-+ return -1;
-+ if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)
-+ return -1;
-+ }
-+ address += SECTORSIZE;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase
-+ * Unit and Update INFTL metadata. Each erase operation is
-+ * checked with check_free_sectors.
-+ *
-+ * Return: 0 when succeed, -1 on error.
-+ *
-+ * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
-+ * 2. UnitSizeFactor != 0xFF
-+ */
-+int INFTL_formatblock(struct INFTLrecord *inftl, int block)
-+{
-+ int retlen;
-+ struct inftl_unittail uci;
-+ struct erase_info *instr = &inftl->instr;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
-+ "block=%d)\n", (int)inftl, block);
-+
-+ memset(instr, 0, sizeof(struct erase_info));
-+
-+ /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
-+ _first_? */
-+
-+ /* Use async erase interface, test return code */
-+ instr->addr = block * inftl->EraseSize;
-+ instr->len = inftl->EraseSize;
-+ MTD_ERASE(inftl->mbd.mtd, instr);
-+
-+ if (instr->state == MTD_ERASE_FAILED) {
-+ /*
-+ * Could not format, FixMe: We should update the BadUnitTable
-+ * both in memory and on disk.
-+ */
-+ printk(KERN_WARNING "INFTL: error while formatting block %d\n",
-+ block);
-+ return -1;
-+ }
-+
-+ /*
-+ * Check the "freeness" of Erase Unit before updating metadata.
-+ * FixMe: is this check really necessary? Since we have check the
-+ * return code after the erase operation.
-+ */
-+ if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0)
-+ return -1;
-+
-+ uci.EraseMark = cpu_to_le16(ERASE_MARK);
-+ uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
-+ uci.Reserved[0] = 0;
-+ uci.Reserved[1] = 0;
-+ uci.Reserved[2] = 0;
-+ uci.Reserved[3] = 0;
-+ if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
-+ 8, 8, &retlen, (char *)&uci) < 0)
-+ return -1;
-+ return 0;
-+}
-+
-+/*
-+ * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase
-+ * Units in a Virtual Unit Chain, i.e. all the units are disconnected.
-+ *
-+ * Since the chain is invalid then we will have to erase it from its
-+ * head (normally for INFTL we go from the oldest). But if it has a
-+ * loop then there is no oldest...
-+ */
-+static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
-+{
-+ unsigned int block = first_block, block1;
-+
-+ printk(KERN_WARNING "INFTL: formatting chain at block %d\n",
-+ first_block);
-+
-+ for (;;) {
-+ block1 = inftl->PUtable[block];
-+
-+ printk(KERN_WARNING "INFTL: formatting block %d\n", block);
-+ if (INFTL_formatblock(inftl, block) < 0) {
-+ /*
-+ * Cannot format !!!! Mark it as Bad Unit,
-+ * FixMe: update the BadUnitTable on disk.
-+ */
-+ inftl->PUtable[block] = BLOCK_RESERVED;
-+ } else {
-+ inftl->PUtable[block] = BLOCK_FREE;
-+ }
-+
-+ /* Goto next block on the chain */
-+ block = block1;
-+
-+ if (block == BLOCK_NIL || block >= inftl->lastEUN)
-+ break;
-+ }
-+}
-+
-+void INFTL_dumptables(struct INFTLrecord *s)
-+{
-+ int i;
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("VUtable[%d] ->", s->nb_blocks);
-+ for (i = 0; i < s->nb_blocks; i++) {
-+ if ((i % 8) == 0)
-+ printk("\n%04x: ", i);
-+ printk("%04x ", s->VUtable[i]);
-+ }
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);
-+ for (i = 0; i <= s->lastEUN; i++) {
-+ if ((i % 8) == 0)
-+ printk("\n%04x: ", i);
-+ printk("%04x ", s->PUtable[i]);
-+ }
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("INFTL ->\n"
-+ " EraseSize = %d\n"
-+ " h/s/c = %d/%d/%d\n"
-+ " numvunits = %d\n"
-+ " firstEUN = %d\n"
-+ " lastEUN = %d\n"
-+ " numfreeEUNs = %d\n"
-+ " LastFreeEUN = %d\n"
-+ " nb_blocks = %d\n"
-+ " nb_boot_blocks = %d",
-+ s->EraseSize, s->heads, s->sectors, s->cylinders,
-+ s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,
-+ s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks);
-+
-+ printk("\n-------------------------------------------"
-+ "----------------------------------\n");
-+}
-+
-+void INFTL_dumpVUchains(struct INFTLrecord *s)
-+{
-+ int logical, block, i;
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+
-+ printk("INFTL Virtual Unit Chains:\n");
-+ for (logical = 0; logical < s->nb_blocks; logical++) {
-+ block = s->VUtable[logical];
-+ if (block > s->nb_blocks)
-+ continue;
-+ printk(" LOGICAL %d --> %d ", logical, block);
-+ for (i = 0; i < s->nb_blocks; i++) {
-+ if (s->PUtable[block] == BLOCK_NIL)
-+ break;
-+ block = s->PUtable[block];
-+ printk("%d ", block);
-+ }
-+ printk("\n");
-+ }
-+
-+ printk("-------------------------------------------"
-+ "----------------------------------\n");
-+}
-+
-+int INFTL_mount(struct INFTLrecord *s)
-+{
-+ unsigned int block, first_block, prev_block, last_block;
-+ unsigned int first_logical_block, logical_block, erase_mark;
-+ int chain_length, do_format_chain;
-+ struct inftl_unithead1 h0;
-+ struct inftl_unittail h1;
-+ int i, retlen;
-+ u8 *ANACtable, ANAC;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s);
-+
-+ /* Search for INFTL MediaHeader and Spare INFTL Media Header */
-+ if (find_boot_record(s) < 0) {
-+ printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
-+ return -1;
-+ }
-+
-+ /* Init the logical to physical table */
-+ for (i = 0; i < s->nb_blocks; i++)
-+ s->VUtable[i] = BLOCK_NIL;
-+
-+ logical_block = block = BLOCK_NIL;
-+
-+ /* Temporary buffer to store ANAC numbers. */
-+ ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
-+ memset(ANACtable, 0, s->nb_blocks);
-+
-+ /*
-+ * First pass is to explore each physical unit, and construct the
-+ * virtual chains that exist (newest physical unit goes into VUtable).
-+ * Any block that is in any way invalid will be left in the
-+ * NOTEXPLORED state. Then at the end we will try to format it and
-+ * mark it as free.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n");
-+ for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {
-+ if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)
-+ continue;
-+
-+ do_format_chain = 0;
-+ first_logical_block = BLOCK_NIL;
-+ last_block = BLOCK_NIL;
-+ block = first_block;
-+
-+ for (chain_length = 0; ; chain_length++) {
-+
-+ if ((chain_length == 0) &&
-+ (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
-+ /* Nothing to do here, onto next block */
-+ break;
-+ }
-+
-+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8,
-+ 8, &retlen, (char *)&h0) < 0 ||
-+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize +
-+ 2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) {
-+ /* Should never happen? */
-+ do_format_chain++;
-+ break;
-+ }
-+
-+ logical_block = le16_to_cpu(h0.virtualUnitNo);
-+ prev_block = le16_to_cpu(h0.prevUnitNo);
-+ erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));
-+ ANACtable[block] = h0.ANAC;
-+
-+ /* Previous block is relative to start of Partition */
-+ if (prev_block < s->nb_blocks)
-+ prev_block += s->firstEUN;
-+
-+ /* Already explored partial chain? */
-+ if (s->PUtable[block] != BLOCK_NOTEXPLORED) {
-+ /* Check if chain for this logical */
-+ if (logical_block == first_logical_block) {
-+ if (last_block != BLOCK_NIL)
-+ s->PUtable[last_block] = block;
-+ }
-+ break;
-+ }
-+
-+ /* Check for invalid block */
-+ if (erase_mark != ERASE_MARK) {
-+ printk(KERN_WARNING "INFTL: corrupt block %d "
-+ "in chain %d, chain length %d, erase "
-+ "mark 0x%x?\n", block, first_block,
-+ chain_length, erase_mark);
-+ /*
-+ * Assume end of chain, probably incomplete
-+ * fold/erase...
-+ */
-+ if (chain_length == 0)
-+ do_format_chain++;
-+ break;
-+ }
-+
-+ /* Check for it being free already then... */
-+ if ((logical_block == BLOCK_FREE) ||
-+ (logical_block == BLOCK_NIL)) {
-+ s->PUtable[block] = BLOCK_FREE;
-+ break;
-+ }
-+
-+ /* Sanity checks on block numbers */
-+ if ((logical_block >= s->nb_blocks) ||
-+ ((prev_block >= s->nb_blocks) &&
-+ (prev_block != BLOCK_NIL))) {
-+ if (chain_length > 0) {
-+ printk(KERN_WARNING "INFTL: corrupt "
-+ "block %d in chain %d?\n",
-+ block, first_block);
-+ do_format_chain++;
-+ }
-+ break;
-+ }
-+
-+ if (first_logical_block == BLOCK_NIL) {
-+ first_logical_block = logical_block;
-+ } else {
-+ if (first_logical_block != logical_block) {
-+ /* Normal for folded chain... */
-+ break;
-+ }
-+ }
-+
-+ /*
-+ * Current block is valid, so if we followed a virtual
-+ * chain to get here then we can set the previous
-+ * block pointer in our PUtable now. Then move onto
-+ * the previous block in the chain.
-+ */
-+ s->PUtable[block] = BLOCK_NIL;
-+ if (last_block != BLOCK_NIL)
-+ s->PUtable[last_block] = block;
-+ last_block = block;
-+ block = prev_block;
-+
-+ /* Check for end of chain */
-+ if (block == BLOCK_NIL)
-+ break;
-+
-+ /* Validate next block before following it... */
-+ if (block > s->lastEUN) {
-+ printk(KERN_WARNING "INFTL: invalid previous "
-+ "block %d in chain %d?\n", block,
-+ first_block);
-+ do_format_chain++;
-+ break;
-+ }
-+ }
-+
-+ if (do_format_chain) {
-+ format_chain(s, first_block);
-+ continue;
-+ }
-+
-+ /*
-+ * Looks like a valid chain then. It may not really be the
-+ * newest block in the chain, but it is the newest we have
-+ * found so far. We might update it in later iterations of
-+ * this loop if we find something newer.
-+ */
-+ s->VUtable[first_logical_block] = first_block;
-+ logical_block = BLOCK_NIL;
-+ }
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumptables(s);
-+#endif
-+
-+ /*
-+ * Second pass, check for infinite loops in chains. These are
-+ * possible because we don't update the previous pointers when
-+ * we fold chains. No big deal, just fix them up in PUtable.
-+ */
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n");
-+ for (logical_block = 0; logical_block < s->numvunits; logical_block++) {
-+ block = s->VUtable[logical_block];
-+ last_block = BLOCK_NIL;
-+
-+ /* Check for free/reserved/nil */
-+ if (block >= BLOCK_RESERVED)
-+ continue;
-+
-+ ANAC = ANACtable[block];
-+ for (i = 0; i < s->numvunits; i++) {
-+ if (s->PUtable[block] == BLOCK_NIL)
-+ break;
-+ if (s->PUtable[block] > s->lastEUN) {
-+ printk(KERN_WARNING "INFTL: invalid prev %d, "
-+ "in virtual chain %d\n",
-+ s->PUtable[block], logical_block);
-+ s->PUtable[block] = BLOCK_NIL;
-+
-+ }
-+ if (ANACtable[block] != ANAC) {
-+ /*
-+ * Chain must point back to itself. This is ok,
-+ * but we will need adjust the tables with this
-+ * newest block and oldest block.
-+ */
-+ s->VUtable[logical_block] = block;
-+ s->PUtable[last_block] = BLOCK_NIL;
-+ break;
-+ }
-+
-+ ANAC--;
-+ last_block = block;
-+ block = s->PUtable[block];
-+ }
-+
-+ if (i >= s->nb_blocks) {
-+ /*
-+ * Uhoo, infinite chain with valid ANACS!
-+ * Format whole chain...
-+ */
-+ format_chain(s, first_block);
-+ }
-+ }
-+
-+#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumptables(s);
-+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+ INFTL_dumpVUchains(s);
-+#endif
-+
-+ /*
-+ * Third pass, format unreferenced blocks and init free block count.
-+ */
-+ s->numfreeEUNs = 0;
-+ s->LastFreeEUN = BLOCK_NIL;
-+
-+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n");
-+ for (block = s->firstEUN; block <= s->lastEUN; block++) {
-+ if (s->PUtable[block] == BLOCK_NOTEXPLORED) {
-+ printk("INFTL: unreferenced block %d, formatting it\n",
-+ block);
-+ if (INFTL_formatblock(s, block) < 0)
-+ s->PUtable[block] = BLOCK_RESERVED;
-+ else
-+ s->PUtable[block] = BLOCK_FREE;
-+ }
-+ if (s->PUtable[block] == BLOCK_FREE) {
-+ s->numfreeEUNs++;
-+ if (s->LastFreeEUN == BLOCK_NIL)
-+ s->LastFreeEUN = block;
-+ }
-+ }
-+
-+ kfree(ANACtable);
-+ return 0;
-+}
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/Config.in linux/drivers/mtd/maps/Config.in
---- linux-mips-2.4.27/drivers/mtd/maps/Config.in 2004-02-26 01:46:35.000000000 +0100
-+++ linux/drivers/mtd/maps/Config.in 2004-11-19 10:25:11.888201464 +0100
-@@ -1,17 +1,14 @@
- # drivers/mtd/maps/Config.in
-
--# $Id$
-+# $Id$
-
- mainmenu_option next_comment
-
- comment 'Mapping drivers for chip access'
-
--dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
--if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
-- hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
-- hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
-- int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
--fi
-+bool ' Support for non-linear mappings of flash chips' CONFIG_MTD_COMPLEX_MAPPINGS
-+
-+bool ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
-
- if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
- dep_tristate ' Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_MTD_CFI
-@@ -21,56 +18,68 @@
- dep_tristate ' CFI Flash device mapped on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
- dep_tristate ' CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI
- dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
-+ dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS
-+ dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT
- if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then
- hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000
- fi
-- dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
-- dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
-- dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
-+ dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS
-+ dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
- dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
- dep_tristate ' ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE
-- dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
-+ dep_tristate ' ROM connected to Intel Hub Controller 2/3/4/5' CONFIG_MTD_ICHXROM $CONFIG_MTD_JEDECPROBE $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS
- dep_tristate ' BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE
- fi
-
--if [ "$CONFIG_PPC" = "y" ]; then
-- dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL
-+if [ "$CONFIG_PPC32" = "y" ]; then
-+ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "y" ]; then
-+ dep_tristate ' Flash device on SBC8240' CONFIG_MTD_SBC8240 $CONFIG_MTD_JEDECPROBE
-+ fi
-+ if [ "$CONFIG_8xx" = "y" ]; then
-+ if [ "$CONFIG_TQM8xxL" = "y" ]; then
-+ dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_RPXLITE" = "y" -o "$CONFIG_RPXCLASSIC" = "y" ]; then
- dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_MBX" = "y" ]; then
- dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_DBOX2" = "y" ]; then
- dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
-+ fi
- dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
-- dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
-+ fi
-+ if [ "$CONFIG_4xx" = "y" ]; then
-+ if [ "$CONFIG_40x" = "y" ]; then
-+ if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then
-+ dep_tristate ' CFI Flash device mapped on IBM Redwood' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
-+ fi
-+ dep_tristate ' CFI Flash device mapped on IBM Beech' CONFIG_MTD_BEECH $CONFIG_MTD_CFI $CONFIG_BEECH
-+ dep_tristate ' CFI Flash device mapped on IBM Arctic' CONFIG_MTD_ARCTIC $CONFIG_MTD_CFI $CONFIG_ARCTIC2
-+ fi
-+ if [ "$CONFIG_440" = "y" ]; then
-+ dep_tristate ' Flash devices mapped on IBM Ebony' CONFIG_MTD_EBONY $CONFIG_MTD_CFI $CONFIG_EBONY
-+ fi
-+ fi
- fi
-
--if [ "$CONFIG_MIPS" = "y" ]; then
-- dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
-- dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
-- dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
-- dep_tristate ' Bosporus MTD support' CONFIG_MTD_BOSPORUS $CONFIG_MIPS_BOSPORUS
-- dep_tristate ' XXS1500 boot flash device' CONFIG_MTD_XXS1500 $CONFIG_MIPS_XXS1500
-- dep_tristate ' MTX-1 flash device' CONFIG_MTD_MTX1 $CONFIG_MIPS_MTX1
-- if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
-- -o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
-- bool ' Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT
-- bool ' Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
-+if [ "$CONFIG_MIPS" = "y" -o "$CONFIG_MIPS64" = "y" ]; then
-+ if [ "$CONFIG_MIPS_PB1000" = "y" -o "$CONFIG_MIPS_PB1100" = "y" -o "$CONFIG_MIPS_PB1500" = "y" ]; then
-+ tristate ' Pb1x00 MTD support' CONFIG_MTD_PB1XXX
-+ if [ "$CONFIG_MIPS_PB1500" = "y" -o "$CONFIG_MIPS_PB1100" = "m" ]; then
-+ bool ' Pb1x00 boot flash device' CONFIG_MTD_PB1500_BOOT
-+ bool ' Pb1x00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
-+ fi
- fi
- tristate ' Db1x00 MTD support' CONFIG_MTD_DB1X00
- if [ "$CONFIG_MTD_DB1X00" = "y" -o "$CONFIG_MTD_DB1X00" = "m" ]; then
- bool ' Db1x00 boot flash device' CONFIG_MTD_DB1X00_BOOT
- bool ' Db1x00 user flash device (2nd bank)' CONFIG_MTD_DB1X00_USER
- fi
-- tristate ' Pb1550 MTD support' CONFIG_MTD_PB1550
-- if [ "$CONFIG_MTD_PB1550" = "y" -o "$CONFIG_MTD_PB1550" = "m" ]; then
-- bool ' Pb1550 Boot Flash' CONFIG_MTD_PB1550_BOOT
-- bool ' Pb1550 User Parameter Flash' CONFIG_MTD_PB1550_USER
-- fi
-- dep_tristate ' Hydrogen 3 MTD support' CONFIG_MTD_HYDROGEN3 $CONFIG_MIPS_HYDROGEN3
-- dep_tristate ' Mirage MTD support' CONFIG_MTD_MIRAGE $CONFIG_MIPS_MIRAGE
- dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS
- if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
- hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000
-@@ -78,7 +87,7 @@
- int ' Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2
- fi
- dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
-- dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT
-+ dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_LASAT
- fi
-
- if [ "$CONFIG_SUPERH" = "y" ]; then
-@@ -90,21 +99,24 @@
- fi
-
- if [ "$CONFIG_ARM" = "y" ]; then
-- dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
- dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
- dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
- dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
-- dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
-+ dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
-+ dep_tristate ' CFI Flash device mapped on the XScale Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK
-+ dep_tristate ' CFI Flash device mapped on XScale IXP425 systems' CONFIG_MTD_IXP425 $CONFIG_MTD_CFI $CONFIG_MTD_COMPLEX_MAPPINGS
- dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
- dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
- dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
- dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
-+ dep_tristate ' CFI Flash device mapped on Hynix evaluation boards' CONFIG_MTD_H720X $CONFIG_MTD_CFI
- dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
- dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA
-+ dep_tristate ' NOR Flash device on TOTO board' CONFIG_MTD_NOR_TOTO $CONFIG_MTD $CONFIG_OMAP_TOTO
- fi
- if [ "$CONFIG_ALPHA" = "y" ]; then
-- dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE
-+ dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE $CONFIG_MTD_COMPLEX_MAPPINGS
- fi
-
- if [ "$CONFIG_UCLINUX" = "y" ]; then
-@@ -112,7 +124,7 @@
- fi
-
- # This needs CFI or JEDEC, depending on the cards found.
--dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
--dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
-+dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI $CONFIG_MTD_COMPLEX_MAPPINGS
-+dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA $CONFIG_MTD_COMPLEX_MAPPINGS
-
- endmenu
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/Makefile linux/drivers/mtd/maps/Makefile
---- linux-mips-2.4.27/drivers/mtd/maps/Makefile 2004-02-26 01:46:35.000000000 +0100
-+++ linux/drivers/mtd/maps/Makefile 2004-11-19 10:25:11.890201160 +0100
-@@ -1,12 +1,16 @@
- #
- # linux/drivers/maps/Makefile
- #
--# $Id$
-+# $Id$
-
--BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
--
--ifeq ($(BELOW25),y)
-+ifeq ($(PATCHLEVEL),4)
- O_TARGET := mapslink.o
-+export-objs := map_funcs.o
-+endif
-+
-+
-+ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
-+obj-$(CONFIG_MTD) += map_funcs.o
- endif
-
- # Chip mappings
-@@ -21,19 +25,13 @@
- obj-$(CONFIG_MTD_IQ80310) += iq80310.o
- obj-$(CONFIG_MTD_L440GX) += l440gx.o
- obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
--obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o
-+obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
- obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
-+obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
- obj-$(CONFIG_MTD_MBX860) += mbx860.o
--obj-$(CONFIG_MTD_NORA) += nora.o
- obj-$(CONFIG_MTD_CEIVA) += ceiva.o
- obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
--ifneq ($(CONFIG_MTD_PHYSMAP),n)
-- ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
-- obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o
-- else
-- obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
-- endif
--endif
-+obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
- obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
- obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
- obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
-@@ -49,16 +47,9 @@
- obj-$(CONFIG_MTD_OCELOT) += ocelot.o
- obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
- obj-$(CONFIG_MTD_PCI) += pci.o
--obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o
--obj-$(CONFIG_MTD_XXS1500) += xxs1500.o
--obj-$(CONFIG_MTD_MTX1) += mtx-1.o
--obj-$(CONFIG_MTD_LASAT) += lasat.o
-+obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o
- obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
--obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o
--obj-$(CONFIG_MTD_HYDROGEN3) += hydrogen3-flash.o
--obj-$(CONFIG_MTD_BOSPORUS) += pb1xxx-flash.o
-+obj-$(CONFIG_MTD_LASAT) += lasat.o
- obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
- obj-$(CONFIG_MTD_EDB7312) += edb7312.o
- obj-$(CONFIG_MTD_IMPA7) += impa7.o
-@@ -67,6 +58,13 @@
- obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
- obj-$(CONFIG_MTD_NETtel) += nettel.o
- obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
--obj-$(CONFIG_MTD_MIRAGE) += mirage-flash.o
-+obj-$(CONFIG_MTD_EBONY) += ebony.o
-+obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
-+obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
-+obj-$(CONFIG_MTD_H720X) += h720x-flash.o
-+obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
-+obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
-+obj-$(CONFIG_MTD_MPC1211) += mpc1211.o
-+obj-$(CONFIG_MTD_IXP425) += ixp425.o
-
--include $(TOPDIR)/Rules.make
-+-include $(TOPDIR)/Rules.make
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/amd76xrom.c linux/drivers/mtd/maps/amd76xrom.c
---- linux-mips-2.4.27/drivers/mtd/maps/amd76xrom.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/amd76xrom.c 2004-11-19 10:25:11.891201008 +0100
-@@ -2,12 +2,13 @@
- * amd76xrom.c
- *
- * Normal mappings of chips in physical memory
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -16,77 +17,59 @@
- #include <linux/pci_ids.h>
-
-
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define MTD_DEV_NAME_LENGTH 16
-+
- struct amd76xrom_map_info {
- struct map_info map;
- struct mtd_info *mtd;
- unsigned long window_addr;
- u32 window_start, window_size;
- struct pci_dev *pdev;
-+ struct resource window_rsrc;
-+ struct resource rom_rsrc;
-+ char mtd_name[MTD_DEV_NAME_LENGTH];
- };
-
--static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
-
--static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
-+static struct amd76xrom_map_info amd76xrom_map = {
-+ .map = {
-+ .name = MOD_NAME,
-+ .size = 0,
-+ .buswidth = 1,
-+ }
-+ /* remaining fields of structure are initialized to 0 */
-+};
-
--static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-
--static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr)
-+static void amd76xrom_cleanup(struct amd76xrom_map_info *info)
- {
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
-+ u8 byte;
-
--static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
-+ /* Disable writes through the rom window */
-+ pci_read_config_byte(info->pdev, 0x40, &byte);
-+ pci_write_config_byte(info->pdev, 0x40, byte & ~1);
-
--static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+ if (info->mtd) {
-+ del_mtd_device(info->mtd);
-+ map_destroy(info->mtd);
-+ info->mtd = NULL;
-+ info->map.virt = 0;
-+ }
-+ if (info->rom_rsrc.parent)
-+ release_resource(&info->rom_rsrc);
-+ if (info->window_rsrc.parent)
-+ release_resource(&info->window_rsrc);
-
--static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
-+ if (info->window_addr) {
-+ iounmap((void *)(info->window_addr));
-+ info->window_addr = 0;
-+ }
- }
-
--static struct amd76xrom_map_info amd76xrom_map = {
-- map: {
-- name: "AMD76X rom",
-- size: 0,
-- buswidth: 1,
-- read8: amd76xrom_read8,
-- read16: amd76xrom_read16,
-- read32: amd76xrom_read32,
-- copy_from: amd76xrom_copy_from,
-- write8: amd76xrom_write8,
-- write16: amd76xrom_write16,
-- write32: amd76xrom_write32,
-- copy_to: amd76xrom_copy_to,
-- /* The standard rom socket is for single power supply chips
-- * that don't have an extra vpp.
-- */
-- },
-- mtd: 0,
-- window_addr: 0,
--};
-
- static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
-@@ -97,6 +80,10 @@
- u8 segen_bits;
- };
- static struct rom_window rom_window[] = {
-+ /*
-+ * Need the 5MiB window for chips that have block lock/unlock
-+ * registers located below 4MiB window.
-+ */
- { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
- { 0xffc00000, 4*1024*1024, (1<<7), },
- { 0xffff0000, 64*1024, 0 },
-@@ -112,19 +99,29 @@
- int i;
- u32 rom_size;
-
-+ info->pdev = pdev;
- window = &rom_window[0];
--#if 0
-- while(window->size) {
-- if (request_mem_region(window->start, window->size, "amd76xrom")) {
-- break;
-- }
-- window++;
-- }
-- if (!window->size) {
-- printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
-- goto err_out_none;
-+
-+ while (window->size) {
-+ /*
-+ * Try to reserve the window mem region. If this fails then
-+ * it is likely due to a fragment of the window being
-+ * "reseved" by the BIOS. In the case that the
-+ * request_mem_region() fails then once the rom size is
-+ * discovered we will try to reserve the unreserved fragment.
-+ */
-+ info->window_rsrc.name = MOD_NAME;
-+ info->window_rsrc.start = window->start;
-+ info->window_rsrc.end = window->start + window->size - 1;
-+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&iomem_resource, &info->window_rsrc)) {
-+ info->window_rsrc.parent = NULL;
-+ printk(KERN_ERR MOD_NAME
-+ " %s(): Unable to register resource"
-+ " 0x%.08lx-0x%.08lx - kernel bug?\n",
-+ __func__,
-+ info->window_rsrc.start, info->window_rsrc.end);
- }
--#endif
-
- /* Enable the selected rom window */
- pci_read_config_byte(pdev, 0x43, &byte);
-@@ -136,49 +133,94 @@
-
- /* FIXME handle registers 0x80 - 0x8C the bios region locks */
-
-- printk(KERN_NOTICE "amd76xrom window : %x at %x\n",
-+ printk(KERN_NOTICE MOD_NAME " window : %x at %x\n",
- window->size, window->start);
- /* For write accesses caches are useless */
-- info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
-+ info->window_addr =
-+ (unsigned long)ioremap_nocache(window->start,
-+ window->size);
-
- if (!info->window_addr) {
- printk(KERN_ERR "Failed to ioremap\n");
-- goto err_out_free_mmio_region;
-+ continue;
- }
-- info->mtd = 0;
-+
-+ info->mtd = NULL;
-+
- for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
- char **chip_type;
- if (rom_size > window->size) {
- continue;
- }
-- info->map.map_priv_1 =
-+ info->map.phys = window->start + window->size - rom_size;
-+ info->map.virt =
- info->window_addr + window->size - rom_size;
- info->map.size = rom_size;
-+ simple_map_init(&info->map);
- chip_type = rom_probe_types;
- for(; !info->mtd && *chip_type; chip_type++) {
- info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
- }
-- if (info->mtd) {
-- break;
-- }
-+ if (info->mtd) goto found_mtd;
- }
-- if (!info->mtd) {
-- goto err_out_iounmap;
-+ iounmap((void *)(info->window_addr));
-+ info->window_addr = 0;
-+
-+ /* Disable writes through the rom window */
-+ pci_read_config_byte(pdev, 0x40, &byte);
-+ pci_write_config_byte(pdev, 0x40, byte & ~1);
-+
-+ window++;
- }
-- printk(KERN_NOTICE "amd76xrom chip at offset: %x\n",
-+ goto failed;
-+
-+ found_mtd:
-+ printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n",
- window->size - rom_size);
-
-- info->mtd->module = THIS_MODULE;
-+ info->mtd->owner = THIS_MODULE;
-+
-+ if (!info->window_rsrc.parent) {
-+ /* failed to reserve entire window - try fragments */
-+ info->window_rsrc.name = MOD_NAME;
-+ info->window_rsrc.start = window->start;
-+ info->window_rsrc.end = window->start + window->size - rom_size - 1;
-+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&iomem_resource, &info->window_rsrc)) {
-+ printk(KERN_ERR MOD_NAME
-+ ": cannot reserve window resource fragment\n");
-+ goto failed;
-+ }
-+ }
-+
- add_mtd_device(info->mtd);
- info->window_start = window->start;
- info->window_size = window->size;
-+
-+ if (info->window_rsrc.parent) {
-+ /*
-+ * Registering the MTD device in iomem may not be possible
-+ * if there is a BIOS "reserved" and BUSY range. If this
-+ * fails then continue anyway.
-+ */
-+ snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
-+ "mtd%d", info->mtd->index);
-+
-+ info->rom_rsrc.name = info->mtd_name;
-+ info->rom_rsrc.start = window->start + window->size - rom_size;
-+ info->rom_rsrc.end = window->start + window->size - 1;
-+ info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
-+ printk(KERN_ERR MOD_NAME
-+ ": cannot reserve MTD resource\n");
-+ info->rom_rsrc.parent = NULL;
-+ }
-+ }
-+
- return 0;
-
--err_out_iounmap:
-- iounmap((void *)(info->window_addr));
--err_out_free_mmio_region:
-- release_mem_region(window->start, window->size);
--err_out_none:
-+ failed:
-+ amd76xrom_cleanup(info);
- return -ENODEV;
- }
-
-@@ -186,21 +228,8 @@
- static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
- {
- struct amd76xrom_map_info *info = &amd76xrom_map;
-- u8 byte;
--
-- del_mtd_device(info->mtd);
-- map_destroy(info->mtd);
-- info->mtd = 0;
-- info->map.map_priv_1 = 0;
--
-- iounmap((void *)(info->window_addr));
-- info->window_addr = 0;
--
-- /* Disable writes through the rom window */
-- pci_read_config_byte(pdev, 0x40, &byte);
-- pci_write_config_byte(pdev, 0x40, byte & ~1);
-
-- release_mem_region(info->window_start, info->window_size);
-+ amd76xrom_cleanup(info);
- }
-
- static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
-@@ -208,6 +237,7 @@
- PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
- PCI_ANY_ID, PCI_ANY_ID, },
-+ { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
- { 0, }
- };
-
-@@ -215,10 +245,10 @@
-
- #if 0
- static struct pci_driver amd76xrom_driver = {
-- name: "amd76xrom",
-- id_table: amd76xrom_pci_tbl,
-- probe: amd76xrom_init_one,
-- remove: amd76xrom_remove_one,
-+ .name = MOD_NAME,
-+ .id_table = amd76xrom_pci_tbl,
-+ .probe = amd76xrom_init_one,
-+ .remove = amd76xrom_remove_one,
- };
- #endif
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/arctic-mtd.c linux/drivers/mtd/maps/arctic-mtd.c
---- linux-mips-2.4.27/drivers/mtd/maps/arctic-mtd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/arctic-mtd.c 2004-11-19 10:25:11.893200704 +0100
-@@ -0,0 +1,135 @@
-+/*
-+ * $Id$
-+ *
-+ * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
-+ * IBM 405LP Arctic boards.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Copyright (C) 2002, International Business Machines Corporation
-+ * All Rights Reserved.
-+ *
-+ * Bishop Brock
-+ * IBM Research, Austin Center for Low-Power Computing
-+ * bcbrock@us.ibm.com
-+ * March 2002
-+ *
-+ * modified for Arctic by,
-+ * David Gibson
-+ * IBM OzLabs, Canberra, Australia
-+ * <arctic@gibson.dropbear.id.au>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/ibm4xx.h>
-+
-+/*
-+ * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
-+ * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
-+ * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
-+ * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
-+ */
-+
-+#define FFS1_SIZE 0x01000000 /* 16MiB */
-+#define KERNEL_SIZE 0x00500000 /* 5.12MiB */
-+#define FFS2_SIZE 0x00a60000 /* 10.624MiB */
-+#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */
-+
-+
-+#define NAME "Arctic Linux Flash"
-+#define PADDR SUBZERO_BOOTFLASH_PADDR
-+#define BUSWIDTH 2
-+#define SIZE SUBZERO_BOOTFLASH_SIZE
-+#define PARTITIONS 4
-+
-+/* Flash memories on these boards are memory resources, accessed big-endian. */
-+
-+{
-+ /* do nothing for now */
-+}
-+
-+static struct map_info arctic_mtd_map = {
-+ .name = NAME,
-+ .size = SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = PADDR,
-+};
-+
-+static struct mtd_info *arctic_mtd;
-+
-+static struct mtd_partition arctic_partitions[PARTITIONS] = {
-+ { .name = "Filesystem",
-+ .size = FFS1_SIZE,
-+ .offset = 0,},
-+ { .name = "Kernel",
-+ .size = KERNEL_SIZE,
-+ .offset = FFS1_SIZE,},
-+ { .name = "Filesystem",
-+ .size = FFS2_SIZE,
-+ .offset = FFS1_SIZE + KERNEL_SIZE,},
-+ { .name = "Firmware",
-+ .size = FIRMWARE_SIZE,
-+ .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-+};
-+
-+static int __init
-+init_arctic_mtd(void)
-+{
-+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-+
-+ arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
-+
-+ if (!arctic_mtd_map.virt) {
-+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-+ return -EIO;
-+ }
-+ simple_map_init(&arctic_mtd_map);
-+
-+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-+ arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-+
-+ if (!arctic_mtd)
-+ return -ENXIO;
-+
-+ arctic_mtd->owner = THIS_MODULE;
-+
-+ return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
-+}
-+
-+static void __exit
-+cleanup_arctic_mtd(void)
-+{
-+ if (arctic_mtd) {
-+ del_mtd_partitions(arctic_mtd);
-+ map_destroy(arctic_mtd);
-+ iounmap((void *) arctic_mtd_map.virt);
-+ }
-+}
-+
-+module_init(init_arctic_mtd);
-+module_exit(cleanup_arctic_mtd);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/autcpu12-nvram.c linux/drivers/mtd/maps/autcpu12-nvram.c
---- linux-mips-2.4.27/drivers/mtd/maps/autcpu12-nvram.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/autcpu12-nvram.c 2004-11-19 10:25:11.894200552 +0100
-@@ -2,7 +2,7 @@
- * NV-RAM memory access on autcpu12
- * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -24,6 +24,7 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/ioport.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/sizes.h>
- #include <asm/hardware.h>
-@@ -32,80 +33,27 @@
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-
--__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-- from++;
-- to++;
-- len--;
-- }
--}
-
- static struct mtd_info *sram_mtd;
-
- struct map_info autcpu12_sram_map = {
-- name: "SRAM",
-- size: 32768,
-- buswidth: 8,
-- read8: autcpu12_read8,
-- read16: autcpu12_read16,
-- read32: autcpu12_read32,
-- copy_from: autcpu12_copy_from,
-- write8: autcpu12_write8,
-- write16: autcpu12_write16,
-- write32: autcpu12_write32,
-- copy_to: autcpu12_copy_to
-+ .name = "SRAM",
-+ .size = 32768,
-+ .buswidth = 4,
-+ .phys = 0x12000000,
- };
-
- static int __init init_autcpu12_sram (void)
- {
- int err, save0, save1;
-
-- autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
-- if (!autcpu12_sram_map.map_priv_1) {
-+ autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K);
-+ if (!autcpu12_sram_map.virt) {
- printk("Failed to ioremap autcpu12 NV-RAM space\n");
- err = -EIO;
- goto out;
- }
-+ simple_map_init(&autcpu_sram_map);
-
- /*
- * Check for 32K/128K
-@@ -115,20 +63,20 @@
- * Read and check result on ofs 0x0
- * Restore contents
- */
-- save0 = autcpu12_read32(&autcpu12_sram_map,0);
-- save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
-- autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
-+ save0 = map_read32(&autcpu12_sram_map,0);
-+ save1 = map_read32(&autcpu12_sram_map,0x10000);
-+ map_write32(&autcpu12_sram_map,~save0,0x10000);
- /* if we find this pattern on 0x0, we have 32K size
- * restore contents and exit
- */
-- if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
-- autcpu12_write32(&autcpu12_sram_map,save0,0x0);
-+ if ( map_read32(&autcpu12_sram_map,0) != save0) {
-+ map_write32(&autcpu12_sram_map,save0,0x0);
- goto map;
- }
- /* We have a 128K found, restore 0x10000 and set size
- * to 128K
- */
-- autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
-+ ma[_write32(&autcpu12_sram_map,save1,0x10000);
- autcpu12_sram_map.size = SZ_128K;
-
- map:
-@@ -139,7 +87,7 @@
- goto out_ioremap;
- }
-
-- sram_mtd->module = THIS_MODULE;
-+ sram_mtd->owner = THIS_MODULE;
- sram_mtd->erasesize = 16;
-
- if (add_mtd_device(sram_mtd)) {
-@@ -148,7 +96,7 @@
- goto out_probe;
- }
-
-- printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-+ printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-
- return 0;
-
-@@ -157,7 +105,7 @@
- sram_mtd = 0;
-
- out_ioremap:
-- iounmap((void *)autcpu12_sram_map.map_priv_1);
-+ iounmap((void *)autcpu12_sram_map.virt);
- out:
- return err;
- }
-@@ -167,7 +115,7 @@
- if (sram_mtd) {
- del_mtd_device(sram_mtd);
- map_destroy(sram_mtd);
-- iounmap((void *)autcpu12_sram_map.map_priv_1);
-+ iounmap((void *)autcpu12_sram_map.virt);
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/beech-mtd.c linux/drivers/mtd/maps/beech-mtd.c
---- linux-mips-2.4.27/drivers/mtd/maps/beech-mtd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/beech-mtd.c 2004-11-19 10:25:11.895200400 +0100
-@@ -0,0 +1,112 @@
-+/*
-+ * $Id$
-+ *
-+ * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
-+ * IBM 405LP Beech boards.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Copyright (C) 2002, International Business Machines Corporation
-+ * All Rights Reserved.
-+ *
-+ * Bishop Brock
-+ * IBM Research, Austin Center for Low-Power Computing
-+ * bcbrock@us.ibm.com
-+ * March 2002
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/ibm4xx.h>
-+
-+#define NAME "Beech Linux Flash"
-+#define PADDR BEECH_BIGFLASH_PADDR
-+#define SIZE BEECH_BIGFLASH_SIZE
-+#define BUSWIDTH 1
-+
-+/* Flash memories on these boards are memory resources, accessed big-endian. */
-+
-+
-+static struct map_info beech_mtd_map = {
-+ .name = NAME,
-+ .size = SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = PADDR
-+};
-+
-+static struct mtd_info *beech_mtd;
-+
-+static struct mtd_partition beech_partitions[2] = {
-+ {
-+ .name = "Linux Kernel",
-+ .size = BEECH_KERNEL_SIZE,
-+ .offset = BEECH_KERNEL_OFFSET
-+ }, {
-+ .name = "Free Area",
-+ .size = BEECH_FREE_AREA_SIZE,
-+ .offset = BEECH_FREE_AREA_OFFSET
-+ }
-+};
-+
-+static int __init
-+init_beech_mtd(void)
-+{
-+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-+
-+ beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
-+
-+ if (!beech_mtd_map.virt) {
-+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&beech_mtd_map);
-+
-+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-+ beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-+
-+ if (!beech_mtd)
-+ return -ENXIO;
-+
-+ beech_mtd->owner = THIS_MODULE;
-+
-+ return add_mtd_partitions(beech_mtd, beech_partitions, 2);
-+}
-+
-+static void __exit
-+cleanup_beech_mtd(void)
-+{
-+ if (beech_mtd) {
-+ del_mtd_partitions(beech_mtd);
-+ map_destroy(beech_mtd);
-+ iounmap((void *) beech_mtd_map.virt);
-+ }
-+}
-+
-+module_init(init_beech_mtd);
-+module_exit(cleanup_beech_mtd);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cdb89712.c linux/drivers/mtd/maps/cdb89712.c
---- linux-mips-2.4.27/drivers/mtd/maps/cdb89712.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/cdb89712.c 2004-11-19 10:25:11.897200096 +0100
-@@ -1,13 +1,14 @@
- /*
- * Flash on Cirrus CDB89712
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/ioport.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/arch/hardware.h>
- #include <linux/mtd/mtd.h>
-@@ -16,77 +17,21 @@
-
-
-
--__u8 cdb89712_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 cdb89712_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 cdb89712_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- // printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to);
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-- from++;
-- to++;
-- len--;
-- }
--}
--
-
- static struct mtd_info *flash_mtd;
-
- struct map_info cdb89712_flash_map = {
-- name: "flash",
-- size: FLASH_SIZE,
-- buswidth: FLASH_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-- write8: cdb89712_write8,
-- write16: cdb89712_write16,
-- write32: cdb89712_write32,
-- copy_to: cdb89712_copy_to
-+ .name = "flash",
-+ .size = FLASH_SIZE,
-+ .buswidth = FLASH_WIDTH,
-+ .phys = FLASH_START,
- };
-
- struct resource cdb89712_flash_resource = {
-- name: "Flash",
-- start: FLASH_START,
-- end: FLASH_START + FLASH_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "Flash",
-+ .start = FLASH_START,
-+ .end = FLASH_START + FLASH_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_flash (void)
-@@ -99,13 +44,13 @@
- goto out;
- }
-
-- cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-- if (!cdb89712_flash_map.map_priv_1) {
-+ cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-+ if (!cdb89712_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_flash_map);
- flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map);
- if (!flash_mtd) {
- flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map);
-@@ -118,7 +63,7 @@
- goto out_ioremap;
- }
-
-- flash_mtd->module = THIS_MODULE;
-+ flash_mtd->owner = THIS_MODULE;
-
- if (add_mtd_device(flash_mtd)) {
- printk("FLASH device addition failed\n");
-@@ -132,7 +77,7 @@
- map_destroy(flash_mtd);
- flash_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_flash_map.map_priv_1);
-+ iounmap((void *)cdb89712_flash_map.virt);
- out_resource:
- release_resource (&cdb89712_flash_resource);
- out:
-@@ -146,24 +91,17 @@
- static struct mtd_info *sram_mtd;
-
- struct map_info cdb89712_sram_map = {
-- name: "SRAM",
-- size: SRAM_SIZE,
-- buswidth: SRAM_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-- write8: cdb89712_write8,
-- write16: cdb89712_write16,
-- write32: cdb89712_write32,
-- copy_to: cdb89712_copy_to
-+ .name = "SRAM",
-+ .size = SRAM_SIZE,
-+ .buswidth = SRAM_WIDTH,
-+ .phys = SRAM_START,
- };
-
- struct resource cdb89712_sram_resource = {
-- name: "SRAM",
-- start: SRAM_START,
-- end: SRAM_START + SRAM_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "SRAM",
-+ .start = SRAM_START,
-+ .end = SRAM_START + SRAM_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_sram (void)
-@@ -176,13 +114,13 @@
- goto out;
- }
-
-- cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
-- if (!cdb89712_sram_map.map_priv_1) {
-+ cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
-+ if (!cdb89712_sram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_sram_map);
- sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map);
- if (!sram_mtd) {
- printk("SRAM probe failed\n");
-@@ -190,7 +128,7 @@
- goto out_ioremap;
- }
-
-- sram_mtd->module = THIS_MODULE;
-+ sram_mtd->owner = THIS_MODULE;
- sram_mtd->erasesize = 16;
-
- if (add_mtd_device(sram_mtd)) {
-@@ -205,7 +143,7 @@
- map_destroy(sram_mtd);
- sram_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_sram_map.map_priv_1);
-+ iounmap((void *)cdb89712_sram_map.virt);
- out_resource:
- release_resource (&cdb89712_sram_resource);
- out:
-@@ -221,20 +159,17 @@
- static struct mtd_info *bootrom_mtd;
-
- struct map_info cdb89712_bootrom_map = {
-- name: "BootROM",
-- size: BOOTROM_SIZE,
-- buswidth: BOOTROM_WIDTH,
-- read8: cdb89712_read8,
-- read16: cdb89712_read16,
-- read32: cdb89712_read32,
-- copy_from: cdb89712_copy_from,
-+ .name = "BootROM",
-+ .size = BOOTROM_SIZE,
-+ .buswidth = BOOTROM_WIDTH,
-+ .phys = BOOTROM_START,
- };
-
- struct resource cdb89712_bootrom_resource = {
-- name: "BootROM",
-- start: BOOTROM_START,
-- end: BOOTROM_START + BOOTROM_SIZE - 1,
-- flags: IORESOURCE_IO | IORESOURCE_BUSY,
-+ .name = "BootROM",
-+ .start = BOOTROM_START,
-+ .end = BOOTROM_START + BOOTROM_SIZE - 1,
-+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
- };
-
- static int __init init_cdb89712_bootrom (void)
-@@ -247,13 +182,13 @@
- goto out;
- }
-
-- cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
-- if (!cdb89712_bootrom_map.map_priv_1) {
-+ cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
-+ if (!cdb89712_bootrom_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
- err = -EIO;
- goto out_resource;
- }
--
-+ simple_map_init(&cdb89712_bootrom_map);
- bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map);
- if (!bootrom_mtd) {
- printk("BootROM probe failed\n");
-@@ -261,7 +196,7 @@
- goto out_ioremap;
- }
-
-- bootrom_mtd->module = THIS_MODULE;
-+ bootrom_mtd->owner = THIS_MODULE;
- bootrom_mtd->erasesize = 0x10000;
-
- if (add_mtd_device(bootrom_mtd)) {
-@@ -276,7 +211,7 @@
- map_destroy(bootrom_mtd);
- bootrom_mtd = 0;
- out_ioremap:
-- iounmap((void *)cdb89712_bootrom_map.map_priv_1);
-+ iounmap((void *)cdb89712_bootrom_map.virt);
- out_resource:
- release_resource (&cdb89712_bootrom_resource);
- out:
-@@ -306,21 +241,21 @@
- if (sram_mtd) {
- del_mtd_device(sram_mtd);
- map_destroy(sram_mtd);
-- iounmap((void *)cdb89712_sram_map.map_priv_1);
-+ iounmap((void *)cdb89712_sram_map.virt);
- release_resource (&cdb89712_sram_resource);
- }
-
- if (flash_mtd) {
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
-- iounmap((void *)cdb89712_flash_map.map_priv_1);
-+ iounmap((void *)cdb89712_flash_map.virt);
- release_resource (&cdb89712_flash_resource);
- }
-
- if (bootrom_mtd) {
- del_mtd_device(bootrom_mtd);
- map_destroy(bootrom_mtd);
-- iounmap((void *)cdb89712_bootrom_map.map_priv_1);
-+ iounmap((void *)cdb89712_bootrom_map.virt);
- release_resource (&cdb89712_bootrom_resource);
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ceiva.c linux/drivers/mtd/maps/ceiva.c
---- linux-mips-2.4.27/drivers/mtd/maps/ceiva.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/ceiva.c 2004-11-19 10:25:11.898199944 +0100
-@@ -11,7 +11,7 @@
- *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -19,6 +19,7 @@
- #include <linux/types.h>
- #include <linux/ioport.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -31,62 +32,10 @@
- #include <asm/sizes.h>
-
- /*
-- * This isnt complete yet, so...
-+ * This isn't complete yet, so...
- */
- #define CONFIG_MTD_CEIVA_STATICMAP
-
--static __u8 clps_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 clps_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 clps_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
--static struct map_info clps_map __initdata = {
-- name: "clps flash",
-- read8: clps_read8,
-- read16: clps_read16,
-- read32: clps_read32,
-- copy_from: clps_copy_from,
-- write8: clps_write8,
-- write16: clps_write16,
-- write32: clps_write32,
-- copy_to: clps_copy_to,
--};
--
- #ifdef CONFIG_MTD_CEIVA_STATICMAP
- /*
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
-@@ -176,7 +125,7 @@
- maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
- if (!maps)
- return -ENOMEM;
--
-+ memset(maps, 0, sizeof(struct map_info) * nr);
- /*
- * Claim and then map the memory regions.
- */
-@@ -191,7 +140,9 @@
- }
-
- clps[i].map = maps + i;
-- memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
-+
-+ clps[i].map->name = "clps flash";
-+ clps[i].map->phys = clps[i].base;
-
- clps[i].vbase = ioremap(clps[i].base, clps[i].size);
- if (!clps[i].vbase) {
-@@ -199,16 +150,18 @@
- break;
- }
-
-- clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
-+ clps[i].map->virt = (unsigned long)clps[i].vbase;
- clps[i].map->buswidth = clps[i].width;
- clps[i].map->size = clps[i].size;
-
-+ simple_map_init(&clps[i].map);
-+
- clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
- if (clps[i].mtd == NULL) {
- ret = -ENXIO;
- break;
- }
-- clps[i].mtd->module = THIS_MODULE;
-+ clps[i].mtd->owner = THIS_MODULE;
- subdev[i] = clps[i].mtd;
-
- printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
-@@ -318,10 +271,8 @@
- return nr;
- }
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
--
- static struct mtd_partition *parsed_parts;
-+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
-
- static void __init clps_locate_partitions(struct mtd_info *mtd)
- {
-@@ -331,20 +282,11 @@
- /*
- * Partition selection stuff.
- */
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
-+ nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
- if (nr_parts > 0) {
- part_type = "command line";
- break;
- }
--#endif
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
-- if (nr_parts > 0) {
-- part_type = "RedBoot";
-- break;
-- }
--#endif
- #ifdef CONFIG_MTD_CEIVA_STATICMAP
- nr_parts = clps_static_partitions(&parsed_parts);
- if (nr_parts > 0) {
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cfi_flagadm.c linux/drivers/mtd/maps/cfi_flagadm.c
---- linux-mips-2.4.27/drivers/mtd/maps/cfi_flagadm.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/cfi_flagadm.c 2004-11-19 10:25:11.900199640 +0100
-@@ -1,7 +1,7 @@
- /*
- * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
-@@ -27,6 +27,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -55,83 +56,33 @@
- #define FLASH_PARTITION3_ADDR 0x00240000
- #define FLASH_PARTITION3_SIZE 0x001C0000
-
--__u8 flagadm_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 flagadm_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 flagadm_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void flagadm_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info flagadm_map = {
-- name: "FlagaDM flash device",
-- size: FLASH_SIZE,
-- buswidth: 2,
-- read8: flagadm_read8,
-- read16: flagadm_read16,
-- read32: flagadm_read32,
-- copy_from: flagadm_copy_from,
-- write8: flagadm_write8,
-- write16: flagadm_write16,
-- write32: flagadm_write32,
-- copy_to: flagadm_copy_to
-+ .name = "FlagaDM flash device",
-+ .size = FLASH_SIZE,
-+ .buswidth = 2,
- };
-
- struct mtd_partition flagadm_parts[] = {
- {
-- name : "Bootloader",
-- offset : FLASH_PARTITION0_ADDR,
-- size : FLASH_PARTITION0_SIZE
-+ .name = "Bootloader",
-+ .offset = FLASH_PARTITION0_ADDR,
-+ .size = FLASH_PARTITION0_SIZE
- },
- {
-- name : "Kernel image",
-- offset : FLASH_PARTITION1_ADDR,
-- size : FLASH_PARTITION1_SIZE
-+ .name = "Kernel image",
-+ .offset = FLASH_PARTITION1_ADDR,
-+ .size = FLASH_PARTITION1_SIZE
- },
- {
-- name : "Initial ramdisk image",
-- offset : FLASH_PARTITION2_ADDR,
-- size : FLASH_PARTITION2_SIZE
-+ .name = "Initial ramdisk image",
-+ .offset = FLASH_PARTITION2_ADDR,
-+ .size = FLASH_PARTITION2_SIZE
- },
- {
-- name : "Persistant storage",
-- offset : FLASH_PARTITION3_ADDR,
-- size : FLASH_PARTITION3_SIZE
-+ .name = "Persistant storage",
-+ .offset = FLASH_PARTITION3_ADDR,
-+ .size = FLASH_PARTITION3_SIZE
- }
- };
-
-@@ -144,22 +95,26 @@
- printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
- FLASH_SIZE, FLASH_PHYS_ADDR);
-
-- flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR,
-+ flagadm_map.phys = FLASH_PHYS_ADDR;
-+ flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR,
- FLASH_SIZE);
-
-- if (!flagadm_map.map_priv_1) {
-+ if (!flagadm_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+
-+ simple_map_init(&flagadm_map);
-+
- mymtd = do_map_probe("cfi_probe", &flagadm_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT);
- printk(KERN_NOTICE "FlagaDM flash device initialized\n");
- return 0;
- }
-
-- iounmap((void *)flagadm_map.map_priv_1);
-+ iounmap((void *)flagadm_map.virt);
- return -ENXIO;
- }
-
-@@ -169,9 +124,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (flagadm_map.map_priv_1) {
-- iounmap((void *)flagadm_map.map_priv_1);
-- flagadm_map.map_priv_1 = 0;
-+ if (flagadm_map.virt) {
-+ iounmap((void *)flagadm_map.virt);
-+ flagadm_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cstm_mips_ixx.c linux/drivers/mtd/maps/cstm_mips_ixx.c
---- linux-mips-2.4.27/drivers/mtd/maps/cstm_mips_ixx.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/cstm_mips_ixx.c 2004-11-19 10:25:11.901199488 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
- * Config with both CFI and JEDEC device support.
-@@ -33,55 +33,13 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
- #include <linux/config.h>
--
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- #include <linux/delay.h>
--#endif
--
--__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- #define CC_GCR 0xB4013818
-@@ -97,10 +55,17 @@
- #define CC_GPAICR 0xB4013804
- #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
- {
-+ static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED;
-+ static int vpp_count = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&vpp_lock, flags);
-+
- if (vpp) {
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ if (!vpp_count++) {
- __u16 data;
- __u8 data1;
- static u8 first = 1;
-@@ -116,10 +81,9 @@
- enabling vpp after powerup */
- udelay(40);
- }
--#endif /* CONFIG_MIPS_ITE8172 */
- }
-- else {
--#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ } else {
-+ if (!--vpp_count) {
- __u16 data;
-
- // Set GPIO port B pin3 to high
-@@ -127,26 +91,11 @@
- data = (data & 0xff3f) | 0x0040;
- *(__u16 *)CC_GPBCR = data;
- *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
--#endif /* CONFIG_MIPS_ITE8172 */
- }
-+ }
-+ spin_unlock_irqrestore(&vpp_lock, flags);
- }
--
--const struct map_info basic_cstm_mips_ixx_map = {
-- NULL,
-- 0,
-- 0,
-- cstm_mips_ixx_read8,
-- cstm_mips_ixx_read16,
-- cstm_mips_ixx_read32,
-- cstm_mips_ixx_copy_from,
-- cstm_mips_ixx_write8,
-- cstm_mips_ixx_write16,
-- cstm_mips_ixx_write32,
-- cstm_mips_ixx_copy_to,
-- cstm_mips_ixx_set_vpp,
-- 0,
-- 0
--};
-+#endif
-
- /* board and partition description */
-
-@@ -175,9 +124,9 @@
- static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
- { // 28F128J3A in 2x16 configuration
- {
-- name: "main partition ",
-- size: 0x02000000, // 128 x 2 x 128k byte sectors
-- offset: 0,
-+ .name = "main partition ",
-+ .size = 0x02000000, // 128 x 2 x 128k byte sectors
-+ .offset = 0,
- },
- },
- };
-@@ -197,9 +146,9 @@
- static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
- {
- {
-- name: "main partition",
-- size: CONFIG_MTD_CSTM_MIPS_IXX_LEN,
-- offset: 0,
-+ .name = "main partition",
-+ .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN,
-+ .offset = 0,
- },
- },
- };
-@@ -216,17 +165,24 @@
-
- /* Initialize mapping */
- for (i=0;i<PHYSMAP_NUMBER;i++) {
-- printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-- memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info));
-- cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-- if (!cstm_mips_ixx_map[i].map_priv_1) {
-+ printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n",
-+ cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-+
-+
-+ cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
-+ cstm_mips_ixx_map[i].virt = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-+ if (!cstm_mips_ixx_map[i].virt) {
- printk(KERN_WARNING "Failed to ioremap\n");
- return -EIO;
- }
- cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
- cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
- cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
-- //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1));
-+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-+ cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
-+#endif
-+ simple_map_init(&cstm_mips_ixx_map[i]);
-+ //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
- }
-
- #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-@@ -244,7 +200,7 @@
- printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
- add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
-@@ -266,9 +222,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (cstm_mips_ixx_map[i].map_priv_1) {
-- iounmap((void *)cstm_mips_ixx_map[i].map_priv_1);
-- cstm_mips_ixx_map[i].map_priv_1 = 0;
-+ if (cstm_mips_ixx_map[i].virt) {
-+ iounmap((void *)cstm_mips_ixx_map[i].virt);
-+ cstm_mips_ixx_map[i].virt = 0;
- }
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/db1x00-flash.c linux/drivers/mtd/maps/db1x00-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/db1x00-flash.c 2003-02-16 07:25:24.000000000 +0100
-+++ linux/drivers/mtd/maps/db1x00-flash.c 2004-11-19 10:25:11.903199184 +0100
-@@ -8,6 +8,7 @@
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
-+#include <linux/init.h>
- #include <linux/kernel.h>
-
- #include <linux/mtd/mtd.h>
-@@ -29,76 +30,6 @@
- static unsigned long flash_size;
-
- static BCSR * const bcsr = (BCSR *)0xAE000000;
--
--__u8 physmap_read8(struct map_info *map, unsigned long ofs)
--{
-- __u8 ret;
-- ret = __raw_readb(map->map_priv_1 + ofs);
-- DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--__u16 physmap_read16(struct map_info *map, unsigned long ofs)
--{
-- __u16 ret;
-- ret = __raw_readw(map->map_priv_1 + ofs);
-- DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--__u32 physmap_read32(struct map_info *map, unsigned long ofs)
--{
-- __u32 ret;
-- ret = __raw_readl(map->map_priv_1 + ofs);
-- DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
--static struct map_info db1x00_map = {
-- name: "Db1x00 flash",
-- read8: physmap_read8,
-- read16: physmap_read16,
-- read32: physmap_read32,
-- copy_from: physmap_copy_from,
-- write8: physmap_write8,
-- write16: physmap_write16,
-- write32: physmap_write32,
-- copy_to: physmap_copy_to,
--};
--
- static unsigned char flash_buswidth = 4;
-
- /*
-@@ -115,58 +46,62 @@
- */
- static struct mtd_partition db1x00_partitions[] = {
- {
-- name: "User FS",
-- size: 0x1c00000,
-- offset: 0x0000000
-+ .name = "User FS",
-+ .size = 0x1c00000,
-+ .offset = 0x0000000
- },{
-- name: "yamon",
-- size: 0x0100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE
-+ .name = "yamon",
-+ .size = 0x0100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
- },{
-- name: "raw kernel",
-- size: (0x300000-0x40000), /* last 256KB is yamon env */
-- offset: MTDPART_OFS_APPEND,
-+ .name = "raw kernel",
-+ .size = (0x300000-0x40000), /* last 256KB is env */
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #elif defined(DB1X00_BOOT_ONLY)
- static struct mtd_partition db1x00_partitions[] = {
- {
-- name: "User FS",
-- size: 0x00c00000,
-- offset: 0x0000000
-+ .name = "User FS",
-+ .size = 0x00c00000,
-+ .offset = 0x0000000
- },{
-- name: "yamon",
-- size: 0x0100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE
-+ .name = "yamon",
-+ .size = 0x0100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
- },{
-- name: "raw kernel",
-- size: (0x300000-0x40000), /* last 256KB is yamon env */
-- offset: MTDPART_OFS_APPEND,
-+ .name = "raw kernel",
-+ .size = (0x300000-0x40000), /* last 256KB is env */
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #elif defined(DB1X00_USER_ONLY)
- static struct mtd_partition db1x00_partitions[] = {
- {
-- name: "User FS",
-- size: 0x0e00000,
-- offset: 0x0000000
-+ .name = "User FS",
-+ .size = 0x0e00000,
-+ .offset = 0x0000000
- },{
-- name: "raw kernel",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "raw kernel",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #else
- #error MTD_DB1X00 define combo error /* should never happen */
- #endif
-+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-+#define NAME "Db1x00 Linux Flash"
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-+static struct map_info db1xxx_mtd_map = {
-+ .name = NAME,
-+};
-
- static struct mtd_partition *parsed_parts;
--static struct mtd_info *mymtd;
-+static struct mtd_info *db1xxx_mtd;
-
- /*
- * Probe the flash density and setup window address and size
-@@ -174,7 +109,7 @@
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
--int setup_flash_params()
-+int setup_flash_params(void)
- {
- switch ((bcsr->status >> 14) & 0x3) {
- case 0: /* 64Mbit devices */
-@@ -228,6 +163,10 @@
- default:
- return 1;
- }
-+ db1xxx_mtd_map.size = window_size;
-+ db1xxx_mtd_map.buswidth = flash_buswidth;
-+ db1xxx_mtd_map.phys = window_addr;
-+ db1xxx_mtd_map.buswidth = flash_buswidth;
- return 0;
- }
-
-@@ -235,10 +174,6 @@
- {
- struct mtd_partition *parts;
- int nb_parts = 0;
-- char *part_type;
--
-- /* Default flash buswidth */
-- db1x00_map.buswidth = flash_buswidth;
-
- if (setup_flash_params())
- return -ENXIO;
-@@ -246,32 +181,29 @@
- /*
- * Static partition definition selection
- */
-- part_type = "static";
- parts = db1x00_partitions;
- nb_parts = NB_OF(db1x00_partitions);
-- db1x00_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n",
-- db1x00_map.buswidth*8);
-- db1x00_map.map_priv_1 =
-- (unsigned long)ioremap(window_addr, window_size);
-- mymtd = do_map_probe("cfi_probe", &db1x00_map);
-- if (!mymtd) return -ENXIO;
-- mymtd->module = THIS_MODULE;
-+ db1xxx_mtd_map.buswidth*8);
-+ db1xxx_mtd_map.virt = (unsigned long)ioremap(window_addr, window_size);
-+ db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
-+ if (!db1xxx_mtd) return -ENXIO;
-+ db1xxx_mtd->owner = THIS_MODULE;
-
-- add_mtd_partitions(mymtd, parts, nb_parts);
-+ add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
- return 0;
- }
-
- static void __exit db1x00_mtd_cleanup(void)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-+ if (db1xxx_mtd) {
-+ del_mtd_partitions(db1xxx_mtd);
-+ map_destroy(db1xxx_mtd);
- if (parsed_parts)
- kfree(parsed_parts);
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dbox2-flash.c linux/drivers/mtd/maps/dbox2-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/dbox2-flash.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/dbox2-flash.c 2004-11-19 10:25:11.904199032 +0100
-@@ -1,12 +1,13 @@
- /*
-- * $Id$
-+ * $Id$
- *
-- * Nokia / Sagem D-Box 2 flash driver
-+ * D-Box 2 flash driver
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -16,22 +17,44 @@
- /* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
--static struct mtd_partition partition_info[]= {{name: "BR bootloader", // raw
-- size: 128 * 1024,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE},
-- {name: "PPC bootloader", // flfs
-- size: 128 * 1024,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0},
-- {name: "Kernel", // idxfs
-- size: 768 * 1024,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0},
-- {name: "System", // jffs
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: 0}};
-+static struct mtd_partition partition_info[]= {
-+ {
-+ .name = "BR bootloader",
-+ .size = 128 * 1024,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ },
-+ {
-+ .name = "flfs (ppcboot)",
-+ .size = 128 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "root (cramfs)",
-+ .size = 7040 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "var (jffs2)",
-+ .size = 896 * 1024,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "flash without bootloader",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 128 * 1024,
-+ .mask_flags = 0
-+ },
-+ {
-+ .name = "complete flash",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ }
-+};
-
- #define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0]))
-
-@@ -40,72 +63,24 @@
-
- static struct mtd_info *mymtd;
-
--__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void dbox2_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info dbox2_flash_map = {
-- name: "D-Box 2 flash memory",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: dbox2_flash_read8,
-- read16: dbox2_flash_read16,
-- read32: dbox2_flash_read32,
-- copy_from: dbox2_flash_copy_from,
-- write8: dbox2_flash_write8,
-- write16: dbox2_flash_write16,
-- write32: dbox2_flash_write32,
-- copy_to: dbox2_flash_copy_to
-+ .name = "D-Box 2 flash memory",
-+ .size = WINDOW_SIZE,
-+ .buswidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- int __init init_dbox2_flash(void)
- {
- printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
-- dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!dbox2_flash_map.map_priv_1) {
-+ if (!dbox2_flash_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&dbox2_flash_map);
-
- // Probe for dual Intel 28F320 or dual AMD
- mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
-@@ -117,7 +92,7 @@
- }
-
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
-@@ -125,7 +100,7 @@
- return 0;
- }
-
-- iounmap((void *)dbox2_flash_map.map_priv_1);
-+ iounmap((void *)dbox2_flash_map.virt);
- return -ENXIO;
- }
-
-@@ -135,9 +110,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (dbox2_flash_map.map_priv_1) {
-- iounmap((void *)dbox2_flash_map.map_priv_1);
-- dbox2_flash_map.map_priv_1 = 0;
-+ if (dbox2_flash_map.virt) {
-+ iounmap((void *)dbox2_flash_map.virt);
-+ dbox2_flash_map.virt = 0;
- }
- }
-
-@@ -146,5 +121,5 @@
-
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>");
--MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board");
-+MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
-+MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dc21285.c linux/drivers/mtd/maps/dc21285.c
---- linux-mips-2.4.27/drivers/mtd/maps/dc21285.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/dc21285.c 2004-11-19 10:25:11.906198728 +0100
-@@ -5,12 +5,13 @@
- *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- */
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -92,26 +93,42 @@
- }
-
- struct map_info dc21285_map = {
-- name: "DC21285 flash",
-- size: 16*1024*1024,
-- read8: dc21285_read8,
-- read16: dc21285_read16,
-- read32: dc21285_read32,
-- copy_from: dc21285_copy_from,
-- write8: dc21285_write8,
-- write16: dc21285_write16,
-- write32: dc21285_write32,
-- copy_to: dc21285_copy_to
-+ .name = "DC21285 flash",
-+ .phys = NO_XIP,
-+ .size = 16*1024*1024,
-+ .read8 = dc21285_read8,
-+ .read16 = dc21285_read16,
-+ .read32 = dc21285_read32,
-+ .copy_from = dc21285_copy_from,
-+ .write8 = dc21285_write8,
-+ .write16 = dc21285_write16,
-+ .write32 = dc21285_write32,
-+ .copy_to = dc21285_copy_to
- };
-
-
- /* Partition stuff */
- static struct mtd_partition *dc21285_parts;
--
--extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
-+#ifdef CONFIG_MTD_PARTITIONS
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+#endif
-
- int __init init_dc21285(void)
- {
-+
-+ /*
-+ * Flash timing is determined with bits 19-16 of the
-+ * CSR_SA110_CNTL. The value is the number of wait cycles, or
-+ * 0 for 16 cycles (the default). Cycles are 20 ns.
-+ * Here we use 7 for 140 ns flash chips.
-+ */
-+ /* access time */
-+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
-+ /* burst time */
-+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
-+ /* tristate time */
-+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
-+
- /* Determine buswidth */
- switch (*CSR_SA110_CNTL & (3<<14)) {
- case SA110_CNTL_ROMWIDTH_8:
-@@ -141,33 +158,18 @@
- if (mymtd) {
- int nrparts = 0;
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /* partition fixup */
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
--#endif
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0);
- if (nrparts > 0) {
- add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-- } else if (nrparts == 0) {
-- printk(KERN_NOTICE "RedBoot partition table failed\n");
-- add_mtd_device(mymtd);
-+ return 0;
- }
--
-- /*
-- * Flash timing is determined with bits 19-16 of the
-- * CSR_SA110_CNTL. The value is the number of wait cycles, or
-- * 0 for 16 cycles (the default). Cycles are 20 ns.
-- * Here we use 7 for 140 ns flash chips.
-- */
-- /* access time */
-- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
-- /* burst time */
-- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
-- /* tristate time */
-- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
--
-+#endif
-+ add_mtd_device(mymtd);
- return 0;
- }
-
-@@ -177,17 +179,16 @@
-
- static void __exit cleanup_dc21285(void)
- {
-- if (mymtd) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (dc21285_parts) {
-+ del_mtd_partitions(mymtd);
-+ kfree(dc21285_parts);
-+ } else
-+#endif
- del_mtd_device(mymtd);
-+
- map_destroy(mymtd);
-- mymtd = NULL;
-- }
-- if (dc21285_map.map_priv_1) {
- iounmap((void *)dc21285_map.map_priv_1);
-- dc21285_map.map_priv_1 = 0;
-- }
-- if(dc21285_parts)
-- kfree(dc21285_parts);
- }
-
- module_init(init_dc21285);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dilnetpc.c linux/drivers/mtd/maps/dilnetpc.c
---- linux-mips-2.4.27/drivers/mtd/maps/dilnetpc.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/dilnetpc.c 2004-11-19 10:25:11.907198576 +0100
-@@ -14,7 +14,7 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *
-- * $Id$
-+ * $Id$
- *
- * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
- * featuring the AMD Elan SC410 processor. There are two variants of this
-@@ -29,6 +29,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -36,7 +37,7 @@
- #include <linux/mtd/concat.h>
-
- /*
--** The DIL/NetPC keeps it's BIOS in two distinct flash blocks.
-+** The DIL/NetPC keeps its BIOS in two distinct flash blocks.
- ** Destroying any of these blocks transforms the DNPC into
- ** a paperweight (albeit not a very useful one, considering
- ** it only weighs a few grams).
-@@ -189,45 +190,6 @@
- }
-
-
--static __u8 dnpc_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 dnpc_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 dnpc_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
-
- /*
- ************************************************************
-@@ -288,19 +250,11 @@
- #define WINDOW_ADDR FLASH_BASE
-
- static struct map_info dnpc_map = {
-- name: "ADNP Flash Bank",
-- size: ADNP_WINDOW_SIZE,
-- buswidth: 1,
-- read8: dnpc_read8,
-- read16: dnpc_read16,
-- read32: dnpc_read32,
-- copy_from: dnpc_copy_from,
-- write8: dnpc_write8,
-- write16: dnpc_write16,
-- write32: dnpc_write32,
-- copy_to: dnpc_copy_to,
-- set_vpp: adnp_set_vpp,
-- map_priv_2: WINDOW_ADDR
-+ .name = "ADNP Flash Bank",
-+ .size = ADNP_WINDOW_SIZE,
-+ .buswidth = 1,
-+ .set_vpp = adnp_set_vpp,
-+ .phys = WINDOW_ADDR
- };
-
- /*
-@@ -316,29 +270,29 @@
- static struct mtd_partition partition_info[]=
- {
- {
-- name: "ADNP boot",
-- offset: 0,
-- size: 0xf0000,
-+ .name = "ADNP boot",
-+ .offset = 0,
-+ .size = 0xf0000,
- },
- {
-- name: "ADNP system BIOS",
-- offset: MTDPART_OFS_NXTBLK,
-- size: 0x10000,
-+ .name = "ADNP system BIOS",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 0x10000,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- {
-- name: "ADNP file system",
-- offset: MTDPART_OFS_NXTBLK,
-- size: 0x2f0000,
-+ .name = "ADNP file system",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 0x2f0000,
- },
- {
-- name: "ADNP system BIOS entry",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "ADNP system BIOS entry",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- };
-@@ -369,21 +323,21 @@
- static struct mtd_partition higlvl_partition_info[]=
- {
- {
-- name: "ADNP boot block",
-- offset: 0,
-- size: CONFIG_MTD_DILNETPC_BOOTSIZE,
-+ .name = "ADNP boot block",
-+ .offset = 0,
-+ .size = CONFIG_MTD_DILNETPC_BOOTSIZE,
- },
- {
-- name: "ADNP file system space",
-- offset: MTDPART_OFS_NXTBLK,
-- size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
-+ .name = "ADNP file system space",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
- },
- {
-- name: "ADNP system BIOS + BIOS Entry",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "ADNP system BIOS + BIOS Entry",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
-- mask_flags: MTD_WRITEABLE,
-+ .mask_flags = MTD_WRITEABLE,
- #endif
- },
- };
-@@ -447,18 +401,19 @@
- }
-
- printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n",
-- is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2);
-+ is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
-
-- dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size);
-+ dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size);
-
-- dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size);
-+ dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
-
-- if (!dnpc_map.map_priv_1) {
-+ if (!dnpc_map.virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+ simple_map_init(&dnpc_map);
-
-- printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1);
-+ printk("FLASH virtual address: 0x%lx\n", dnpc_map.virt);
-
- mymtd = do_map_probe("jedec_probe", &dnpc_map);
-
-@@ -475,11 +430,11 @@
- mymtd->erasesize = 0x10000;
-
- if (!mymtd) {
-- iounmap((void *)dnpc_map.map_priv_1);
-+ iounmap((void *)dnpc_map.virt);
- return -ENXIO;
- }
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /*
- ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
-@@ -525,10 +480,10 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (dnpc_map.map_priv_1) {
-- iounmap((void *)dnpc_map.map_priv_1);
-+ if (dnpc_map.virt) {
-+ iounmap((void *)dnpc_map.virt);
- dnpc_unmap_flash();
-- dnpc_map.map_priv_1 = 0;
-+ dnpc_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ebony.c linux/drivers/mtd/maps/ebony.c
---- linux-mips-2.4.27/drivers/mtd/maps/ebony.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/ebony.c 2004-11-19 10:25:11.909198272 +0100
-@@ -0,0 +1,164 @@
-+/*
-+ * $Id$
-+ *
-+ * Mapping for Ebony user flash
-+ *
-+ * Matt Porter <mporter@mvista.com>
-+ *
-+ * Copyright 2002 MontaVista Software Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <asm/io.h>
-+#include <asm/ibm440.h>
-+#include <platforms/ebony.h>
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info ebony_small_map = {
-+ .name = "Ebony small flash",
-+ .size = EBONY_SMALL_FLASH_SIZE,
-+ .buswidth = 1,
-+};
-+
-+static struct map_info ebony_large_map = {
-+ .name = "Ebony large flash",
-+ .size = EBONY_LARGE_FLASH_SIZE,
-+ .buswidth = 1,
-+};
-+
-+static struct mtd_partition ebony_small_partitions[] = {
-+ {
-+ .name = "OpenBIOS",
-+ .offset = 0x0,
-+ .size = 0x80000,
-+ }
-+};
-+
-+static struct mtd_partition ebony_large_partitions[] = {
-+ {
-+ .name = "fs",
-+ .offset = 0,
-+ .size = 0x380000,
-+ },
-+ {
-+ .name = "firmware",
-+ .offset = 0x380000,
-+ .size = 0x80000,
-+ }
-+};
-+
-+int __init init_ebony(void)
-+{
-+ u8 fpga0_reg;
-+ unsigned long fpga0_adr;
-+ unsigned long long small_flash_base, large_flash_base;
-+
-+ fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16);
-+ if (!fpga0_adr)
-+ return -ENOMEM;
-+
-+ fpga0_reg = readb(fpga0_adr);
-+ iounmap64(fpga0_adr);
-+
-+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_HIGH2;
-+ else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_HIGH1;
-+ else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_FLASH_SEL(fpga0_reg))
-+ small_flash_base = EBONY_SMALL_FLASH_LOW2;
-+ else
-+ small_flash_base = EBONY_SMALL_FLASH_LOW1;
-+
-+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
-+ !EBONY_ONBRD_FLASH_EN(fpga0_reg))
-+ large_flash_base = EBONY_LARGE_FLASH_LOW;
-+ else
-+ large_flash_base = EBONY_LARGE_FLASH_HIGH;
-+
-+ ebony_small_map.phys = small_flash_base;
-+ ebony_small_map.virt =
-+ (unsigned long)ioremap64(small_flash_base,
-+ ebony_small_map.size);
-+
-+ if (!ebony_small_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ebony_small_map);
-+
-+ flash = do_map_probe("map_rom", &ebony_small_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ebony_small_partitions,
-+ ARRAY_SIZE(ebony_small_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ ebony_large_map.phys = large_flash_base;
-+ ebony_large_map.virt =
-+ (unsigned long)ioremap64(large_flash_base,
-+ ebony_large_map.size);
-+
-+ if (!ebony_large_map.virt) {
-+ printk("Failed to ioremap flash\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&ebony_large_map);
-+
-+ flash = do_map_probe("cfi_probe", &ebony_large_map);
-+ if (flash) {
-+ flash->owner = THIS_MODULE;
-+ add_mtd_partitions(flash, ebony_large_partitions,
-+ ARRAY_SIZE(ebony_large_partitions));
-+ } else {
-+ printk("map probe failed for flash\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit cleanup_ebony(void)
-+{
-+ if (flash) {
-+ del_mtd_partitions(flash);
-+ map_destroy(flash);
-+ }
-+
-+ if (ebony_small_map.virt) {
-+ iounmap((void *)ebony_small_map.virt);
-+ ebony_small_map.virt = 0;
-+ }
-+
-+ if (ebony_large_map.virt) {
-+ iounmap((void *)ebony_large_map.virt);
-+ ebony_large_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_ebony);
-+module_exit(cleanup_ebony);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Matt Porter <mporter@mvista.com>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/edb7312.c linux/drivers/mtd/maps/edb7312.c
---- linux-mips-2.4.27/drivers/mtd/maps/edb7312.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/edb7312.c 2004-11-19 10:25:11.910198120 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Handle mapping of the NOR flash on Cogent EDB7312 boards
- *
-@@ -13,6 +13,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -35,61 +36,11 @@
-
- static struct mtd_info *mymtd;
-
--__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
- struct map_info edb7312nor_map = {
-- name: "NOR flash on EDB7312",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: edb7312nor_read8,
-- read16: edb7312nor_read16,
-- read32: edb7312nor_read32,
-- copy_from: edb7312nor_copy_from,
-- write8: edb7312nor_write8,
-- write16: edb7312nor_write16,
-- write32: edb7312nor_write32,
-- copy_to: edb7312nor_copy_to
-+ .name = "NOR flash on EDB7312",
-+ .size = WINDOW_SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR,
- };
-
- #ifdef CONFIG_MTD_PARTITIONS
-@@ -100,29 +51,23 @@
- static struct mtd_partition static_partitions[3] =
- {
- {
-- name: "ARMboot",
-- size: 0x40000,
-- offset: 0
-+ .name = "ARMboot",
-+ .size = 0x40000,
-+ .offset = 0
- },
- {
-- name: "Kernel",
-- size: 0x200000,
-- offset: 0x40000
-+ .name = "Kernel",
-+ .size = 0x200000,
-+ .offset = 0x40000
- },
- {
-- name: "RootFS",
-- size: 0xDC0000,
-- offset: 0x240000
-+ .name = "RootFS",
-+ .size = 0xDC0000,
-+ .offset = 0x240000
- },
- };
-
--#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
--
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
--#endif
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
- #endif
-
-@@ -137,32 +82,33 @@
-
- printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
- WINDOW_SIZE, WINDOW_ADDR);
-- edb7312nor_map.map_priv_1 = (unsigned long)
-+ edb7312nor_map.virt = (unsigned long)
- ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!edb7312nor_map.map_priv_1) {
-+ if (!edb7312nor_map.virt) {
- printk(MSG_PREFIX "failed to ioremap\n");
- return -EIO;
- }
-
-+ simple_map_init(&edb7312nor_map);
-+
- mymtd = 0;
- type = rom_probe_types;
- for(; !mymtd && *type; type++) {
- mymtd = do_map_probe(*type, &edb7312nor_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
-+ mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
- if (mtd_parts_nb > 0)
-- part_type = "command line";
--#endif
-+ part_type = "detected";
-+
- if (mtd_parts_nb == 0)
- {
- mtd_parts = static_partitions;
-- mtd_parts_nb = NB_OF(static_partitions);
-+ mtd_parts_nb = ARRAY_SIZE(static_partitions);
- part_type = "static";
- }
- #endif
-@@ -178,7 +124,7 @@
- return 0;
- }
-
-- iounmap((void *)edb7312nor_map.map_priv_1);
-+ iounmap((void *)edb7312nor_map.virt);
- return -ENXIO;
- }
-
-@@ -188,9 +134,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (edb7312nor_map.map_priv_1) {
-- iounmap((void *)edb7312nor_map.map_priv_1);
-- edb7312nor_map.map_priv_1 = 0;
-+ if (edb7312nor_map.virt) {
-+ iounmap((void *)edb7312nor_map.virt);
-+ edb7312nor_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/elan-104nc.c linux/drivers/mtd/maps/elan-104nc.c
---- linux-mips-2.4.27/drivers/mtd/maps/elan-104nc.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/elan-104nc.c 2004-11-19 10:25:11.912197816 +0100
-@@ -16,7 +16,7 @@
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-- $Id$
-+ $Id$
-
- The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
- mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
-@@ -40,6 +40,7 @@
- #include <asm/io.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-
- #define WINDOW_START 0xb0000
-@@ -59,14 +60,14 @@
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
-- { name: "ELAN-104NC flash boot partition",
-- offset: 0,
-- size: 640*1024 },
-- { name: "ELAN-104NC flash partition 1",
-- offset: 640*1024,
-- size: 896*1024 },
-- { name: "ELAN-104NC flash partition 2",
-- offset: (640+896)*1024 }
-+ { .name = "ELAN-104NC flash boot partition",
-+ .offset = 0,
-+ .size = 640*1024 },
-+ { .name = "ELAN-104NC flash partition 1",
-+ .offset = 640*1024,
-+ .size = 896*1024 },
-+ { .name = "ELAN-104NC flash partition 2",
-+ .offset = (640+896)*1024 }
- };
- #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
-@@ -195,19 +196,20 @@
- }
-
- static struct map_info elan_104nc_map = {
-- name: "ELAN-104NC flash",
-- size: 8*1024*1024, /* this must be set to a maximum possible amount
-+ .name = "ELAN-104NC flash",
-+ .phys = NO_XIP,
-+ .size = 8*1024*1024, /* this must be set to a maximum possible amount
- of flash so the cfi probe routines find all
- the chips */
-- buswidth: 2,
-- read8: elan_104nc_read8,
-- read16: elan_104nc_read16,
-- read32: elan_104nc_read32,
-- copy_from: elan_104nc_copy_from,
-- write8: elan_104nc_write8,
-- write16: elan_104nc_write16,
-- write32: elan_104nc_write32,
-- copy_to: elan_104nc_copy_to
-+ .buswidth = 2,
-+ .read8 = elan_104nc_read8,
-+ .read16 = elan_104nc_read16,
-+ .read32 = elan_104nc_read32,
-+ .copy_from = elan_104nc_copy_from,
-+ .write8 = elan_104nc_write8,
-+ .write16 = elan_104nc_write16,
-+ .write32 = elan_104nc_write32,
-+ .copy_to = elan_104nc_copy_to
- };
-
- /* MTD device for all of the flash. */
-@@ -221,20 +223,13 @@
- }
-
- iounmap((void *)iomapadr);
-- release_region(PAGE_IO,PAGE_IO_SIZE);
- }
-
- int __init init_elan_104nc(void)
- {
-- /* Urg! We use I/O port 0x22 without request_region()ing it */
-- /*
-- if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) {
-- printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-- elan_104nc_map.name,
-- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-- return -EAGAIN;
-- }
-- */
-+ /* Urg! We use I/O port 0x22 without request_region()ing it,
-+ because it's already allocated to the PIC. */
-+
- iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
- if (!iomapadr) {
- printk( KERN_ERR"%s: failed to ioremap memory region\n",
-@@ -242,10 +237,6 @@
- return -EIO;
- }
-
-- /*
-- request_region( PAGE_IO, PAGE_IO_SIZE, "ELAN-104NC flash" );
-- */
--
- printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
- elan_104nc_map.name,
- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
-@@ -260,7 +251,7 @@
- return -ENXIO;
- }
-
-- all_mtd->module=THIS_MODULE;
-+ all_mtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/epxa10db-flash.c linux/drivers/mtd/maps/epxa10db-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/epxa10db-flash.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/epxa10db-flash.c 2004-11-19 10:25:11.913197664 +0100
-@@ -5,7 +5,7 @@
- * Copyright (C) 2001 Altera Corporation
- * Copyright (C) 2001 Red Hat, Inc.
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -26,6 +26,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -43,87 +44,38 @@
-
- static struct mtd_info *mymtd;
-
--extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
- static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-
--static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
--
-
- static struct map_info epxa_map = {
-- name: "EPXA flash",
-- size: FLASH_SIZE,
-- buswidth: 2,
-- read8: epxa_read8,
-- read16: epxa_read16,
-- read32: epxa_read32,
-- copy_from: epxa_copy_from,
-- write8: epxa_write8,
-- write16: epxa_write16,
-- write32: epxa_write32,
-- copy_to: epxa_copy_to
-+ .name = "EPXA flash",
-+ .size = FLASH_SIZE,
-+ .buswidth = 2,
-+ .phys = FLASH_START,
- };
-
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-
- static int __init epxa_mtd_init(void)
- {
- int i;
-
-- printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
-- epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-- if (!epxa_map.map_priv_1) {
-+ printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
-+
-+ epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-+ if (!epxa_map.virt) {
- printk("Failed to ioremap %s flash\n",BOARD_NAME);
- return -EIO;
- }
-+ simple_map_init(&epxa_map);
-
- mymtd = do_map_probe("cfi_probe", &epxa_map);
- if (!mymtd) {
-- iounmap((void *)epxa_map.map_priv_1);
-+ iounmap((void *)epxa_map.virt);
- return -ENXIO;
- }
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- /* Unlock the flash device. */
- if(mymtd->unlock){
-@@ -135,23 +87,14 @@
- }
- }
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nr_parts = parse_redboot_partitions(mymtd, &parts);
--
-- if (nr_parts > 0) {
-- add_mtd_partitions(mymtd, parts, nr_parts);
-- return 0;
-- }
--#endif
--#ifdef CONFIG_MTD_AFS_PARTS
-- nr_parts = parse_afs_partitions(mymtd, &parts);
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0);
-
- if (nr_parts > 0) {
- add_mtd_partitions(mymtd, parts, nr_parts);
- return 0;
- }
- #endif
--
- /* No recognised partitioning schemes found - use defaults */
- nr_parts = epxa_default_partitions(mymtd, &parts);
- if (nr_parts > 0) {
-@@ -173,9 +116,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (epxa_map.map_priv_1) {
-- iounmap((void *)epxa_map.map_priv_1);
-- epxa_map.map_priv_1 = 0;
-+ if (epxa_map.virt) {
-+ iounmap((void *)epxa_map.virt);
-+ epxa_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/fortunet.c linux/drivers/mtd/maps/fortunet.c
---- linux-mips-2.4.27/drivers/mtd/maps/fortunet.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/fortunet.c 2004-11-19 10:25:11.915197360 +0100
-@@ -1,11 +1,12 @@
- /* fortunet.c memory map
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -23,7 +24,7 @@
-
- struct map_region
- {
-- int window_addr_phyical;
-+ int window_addr_physical;
- int altbuswidth;
- struct map_info map_info;
- struct mtd_info *mymtd;
-@@ -37,57 +38,10 @@
- static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
-
-
--__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
-
- struct map_info default_map = {
-- size: DEF_WINDOW_SIZE,
-- buswidth: 4,
-- read8: fortunet_read8,
-- read16: fortunet_read16,
-- read32: fortunet_read32,
-- copy_from: fortunet_copy_from,
-- write8: fortunet_write8,
-- write16: fortunet_write16,
-- write32: fortunet_write32,
-- copy_to: fortunet_copy_to
-+ .size = DEF_WINDOW_SIZE,
-+ .buswidth = 4,
- };
-
- static char * __init get_string_option(char *dest,int dest_size,char *sor)
-@@ -147,7 +101,7 @@
- get_options (get_string_option(string,sizeof(string),line),6,params);
- if(params[0]<1)
- {
-- printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
-+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
- " name,region-number[,base,size,buswidth,altbuswidth]\n");
- return 1;
- }
-@@ -161,14 +115,14 @@
- memcpy(&map_regions[params[1]].map_info,
- &default_map,sizeof(map_regions[params[1]].map_info));
- map_regions_set[params[1]] = 1;
-- map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
-+ map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
- map_regions[params[1]].altbuswidth = 2;
- map_regions[params[1]].mymtd = NULL;
- map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
- strcpy(map_regions[params[1]].map_info.name,string);
- if(params[0]>1)
- {
-- map_regions[params[1]].window_addr_phyical = params[2];
-+ map_regions[params[1]].window_addr_physical = params[2];
- }
- if(params[0]>2)
- {
-@@ -185,14 +139,14 @@
- return 1;
- }
-
--static int __init MTD_New_Partion(char *line)
-+static int __init MTD_New_Partition(char *line)
- {
- char string[MAX_NAME_SIZE];
- int params[4];
- get_options (get_string_option(string,sizeof(string),line),4,params);
- if(params[0]<3)
- {
-- printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
-+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
- " name,region-number,size,offset\n");
- return 1;
- }
-@@ -204,7 +158,7 @@
- }
- if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
- {
-- printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
-+ printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
- return 1;
- }
- map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
-@@ -220,7 +174,10 @@
- }
-
- __setup("MTD_Region=", MTD_New_Region);
--__setup("MTD_Partion=", MTD_New_Partion);
-+__setup("MTD_Partition=", MTD_New_Partition);
-+
-+/* Backwards-spelling-compatibility */
-+__setup("MTD_Partion=", MTD_New_Partition);
-
- int __init init_fortunet(void)
- {
-@@ -229,13 +186,13 @@
- {
- if(map_regions_parts[ix]&&(!map_regions_set[ix]))
- {
-- printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
-+ printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
- ix);
- memset(&map_regions[ix],0,sizeof(map_regions[ix]));
- memcpy(&map_regions[ix].map_info,&default_map,
- sizeof(map_regions[ix].map_info));
- map_regions_set[ix] = 1;
-- map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
-+ map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
- map_regions[ix].altbuswidth = 2;
- map_regions[ix].mymtd = NULL;
- map_regions[ix].map_info.name = map_regions[ix].map_name;
-@@ -244,30 +201,35 @@
- if(map_regions_set[ix])
- {
- iy++;
-- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
- " address %x size %x\n",
- map_regions[ix].map_info.name,
-- map_regions[ix].window_addr_phyical,
-+ map_regions[ix].window_addr_physical,
- map_regions[ix].map_info.size);
-- map_regions[ix].map_info.map_priv_1 =
-+
-+ map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
-+
-+ map_regions[ix].map_info.virt =
- (int)ioremap_nocache(
-- map_regions[ix].window_addr_phyical,
-+ map_regions[ix].window_addr_physical,
- map_regions[ix].map_info.size);
-- if(!map_regions[ix].map_info.map_priv_1)
-+ if(!map_regions[ix].map_info.virt)
- {
- printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
- map_regions[ix].map_info.name);
- return -ENXIO;
- }
-- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
-+ simple_map_init(&map_regions[ix].map_info);
-+
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
- map_regions[ix].map_info.name,
-- map_regions[ix].map_info.map_priv_1);
-+ map_regions[ix].map_info.virt);
- map_regions[ix].mymtd = do_map_probe("cfi_probe",
- &map_regions[ix].map_info);
- if((!map_regions[ix].mymtd)&&(
- map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
- {
-- printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
-+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth "
- "for %s flash.\n",
- map_regions[ix].map_info.name);
- map_regions[ix].map_info.buswidth =
-@@ -275,7 +237,7 @@
- map_regions[ix].mymtd = do_map_probe("cfi_probe",
- &map_regions[ix].map_info);
- }
-- map_regions[ix].mymtd->module = THIS_MODULE;
-+ map_regions[ix].mymtd->owner = THIS_MODULE;
- add_mtd_partitions(map_regions[ix].mymtd,
- map_regions[ix].parts,map_regions_parts[ix]);
- }
-@@ -297,7 +259,7 @@
- del_mtd_partitions( map_regions[ix].mymtd );
- map_destroy( map_regions[ix].mymtd );
- }
-- iounmap((void *)map_regions[ix].map_info.map_priv_1);
-+ iounmap((void *)map_regions[ix].map_info.virt);
- }
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/h720x-flash.c linux/drivers/mtd/maps/h720x-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/h720x-flash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/h720x-flash.c 2004-11-19 10:25:11.917197056 +0100
-@@ -0,0 +1,142 @@
-+/*
-+ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based
-+ * evaluation boards
-+ *
-+ * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
-+ * 2003 Thomas Gleixner <tglx@linutronix.de>
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+static struct mtd_info *mymtd;
-+
-+static struct map_info h720x_map = {
-+ .name = "H720X",
-+ .buswidth = 4,
-+ .size = FLASH_SIZE,
-+ .phys = FLASH_PHYS,
-+};
-+
-+static struct mtd_partition h720x_partitions[] = {
-+ {
-+ .name = "ArMon",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Env",
-+ .size = 0x00040000,
-+ .offset = 0x00080000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Kernel",
-+ .size = 0x00180000,
-+ .offset = 0x000c0000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "Ramdisk",
-+ .size = 0x00400000,
-+ .offset = 0x00240000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
-+ }
-+};
-+
-+#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0]))
-+
-+static int nr_mtd_parts;
-+static struct mtd_partition *mtd_parts;
-+static const char *probes[] = { "cmdlinepart", NULL };
-+
-+/*
-+ * Initialize FLASH support
-+ */
-+int __init h720x_mtd_init(void)
-+{
-+
-+ char *part_type = NULL;
-+
-+ h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE);
-+
-+ if (!h720x_map.virt) {
-+ printk(KERN_ERR "H720x-MTD: ioremap failed\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&h720x_map);
-+
-+ // Probe for flash buswidth 4
-+ printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
-+ mymtd = do_map_probe("cfi_probe", &h720x_map);
-+ if (!mymtd) {
-+ printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
-+ // Probe for buswidth 2
-+ h720x_map.buswidth = 2;
-+ mymtd = do_map_probe("cfi_probe", &h720x_map);
-+ }
-+
-+ if (mymtd) {
-+ mymtd->owner = THIS_MODULE;
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
-+ if (nr_mtd_parts > 0)
-+ part_type = "command line";
-+#endif
-+ if (nr_mtd_parts <= 0) {
-+ mtd_parts = h720x_partitions;
-+ nr_mtd_parts = NUM_PARTITIONS;
-+ part_type = "builtin";
-+ }
-+ printk(KERN_INFO "Using %s partition table\n", part_type);
-+ add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts);
-+ return 0;
-+ }
-+
-+ iounmap((void *)h720x_map.virt);
-+ return -ENXIO;
-+}
-+
-+/*
-+ * Cleanup
-+ */
-+static void __exit h720x_mtd_cleanup(void)
-+{
-+
-+ if (mymtd) {
-+ del_mtd_partitions(mymtd);
-+ map_destroy(mymtd);
-+ }
-+
-+ /* Free partition info, if commandline partition was used */
-+ if (mtd_parts && (mtd_parts != h720x_partitions))
-+ kfree (mtd_parts);
-+
-+ if (h720x_map.virt) {
-+ iounmap((void *)h720x_map.virt);
-+ h720x_map.virt = 0;
-+ }
-+}
-+
-+
-+module_init(h720x_mtd_init);
-+module_exit(h720x_mtd_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-+MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ichxrom.c linux/drivers/mtd/maps/ichxrom.c
---- linux-mips-2.4.27/drivers/mtd/maps/ichxrom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/ichxrom.c 2004-11-19 10:25:11.918196904 +0100
-@@ -0,0 +1,380 @@
-+/*
-+ * ichxrom.c
-+ *
-+ * Normal mappings of chips in physical memory
-+ * $Id$
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/config.h>
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define MTD_DEV_NAME_LENGTH 16
-+
-+#define RESERVE_MEM_REGION 0
-+
-+#define ICHX_FWH_REGION_START 0xFF000000UL
-+#define ICHX_FWH_REGION_SIZE 0x01000000UL
-+#define BIOS_CNTL 0x4e
-+#define FWH_DEC_EN1 0xE3
-+#define FWH_DEC_EN2 0xF0
-+#define FWH_SEL1 0xE8
-+#define FWH_SEL2 0xEE
-+
-+struct ichxrom_map_info {
-+ struct map_info map;
-+ struct mtd_info *mtd;
-+ unsigned long window_addr;
-+ struct pci_dev *pdev;
-+ struct resource window_rsrc;
-+ struct resource rom_rsrc;
-+ char mtd_name[MTD_DEV_NAME_LENGTH];
-+};
-+
-+static inline unsigned long addr(struct map_info *map, unsigned long ofs)
-+{
-+ unsigned long offset;
-+ offset = ((8*1024*1024) - map->size) + ofs;
-+ if (offset >= (4*1024*1024)) {
-+ offset += 0x400000;
-+ }
-+ return map->map_priv_1 + 0x400000 + offset;
-+}
-+
-+static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
-+{
-+ return addr - map->map_priv_1 + ICHX_FWH_REGION_START;
-+}
-+
-+static __u8 ichxrom_read8(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readb(addr(map, ofs));
-+}
-+
-+static __u16 ichxrom_read16(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readw(addr(map, ofs));
-+}
-+
-+static __u32 ichxrom_read32(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readl(addr(map, ofs));
-+}
-+
-+static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ memcpy_fromio(to, addr(map, from), len);
-+}
-+
-+static void ichxrom_write8(struct map_info *map, __u8 d, unsigned long ofs)
-+{
-+ __raw_writeb(d, addr(map,ofs));
-+ mb();
-+}
-+
-+static void ichxrom_write16(struct map_info *map, __u16 d, unsigned long ofs)
-+{
-+ __raw_writew(d, addr(map, ofs));
-+ mb();
-+}
-+
-+static void ichxrom_write32(struct map_info *map, __u32 d, unsigned long ofs)
-+{
-+ __raw_writel(d, addr(map, ofs));
-+ mb();
-+}
-+
-+static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ memcpy_toio(addr(map, to), from, len);
-+}
-+
-+static struct ichxrom_map_info ichxrom_map = {
-+ .map = {
-+ .name = MOD_NAME,
-+ .phys = NO_XIP,
-+ .size = 0,
-+ .buswidth = 1,
-+ .read8 = ichxrom_read8,
-+ .read16 = ichxrom_read16,
-+ .read32 = ichxrom_read32,
-+ .copy_from = ichxrom_copy_from,
-+ .write8 = ichxrom_write8,
-+ .write16 = ichxrom_write16,
-+ .write32 = ichxrom_write32,
-+ .copy_to = ichxrom_copy_to,
-+ /* Firmware hubs only use vpp when being programmed
-+ * in a factory setting. So in-place programming
-+ * needs to use a different method.
-+ */
-+ },
-+ /* remaining fields of structure are initialized to 0 */
-+};
-+
-+enum fwh_lock_state {
-+ FWH_DENY_WRITE = 1,
-+ FWH_IMMUTABLE = 2,
-+ FWH_DENY_READ = 4,
-+};
-+
-+static void ichxrom_cleanup(struct ichxrom_map_info *info)
-+{
-+ u16 word;
-+
-+ /* Disable writes through the rom window */
-+ pci_read_config_word(info->pdev, BIOS_CNTL, &word);
-+ pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1);
-+
-+ if (info->mtd) {
-+ del_mtd_device(info->mtd);
-+ map_destroy(info->mtd);
-+ info->mtd = NULL;
-+ info->map.virt = 0;
-+ }
-+ if (info->rom_rsrc.parent)
-+ release_resource(&info->rom_rsrc);
-+ if (info->window_rsrc.parent)
-+ release_resource(&info->window_rsrc);
-+
-+ if (info->window_addr) {
-+ iounmap((void *)(info->window_addr));
-+ info->window_addr = 0;
-+ }
-+}
-+
-+
-+static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
-+ enum fwh_lock_state state)
-+{
-+ struct map_info *map = mtd->priv;
-+ unsigned long start = ofs;
-+ unsigned long end = start + len -1;
-+
-+ /* FIXME do I need to guard against concurrency here? */
-+ /* round down to 64K boundaries */
-+ start = start & ~0xFFFF;
-+ end = end & ~0xFFFF;
-+ while (start <= end) {
-+ unsigned long ctrl_addr;
-+ ctrl_addr = addr(map, start) - 0x400000 + 2;
-+ writeb(state, ctrl_addr);
-+ start = start + 0x10000;
-+ }
-+ return 0;
-+}
-+
-+static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+ return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
-+}
-+
-+static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+ return ichxrom_set_lock_state(mtd, ofs, len, 0);
-+}
-+
-+static int __devinit ichxrom_init_one (struct pci_dev *pdev,
-+ const struct pci_device_id *ent)
-+{
-+ u16 word;
-+ struct ichxrom_map_info *info = &ichxrom_map;
-+ unsigned long map_size;
-+
-+ /* For now I just handle the ichx and I assume there
-+ * are not a lot of resources up at the top of the address
-+ * space. It is possible to handle other devices in the
-+ * top 16MB but it is very painful. Also since
-+ * you can only really attach a FWH to an ICHX there
-+ * a number of simplifications you can make.
-+ *
-+ * Also you can page firmware hubs if an 8MB window isn't enough
-+ * but don't currently handle that case either.
-+ */
-+
-+ info->pdev = pdev;
-+
-+ /*
-+ * Try to reserve the window mem region. If this fails then
-+ * it is likely due to the window being "reseved" by the BIOS.
-+ */
-+ info->window_rsrc.name = MOD_NAME;
-+ info->window_rsrc.start = ICHX_FWH_REGION_START;
-+ info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1;
-+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&iomem_resource, &info->window_rsrc)) {
-+ info->window_rsrc.parent = NULL;
-+ printk(KERN_ERR MOD_NAME
-+ " %s(): Unable to register resource"
-+ " 0x%.08lx-0x%.08lx - kernel bug?\n",
-+ __func__,
-+ info->window_rsrc.start, info->window_rsrc.end);
-+ }
-+
-+ /* Enable writes through the rom window */
-+ pci_read_config_word(pdev, BIOS_CNTL, &word);
-+ if (!(word & 1) && (word & (1<<1))) {
-+ /* The BIOS will generate an error if I enable
-+ * this device, so don't even try.
-+ */
-+ printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
-+ goto failed;
-+ }
-+ pci_write_config_word(pdev, BIOS_CNTL, word | 1);
-+
-+
-+ /* Map the firmware hub into my address space. */
-+ /* Does this use too much virtual address space? */
-+ info->window_addr = (unsigned long)ioremap(
-+ ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
-+ if (!info->window_addr) {
-+ printk(KERN_ERR "Failed to ioremap\n");
-+ goto failed;
-+ }
-+
-+ /* For now assume the firmware has setup all relevant firmware
-+ * windows. We don't have enough information to handle this case
-+ * intelligently.
-+ */
-+
-+ /* FIXME select the firmware hub and enable a window to it. */
-+
-+ info->mtd = 0;
-+ info->map.map_priv_1 = info->window_addr;
-+
-+ map_size = ICHX_FWH_REGION_SIZE;
-+ while(!info->mtd && (map_size > 0)) {
-+ info->map.size = map_size;
-+ info->mtd = do_map_probe("jedec_probe", &ichxrom_map.map);
-+ map_size -= 512*1024;
-+ }
-+ if (!info->mtd) {
-+ goto failed;
-+ }
-+ /* I know I can only be a firmware hub here so put
-+ * in the special lock and unlock routines.
-+ */
-+ info->mtd->lock = ichxrom_lock;
-+ info->mtd->unlock = ichxrom_unlock;
-+
-+ info->mtd->owner = THIS_MODULE;
-+ add_mtd_device(info->mtd);
-+
-+ if (info->window_rsrc.parent) {
-+ /*
-+ * Registering the MTD device in iomem may not be possible
-+ * if there is a BIOS "reserved" and BUSY range. If this
-+ * fails then continue anyway.
-+ */
-+ snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
-+ "mtd%d", info->mtd->index);
-+
-+ info->rom_rsrc.name = info->mtd_name;
-+ info->rom_rsrc.start = ICHX_FWH_REGION_START
-+ + ICHX_FWH_REGION_SIZE - map_size;
-+ info->rom_rsrc.end = ICHX_FWH_REGION_START
-+ + ICHX_FWH_REGION_SIZE;
-+ info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+ if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
-+ printk(KERN_ERR MOD_NAME
-+ ": cannot reserve MTD resource\n");
-+ info->rom_rsrc.parent = NULL;
-+ }
-+ }
-+
-+ return 0;
-+
-+ failed:
-+ ichxrom_cleanup(info);
-+ return -ENODEV;
-+}
-+
-+
-+static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
-+{
-+ struct ichxrom_map_info *info = &ichxrom_map;
-+ u16 word;
-+
-+ del_mtd_device(info->mtd);
-+ map_destroy(info->mtd);
-+ info->mtd = 0;
-+ info->map.map_priv_1 = 0;
-+
-+ iounmap((void *)(info->window_addr));
-+ info->window_addr = 0;
-+
-+ /* Disable writes through the rom window */
-+ pci_read_config_word(pdev, BIOS_CNTL, &word);
-+ pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
-+
-+#if RESERVE_MEM_REGION
-+ release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
-+#endif
-+}
-+
-+static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
-+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
-+ PCI_ANY_ID, PCI_ANY_ID, },
-+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
-+ PCI_ANY_ID, PCI_ANY_ID, },
-+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
-+ PCI_ANY_ID, PCI_ANY_ID, },
-+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
-+ PCI_ANY_ID, PCI_ANY_ID, },
-+ { 0, },
-+};
-+
-+MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
-+
-+#if 0
-+static struct pci_driver ichxrom_driver = {
-+ .name = MOD_NAME,
-+ .id_table = ichxrom_pci_tbl,
-+ .probe = ichxrom_init_one,
-+ .remove = ichxrom_remove_one,
-+};
-+#endif
-+
-+static struct pci_dev *mydev;
-+int __init init_ichxrom(void)
-+{
-+ struct pci_dev *pdev;
-+ struct pci_device_id *id;
-+ pdev = 0;
-+ for(id = ichxrom_pci_tbl; id->vendor; id++) {
-+ pdev = pci_find_device(id->vendor, id->device, 0);
-+ if (pdev) {
-+ break;
-+ }
-+ }
-+ if (pdev) {
-+ mydev = pdev;
-+ return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
-+ }
-+ return -ENXIO;
-+#if 0
-+ return pci_module_init(&ichxrom_driver);
-+#endif
-+}
-+
-+static void __exit cleanup_ichxrom(void)
-+{
-+ ichxrom_remove_one(mydev);
-+}
-+
-+module_init(init_ichxrom);
-+module_exit(cleanup_ichxrom);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
-+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/impa7.c linux/drivers/mtd/maps/impa7.c
---- linux-mips-2.4.27/drivers/mtd/maps/impa7.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/impa7.c 2004-11-19 10:25:11.920196600 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Handle mapping of the NOR flash on implementa A7 boards
- *
-@@ -13,6 +13,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -37,75 +38,17 @@
-
- static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
-
--__u8 impa7_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 impa7_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 impa7_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- static struct map_info impa7_map[NUM_FLASHBANKS] = {
- {
-- name: "impA7 NOR Flash Bank #0",
-- size: WINDOW_SIZE0,
-- buswidth: BUSWIDTH,
-- read8: impa7_read8,
-- read16: impa7_read16,
-- read32: impa7_read32,
-- copy_from: impa7_copy_from,
-- write8: impa7_write8,
-- write16: impa7_write16,
-- write32: impa7_write32,
-- copy_to: impa7_copy_to
-+ .name = "impA7 NOR Flash Bank #0",
-+ .size = WINDOW_SIZE0,
-+ .buswidth = BUSWIDTH,
- },
- {
-- name: "impA7 NOR Flash Bank #1",
-- size: WINDOW_SIZE1,
-- buswidth: BUSWIDTH,
-- read8: impa7_read8,
-- read16: impa7_read16,
-- read32: impa7_read32,
-- copy_from: impa7_copy_from,
-- write8: impa7_write8,
-- write16: impa7_write16,
-- write32: impa7_write32,
-- copy_to: impa7_copy_to
-+ .name = "impA7 NOR Flash Bank #1",
-+ .size = WINDOW_SIZE1,
-+ .buswidth = BUSWIDTH,
- },
- };
-
-@@ -117,24 +60,18 @@
- static struct mtd_partition static_partitions[] =
- {
- {
-- name: "FileSystem",
-- size: 0x800000,
-- offset: 0x00000000
-+ .name = "FileSystem",
-+ .size = 0x800000,
-+ .offset = 0x00000000
- },
- };
-
--#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-+static int mtd_parts_nb[NUM_FLASHBANKS];
-+static struct mtd_partition *mtd_parts[NUM_FLASHBANKS];
-
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
- #endif
-
--#endif
--
--static int mtd_parts_nb = 0;
--static struct mtd_partition *mtd_parts = 0;
-+static const char *probes[] = { "cmdlinepart", NULL };
-
- int __init init_impa7(void)
- {
-@@ -146,20 +83,21 @@
- { WINDOW_ADDR0, WINDOW_SIZE0 },
- { WINDOW_ADDR1, WINDOW_SIZE1 },
- };
-- char mtdid[10];
- int devicesfound = 0;
-
- for(i=0; i<NUM_FLASHBANKS; i++)
- {
- printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
- pt[i].size, pt[i].addr);
-- impa7_map[i].map_priv_1 = (unsigned long)
-- ioremap(pt[i].addr, pt[i].size);
-
-- if (!impa7_map[i].map_priv_1) {
-+ impa7_map[i].phys = pt[i].addr;
-+ impa7_map[i].virt = (unsigned long)
-+ ioremap(pt[i].addr, pt[i].size);
-+ if (!impa7_map[i].virt) {
- printk(MSG_PREFIX "failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&impa7_map[i]);
-
- impa7_mtd[i] = 0;
- type = rom_probe_types;
-@@ -167,43 +105,34 @@
- impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
- }
-
-- if (impa7_mtd[i])
-- {
-- impa7_mtd[i]->module = THIS_MODULE;
-- add_mtd_device(impa7_mtd[i]);
-+ if (impa7_mtd[i]) {
-+ impa7_mtd[i]->owner = THIS_MODULE;
- devicesfound++;
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- sprintf(mtdid, MTDID, i);
-- mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i],
-- &mtd_parts,
-- mtdid);
-- if (mtd_parts_nb > 0)
-+ mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i],
-+ probes,
-+ &mtd_parts[i],
-+ 0);
-+ if (mtd_parts_nb[i] > 0) {
- part_type = "command line";
--#endif
-- if (mtd_parts_nb <= 0)
-- {
-- mtd_parts = static_partitions;
-- mtd_parts_nb = NB_OF(static_partitions);
-+ } else {
-+ mtd_parts[i] = static_partitions;
-+ mtd_parts_nb[i] = ARRAY_SIZE(static_partitions);
- part_type = "static";
- }
-- if (mtd_parts_nb <= 0)
-- {
-- printk(KERN_NOTICE MSG_PREFIX
-- "no partition info available\n");
-- }
-- else
-- {
-+
- printk(KERN_NOTICE MSG_PREFIX
- "using %s partition definition\n",
- part_type);
- add_mtd_partitions(impa7_mtd[i],
-- mtd_parts, mtd_parts_nb);
-- }
-+ mtd_parts[i], mtd_parts_nb[i]);
-+#else
-+ add_mtd_device(impa7_mtd[i]);
-+
- #endif
- }
- else
-- iounmap((void *)impa7_map[i].map_priv_1);
-+ iounmap((void *)impa7_map[i].virt);
- }
- return devicesfound == 0 ? -ENXIO : 0;
- }
-@@ -211,17 +140,16 @@
- static void __exit cleanup_impa7(void)
- {
- int i;
-- for (i=0; i<NUM_FLASHBANKS; i++)
-- {
-- if (impa7_mtd[i])
-- {
-+ for (i=0; i<NUM_FLASHBANKS; i++) {
-+ if (impa7_mtd[i]) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ del_mtd_partitions(impa7_mtd[i]);
-+#else
- del_mtd_device(impa7_mtd[i]);
-+#endif
- map_destroy(impa7_mtd[i]);
-- }
-- if (impa7_map[i].map_priv_1)
-- {
-- iounmap((void *)impa7_map[i].map_priv_1);
-- impa7_map[i].map_priv_1 = 0;
-+ iounmap((void *)impa7_map[i].virt);
-+ impa7_map[i].virt = 0;
- }
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/integrator-flash-v24.c linux/drivers/mtd/maps/integrator-flash-v24.c
---- linux-mips-2.4.27/drivers/mtd/maps/integrator-flash-v24.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/integrator-flash-v24.c 2004-11-19 10:25:11.921196448 +0100
-@@ -0,0 +1,258 @@
-+/*======================================================================
-+
-+ drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning
-+
-+ Copyright (C) 2000 ARM Limited
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+ This is access code for flashes using ARM's flash partitioning
-+ standards.
-+
-+ $Id$
-+
-+======================================================================*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+// board specific stuff - sorry, it should be in arch/arm/mach-*.
-+#ifdef CONFIG_ARCH_INTEGRATOR
-+
-+#define FLASH_BASE INTEGRATOR_FLASH_BASE
-+#define FLASH_SIZE INTEGRATOR_FLASH_SIZE
-+
-+#define FLASH_PART_SIZE 0x400000
-+
-+#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
-+#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
-+#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
-+#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
-+
-+/*
-+ * Initialise the flash access systems:
-+ * - Disable VPP
-+ * - Assert WP
-+ * - Set write enable bit in EBI reg
-+ */
-+static void armflash_flash_init(void)
-+{
-+ unsigned int tmp;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+ tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
-+ __raw_writel(tmp, EBI_CSR1);
-+
-+ if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
-+ __raw_writel(0xa05f, EBI_LOCK);
-+ __raw_writel(tmp, EBI_CSR1);
-+ __raw_writel(0, EBI_LOCK);
-+ }
-+}
-+
-+/*
-+ * Shutdown the flash access systems:
-+ * - Disable VPP
-+ * - Assert WP
-+ * - Clear write enable bit in EBI reg
-+ */
-+static void armflash_flash_exit(void)
-+{
-+ unsigned int tmp;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+ /*
-+ * Clear the write enable bit in system controller EBI register.
-+ */
-+ tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
-+ __raw_writel(tmp, EBI_CSR1);
-+
-+ if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
-+ __raw_writel(0xa05f, EBI_LOCK);
-+ __raw_writel(tmp, EBI_CSR1);
-+ __raw_writel(0, EBI_LOCK);
-+ }
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+ unsigned int reg;
-+
-+ if (on)
-+ reg = SC_CTRLC;
-+ else
-+ reg = SC_CTRLS;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+ unsigned int reg;
-+
-+ if (on)
-+ reg = SC_CTRLS;
-+ else
-+ reg = SC_CTRLC;
-+
-+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
-+}
-+#endif
-+
-+#ifdef CONFIG_ARCH_P720T
-+
-+#define FLASH_BASE (0x04000000)
-+#define FLASH_SIZE (64*1024*1024)
-+
-+#define FLASH_PART_SIZE (4*1024*1024)
-+#define FLASH_BLOCK_SIZE (128*1024)
-+
-+static void armflash_flash_init(void)
-+{
-+}
-+
-+static void armflash_flash_exit(void)
-+{
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+}
-+#endif
-+
-+
-+static struct map_info armflash_map =
-+{
-+ .name = "AFS",
-+ .set_vpp = armflash_set_vpp,
-+ .phys = FLASH_BASE,
-+};
-+
-+static struct mtd_info *mtd;
-+static struct mtd_partition *parts;
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-+
-+static int __init armflash_cfi_init(void *base, u_int size)
-+{
-+ int ret;
-+
-+ armflash_flash_init();
-+ armflash_flash_wp(1);
-+
-+ /*
-+ * look for CFI based flash parts fitted to this board
-+ */
-+ armflash_map.size = size;
-+ armflash_map.buswidth = 4;
-+ armflash_map.virt = (unsigned long) base;
-+
-+ simple_map_init(&armflash_map);
-+
-+ /*
-+ * Also, the CFI layer automatically works out what size
-+ * of chips we have, and does the necessary identification
-+ * for us automatically.
-+ */
-+ mtd = do_map_probe("cfi_probe", &armflash_map);
-+ if (!mtd)
-+ return -ENXIO;
-+
-+ mtd->owner = THIS_MODULE;
-+
-+ ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0);
-+ if (ret > 0) {
-+ ret = add_mtd_partitions(mtd, parts, ret);
-+ if (ret)
-+ printk(KERN_ERR "mtd partition registration "
-+ "failed: %d\n", ret);
-+ }
-+
-+ /*
-+ * If we got an error, free all resources.
-+ */
-+ if (ret < 0) {
-+ del_mtd_partitions(mtd);
-+ map_destroy(mtd);
-+ }
-+
-+ return ret;
-+}
-+
-+static void armflash_cfi_exit(void)
-+{
-+ if (mtd) {
-+ del_mtd_partitions(mtd);
-+ map_destroy(mtd);
-+ }
-+ if (parts)
-+ kfree(parts);
-+}
-+
-+static int __init armflash_init(void)
-+{
-+ int err = -EBUSY;
-+ void *base;
-+
-+ if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
-+ goto out;
-+
-+ base = ioremap(FLASH_BASE, FLASH_SIZE);
-+ err = -ENOMEM;
-+ if (base == NULL)
-+ goto release;
-+
-+ err = armflash_cfi_init(base, FLASH_SIZE);
-+ if (err) {
-+ iounmap(base);
-+release:
-+ release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ }
-+out:
-+ return err;
-+}
-+
-+static void __exit armflash_exit(void)
-+{
-+ armflash_cfi_exit();
-+ iounmap((void *)armflash_map.virt);
-+ release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ armflash_flash_exit();
-+}
-+
-+module_init(armflash_init);
-+module_exit(armflash_exit);
-+
-+MODULE_AUTHOR("ARM Ltd");
-+MODULE_DESCRIPTION("ARM Integrator CFI map driver");
-+MODULE_LICENSE("GPL");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/integrator-flash.c linux/drivers/mtd/maps/integrator-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/integrator-flash.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/integrator-flash.c 2004-11-19 10:25:11.923196144 +0100
-@@ -1,8 +1,9 @@
- /*======================================================================
-
-- drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning
-+ drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
-
- Copyright (C) 2000 ARM Limited
-+ Copyright (C) 2003 Deep Blue Solutions Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
-@@ -21,7 +22,7 @@
- This is access code for flashes using ARM's flash partitioning
- standards.
-
-- $Id$
-+ $Id$
-
- ======================================================================*/
-
-@@ -31,268 +32,181 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/ioport.h>
-+#include <linux/device.h>
- #include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-
-+#include <asm/mach/flash.h>
- #include <asm/hardware.h>
- #include <asm/io.h>
- #include <asm/system.h>
-
--extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **);
--
--// board specific stuff - sorry, it should be in arch/arm/mach-*.
--#ifdef CONFIG_ARCH_INTEGRATOR
--
--#define FLASH_BASE INTEGRATOR_FLASH_BASE
--#define FLASH_SIZE INTEGRATOR_FLASH_SIZE
--
--#define FLASH_PART_SIZE 0x400000
--
--#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
--#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
--#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
--#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
--
--/*
-- * Initialise the flash access systems:
-- * - Disable VPP
-- * - Assert WP
-- * - Set write enable bit in EBI reg
-- */
--static void armflash_flash_init(void)
--{
-- unsigned int tmp;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
--
-- tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
-- __raw_writel(tmp, EBI_CSR1);
--
-- if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
-- __raw_writel(0xa05f, EBI_LOCK);
-- __raw_writel(tmp, EBI_CSR1);
-- __raw_writel(0, EBI_LOCK);
-- }
--}
--
--/*
-- * Shutdown the flash access systems:
-- * - Disable VPP
-- * - Assert WP
-- * - Clear write enable bit in EBI reg
-- */
--static void armflash_flash_exit(void)
--{
-- unsigned int tmp;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
--
-- /*
-- * Clear the write enable bit in system controller EBI register.
-- */
-- tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
-- __raw_writel(tmp, EBI_CSR1);
--
-- if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
-- __raw_writel(0xa05f, EBI_LOCK);
-- __raw_writel(tmp, EBI_CSR1);
-- __raw_writel(0, EBI_LOCK);
-- }
--}
--
--static void armflash_flash_wp(int on)
--{
-- unsigned int reg;
--
-- if (on)
-- reg = SC_CTRLC;
-- else
-- reg = SC_CTRLS;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
--}
--
--static void armflash_set_vpp(struct map_info *map, int on)
--{
-- unsigned int reg;
--
-- if (on)
-- reg = SC_CTRLS;
-- else
-- reg = SC_CTRLC;
--
-- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
--}
--#endif
--
- #ifdef CONFIG_ARCH_P720T
--
- #define FLASH_BASE (0x04000000)
- #define FLASH_SIZE (64*1024*1024)
--
--#define FLASH_PART_SIZE (4*1024*1024)
--#define FLASH_BLOCK_SIZE (128*1024)
--
--static void armflash_flash_init(void)
--{
--}
--
--static void armflash_flash_exit(void)
--{
--}
--
--static void armflash_flash_wp(int on)
--{
--}
--
--static void armflash_set_vpp(struct map_info *map, int on)
--{
--}
- #endif
-
--static __u8 armflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(ofs + map->map_priv_2);
--}
--
--static __u16 armflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(ofs + map->map_priv_2);
--}
-+struct armflash_info {
-+ struct flash_platform_data *plat;
-+ struct resource *res;
-+ struct mtd_partition *parts;
-+ struct mtd_info *mtd;
-+ struct map_info map;
-+};
-
--static __u32 armflash_read32(struct map_info *map, unsigned long ofs)
-+static void armflash_set_vpp(struct map_info *map, int on)
- {
-- return readl(ofs + map->map_priv_2);
--}
-+ struct armflash_info *info = container_of(map, struct armflash_info, map);
-
--static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *) (from + map->map_priv_2), len);
-+ if (info->plat && info->plat->set_vpp)
-+ info->plat->set_vpp(on);
- }
-
--static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, adr + map->map_priv_2);
--}
--
--static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, adr + map->map_priv_2);
--}
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-
--static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr)
-+static int armflash_probe(struct device *_dev)
- {
-- writel(d, adr + map->map_priv_2);
--}
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct flash_platform_data *plat = dev->dev.platform_data;
-+ struct resource *res = dev->resource;
-+ unsigned int size = res->end - res->start + 1;
-+ struct armflash_info *info;
-+ int err;
-+ void *base;
-
--static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *) (to + map->map_priv_2), from, len);
--}
-+ info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL);
-+ if (!info) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-
--static struct map_info armflash_map =
--{
-- name: "AFS",
-- read8: armflash_read8,
-- read16: armflash_read16,
-- read32: armflash_read32,
-- copy_from: armflash_copy_from,
-- write8: armflash_write8,
-- write16: armflash_write16,
-- write32: armflash_write32,
-- copy_to: armflash_copy_to,
-- set_vpp: armflash_set_vpp,
--};
-+ memset(info, 0, sizeof(struct armflash_info));
-
--static struct mtd_info *mtd;
--static struct mtd_partition *parts;
-+ info->plat = plat;
-+ if (plat && plat->init) {
-+ err = plat->init();
-+ if (err)
-+ goto no_resource;
-+ }
-
--static int __init armflash_cfi_init(void *base, u_int size)
--{
-- int ret;
-+ info->res = request_mem_region(res->start, size, "armflash");
-+ if (!info->res) {
-+ err = -EBUSY;
-+ goto no_resource;
-+ }
-
-- armflash_flash_init();
-- armflash_flash_wp(1);
-+ base = ioremap(res->start, size);
-+ if (!base) {
-+ err = -ENOMEM;
-+ goto no_mem;
-+ }
-
- /*
- * look for CFI based flash parts fitted to this board
- */
-- armflash_map.size = size;
-- armflash_map.buswidth = 4;
-- armflash_map.map_priv_2 = (unsigned long) base;
-+ info->map.size = size;
-+ info->map.buswidth = plat->width;
-+ info->map.phys = res->start;
-+ info->map.virt = (unsigned long) base;
-+ info->map.name = dev->dev.bus_id;
-+ info->map.set_vpp = armflash_set_vpp;
-+
-+ simple_map_init(&info->map);
-
- /*
- * Also, the CFI layer automatically works out what size
- * of chips we have, and does the necessary identification
- * for us automatically.
- */
-- mtd = do_map_probe("cfi_probe", &armflash_map);
-- if (!mtd)
-- return -ENXIO;
--
-- mtd->module = THIS_MODULE;
--
-- ret = parse_afs_partitions(mtd, &parts);
-- if (ret > 0) {
-- ret = add_mtd_partitions(mtd, parts, ret);
-- if (ret)
-- printk(KERN_ERR "mtd partition registration "
-- "failed: %d\n", ret);
-+ info->mtd = do_map_probe(plat->map_name, &info->map);
-+ if (!info->mtd) {
-+ err = -ENXIO;
-+ goto no_device;
- }
-
-+ info->mtd->owner = THIS_MODULE;
-+
-+ err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
-+ if (err > 0) {
-+ err = add_mtd_partitions(info->mtd, info->parts, err);
-+ if (err)
-+ printk(KERN_ERR
-+ "mtd partition registration failed: %d\n", err);
-+ }
-+
-+ if (err == 0)
-+ dev_set_drvdata(&dev->dev, info);
-+
- /*
- * If we got an error, free all resources.
- */
-- if (ret < 0) {
-- del_mtd_partitions(mtd);
-- map_destroy(mtd);
-+ if (err < 0) {
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
- }
-+ if (info->parts)
-+ kfree(info->parts);
-
-- return ret;
--}
--
--static void armflash_cfi_exit(void)
--{
-- if (mtd) {
-- del_mtd_partitions(mtd);
-- map_destroy(mtd);
-+ no_device:
-+ iounmap(base);
-+ no_mem:
-+ release_mem_region(res->start, size);
-+ no_resource:
-+ if (plat && plat->exit)
-+ plat->exit();
-+ kfree(info);
- }
-- if (parts)
-- kfree(parts);
-+ out:
-+ return err;
- }
-
--static int __init armflash_init(void)
-+static int armflash_remove(struct device *_dev)
- {
-- int err = -EBUSY;
-- void *base;
-+ struct platform_device *dev = to_platform_device(_dev);
-+ struct armflash_info *info = dev_get_drvdata(&dev->dev);
-
-- if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
-- goto out;
-+ dev_set_drvdata(&dev->dev, NULL);
-
-- base = ioremap(FLASH_BASE, FLASH_SIZE);
-- err = -ENOMEM;
-- if (base == NULL)
-- goto release;
-+ if (info) {
-+ if (info->mtd) {
-+ del_mtd_partitions(info->mtd);
-+ map_destroy(info->mtd);
-+ }
-+ if (info->parts)
-+ kfree(info->parts);
-
-- err = armflash_cfi_init(base, FLASH_SIZE);
-- if (err) {
-- iounmap(base);
--release:
-- release_mem_region(FLASH_BASE, FLASH_SIZE);
-+ iounmap((void *)info->map.virt);
-+ release_resource(info->res);
-+ kfree(info->res);
-+
-+ if (info->plat && info->plat->exit)
-+ info->plat->exit();
-+
-+ kfree(info);
- }
--out:
-- return err;
-+
-+ return 0;
-+}
-+
-+static struct device_driver armflash_driver = {
-+ .name = "armflash",
-+ .bus = &platform_bus_type,
-+ .probe = armflash_probe,
-+ .remove = armflash_remove,
-+};
-+
-+static int __init armflash_init(void)
-+{
-+ return driver_register(&armflash_driver);
- }
-
- static void __exit armflash_exit(void)
- {
-- armflash_cfi_exit();
-- iounmap((void *)armflash_map.map_priv_2);
-- release_mem_region(FLASH_BASE, FLASH_SIZE);
-- armflash_flash_exit();
-+ driver_unregister(&armflash_driver);
- }
-
- module_init(armflash_init);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/iq80310.c linux/drivers/mtd/maps/iq80310.c
---- linux-mips-2.4.27/drivers/mtd/maps/iq80310.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/iq80310.c 2004-11-19 10:25:11.924195992 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Mapping for the Intel XScale IQ80310 evaluation board
- *
-@@ -14,6 +14,8 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -26,127 +28,72 @@
-
- static struct mtd_info *mymtd;
-
--static __u8 iq80310_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--static __u16 iq80310_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--static __u32 iq80310_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(__u32 *)(map->map_priv_1 + ofs);
--}
--
--static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
- static struct map_info iq80310_map = {
-- name: "IQ80310 flash",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: iq80310_read8,
-- read16: iq80310_read16,
-- read32: iq80310_read32,
-- copy_from: iq80310_copy_from,
-- write8: iq80310_write8,
-- write16: iq80310_write16,
-- write32: iq80310_write32,
-- copy_to: iq80310_copy_to
-+ .name = "IQ80310 flash",
-+ .size = WINDOW_SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR
- };
-
- static struct mtd_partition iq80310_partitions[4] = {
- {
-- name: "Firmware",
-- size: 0x00080000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Firmware",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
-- name: "Kernel",
-- size: 0x000a0000,
-- offset: 0x00080000,
-+ .name = "Kernel",
-+ .size = 0x000a0000,
-+ .offset = 0x00080000,
- },{
-- name: "Filesystem",
-- size: 0x00600000,
-- offset: 0x00120000
-+ .name = "Filesystem",
-+ .size = 0x00600000,
-+ .offset = 0x00120000
- },{
-- name: "RedBoot",
-- size: 0x000e0000,
-- offset: 0x00720000,
-- mask_flags: MTD_WRITEABLE
-+ .name = "RedBoot",
-+ .size = 0x000e0000,
-+ .offset = 0x00720000,
-+ .mask_flags = MTD_WRITEABLE
- }
- };
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
- static struct mtd_info *mymtd;
- static struct mtd_partition *parsed_parts;
--
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
- static int __init init_iq80310(void)
- {
- struct mtd_partition *parts;
- int nb_parts = 0;
- int parsed_nr_parts = 0;
-- char *part_type = "static";
-+ int ret;
-
-- iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-- if (!iq80310_map.map_priv_1) {
-+ iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ if (!iq80310_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&iq80310_map);
-+
- mymtd = do_map_probe("cfi_probe", &iq80310_map);
- if (!mymtd) {
-- iounmap((void *)iq80310_map.map_priv_1);
-+ iounmap((void *)iq80310_map.virt);
- return -ENXIO;
- }
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-+ ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
-
-- if (ret > 0) {
-- part_type = "RedBoot";
-+ if (ret > 0)
- parsed_nr_parts = ret;
-- }
-- }
--#endif
-
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
- } else {
- parts = iq80310_partitions;
-- nb_parts = NB_OF(iq80310_partitions);
-+ nb_parts = ARRAY_SIZE(iq80310_partitions);
- }
-- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
- }
-@@ -159,8 +106,8 @@
- if (parsed_parts)
- kfree(parsed_parts);
- }
-- if (iq80310_map.map_priv_1)
-- iounmap((void *)iq80310_map.map_priv_1);
-+ if (iq80310_map.virt)
-+ iounmap((void *)iq80310_map.virt);
- }
-
- module_init(init_iq80310);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ixp425.c linux/drivers/mtd/maps/ixp425.c
---- linux-mips-2.4.27/drivers/mtd/maps/ixp425.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/ixp425.c 2004-11-19 10:25:11.925195840 +0100
-@@ -0,0 +1,220 @@
-+/*
-+ * $Id$
-+ *
-+ * drivers/mtd/maps/ixp425.c
-+ *
-+ * MTD Map file for IXP425 based systems. Please do not make per-board
-+ * map driver as the code will be 90% identical. For now just add
-+ * if(machine_is_XXX()) checks to the code. I'll clean this stuff to
-+ * use platform_data in the the future so we can get rid of that too.
-+ *
-+ * Original Author: Intel Corporation
-+ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
-+ *
-+ * Copyright (C) 2002 Intel Corporation
-+ * Copyright (C) 2003 MontaVista Software, Inc.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/ioport.h>
-+#include <asm/io.h>
-+#include <asm/mach-types.h>
-+
-+#include <linux/reboot.h>
-+
-+#define WINDOW_ADDR 0x50000000
-+#define BUSWIDTH 2
-+
-+#ifndef __ARMEB__
-+#define BYTE0(h) ((h) & 0xFF)
-+#define BYTE1(h) (((h) >> 8) & 0xFF)
-+#else
-+#define BYTE0(h) (((h) >> 8) & 0xFF)
-+#define BYTE1(h) ((h) & 0xFF)
-+#endif
-+
-+static __u16
-+ixp425_read16(struct map_info *map, unsigned long ofs)
-+{
-+ return *(__u16 *) (map->map_priv_1 + ofs);
-+}
-+
-+/*
-+ * The IXP425 expansion bus only allows 16-bit wide acceses
-+ * when attached to a 16-bit wide device (such as the 28F128J3A),
-+ * so we can't just memcpy_fromio().
-+ */
-+static void
-+ixp425_copy_from(struct map_info *map, void *to,
-+ unsigned long from, ssize_t len)
-+{
-+ int i;
-+ u8 *dest = (u8 *) to;
-+ u16 *src = (u16 *) (map->map_priv_1 + from);
-+ u16 data;
-+
-+ for (i = 0; i < (len / 2); i++) {
-+ data = src[i];
-+ dest[i * 2] = BYTE0(data);
-+ dest[i * 2 + 1] = BYTE1(data);
-+ }
-+
-+ if (len & 1)
-+ dest[len - 1] = BYTE0(src[i]);
-+}
-+
-+static void
-+ixp425_write16(struct map_info *map, __u16 d, unsigned long adr)
-+{
-+ *(__u16 *) (map->map_priv_1 + adr) = d;
-+}
-+
-+static struct map_info ixp425_map = {
-+ .name = "IXP425 Flash",
-+ .buswidth = BUSWIDTH,
-+ .read16 = ixp425_read16,
-+ .copy_from = ixp425_copy_from,
-+ .write16 = ixp425_write16,
-+};
-+
-+/*
-+ * Put flash back in read mode so RedBoot can boot properly.
-+ */
-+int ixp425_mtd_reboot(struct notifier_block *n, unsigned long code, void *p)
-+{
-+ if (code != SYS_RESTART)
-+ return NOTIFY_DONE;
-+
-+ ixp425_write16(&ixp425_map, 0xff, 0x55 * 0x2);
-+ return NOTIFY_DONE;
-+}
-+
-+static struct notifier_block ixp425_mtd_notifier = {
-+ notifier_call:ixp425_mtd_reboot,
-+ next:NULL,
-+ priority:0
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static struct mtd_partition ixp425_partitions[] = {
-+ {
-+ .name = "image",
-+ .offset = 0x00040000,
-+ .size = 0x00400000,
-+ }, {
-+ .name = "user",
-+ .offset = 0x00440000,
-+ .size = MTDPART_SIZ_FULL
-+ }
-+};
-+
-+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-+
-+static struct mtd_info *ixp425_mtd;
-+static struct resource *mtd_resource;
-+
-+static void
-+ixp425_exit(void)
-+{
-+ if (ixp425_mtd) {
-+ del_mtd_partitions(ixp425_mtd);
-+ map_destroy(ixp425_mtd);
-+ }
-+ if (ixp425_map.map_priv_1)
-+ iounmap((void *) ixp425_map.map_priv_1);
-+ if (mtd_resource)
-+ release_mem_region(WINDOW_ADDR, ixp425_map.size);
-+
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+
-+ unregister_reboot_notifier(&ixp425_mtd_notifier);
-+
-+ /* Disable flash write */
-+ *IXP425_EXP_CS0 &= ~IXP425_FLASH_WRITABLE;
-+
-+ if(machine_is_adi_coyote())
-+ *IXP425_EXP_CS1 &= ~IXP425_FLASH_WRITABLE;
-+}
-+
-+static int __init
-+ixp425_init(void)
-+{
-+ int res = -1, npart;
-+
-+ /* Enable flash write */
-+ *IXP425_EXP_CS0 |= IXP425_FLASH_WRITABLE;
-+
-+ /*
-+ * Coyote requires CS1 write to be enabled and has 32MB flash.
-+ * This will move to the platform init code in 2.6
-+ */
-+ if(machine_is_adi_coyote()) {
-+ *IXP425_EXP_CS1 |= IXP425_FLASH_WRITABLE;
-+ ixp425_map.size = 0x02000000;
-+ } else
-+ ixp425_map.size = 0x01000000;
-+
-+ ixp425_map.map_priv_1 = 0;
-+ mtd_resource =
-+ request_mem_region(WINDOW_ADDR, ixp425_map.size, "IXP425 Flash");
-+ if (!mtd_resource) {
-+ printk(KERN_ERR
-+ "ixp425 flash: Could not request mem region.\n");
-+ res = -ENOMEM;
-+ goto Error;
-+ }
-+
-+ ixp425_map.map_priv_1 =
-+ (unsigned long) ioremap(WINDOW_ADDR, ixp425_map.size);
-+ if (!ixp425_map.map_priv_1) {
-+ printk("ixp425 Flash: Failed to map IO region. (ioremap)\n");
-+ res = -EIO;
-+ goto Error;
-+ }
-+
-+ ixp425_mtd = do_map_probe("cfi_probe", &ixp425_map);
-+ if (!ixp425_mtd) {
-+ res = -ENXIO;
-+ goto Error;
-+ }
-+ ixp425_mtd->owner = THIS_MODULE;
-+
-+ /* Try to parse RedBoot partitions */
-+ npart = parse_mtd_partitions(ixp425_mtd, probes, &parsed_parts, 0);
-+ if (npart > 0)
-+ res = add_mtd_partitions(ixp425_mtd, parsed_parts, npart);
-+ else {
-+ printk("IXP425 Flash: Using static MTD partitions.\n");
-+ res = add_mtd_partitions(ixp425_mtd, ixp425_partitions,
-+ NB_OF(ixp425_partitions));
-+ }
-+
-+ if (res)
-+ goto Error;
-+
-+ register_reboot_notifier(&ixp425_mtd_notifier);
-+
-+ return res;
-+
-+Error:
-+ ixp425_exit();
-+ return res;
-+}
-+
-+module_init(ixp425_init);
-+module_exit(ixp425_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("MTD map driver for ixp425 evaluation board");
-+MODULE_AUTHOR("Deepak Saxena");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/l440gx.c linux/drivers/mtd/maps/l440gx.c
---- linux-mips-2.4.27/drivers/mtd/maps/l440gx.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/l440gx.c 2004-11-19 10:25:11.927195536 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * BIOS Flash chip on Intel 440GX board.
- *
-@@ -9,6 +9,7 @@
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -27,48 +28,6 @@
-
- static struct mtd_info *mymtd;
-
--__u8 l440gx_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 l440gx_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 l440gx_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- /* Is this really the vpp port? */
- void l440gx_set_vpp(struct map_info *map, int vpp)
-@@ -85,22 +44,15 @@
- }
-
- struct map_info l440gx_map = {
-- name: "L440GX BIOS",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: l440gx_read8,
-- read16: l440gx_read16,
-- read32: l440gx_read32,
-- copy_from: l440gx_copy_from,
-- write8: l440gx_write8,
-- write16: l440gx_write16,
-- write32: l440gx_write32,
-- copy_to: l440gx_copy_to,
-+ .name = "L440GX BIOS",
-+ .size = WINDOW_SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR,
- #if 0
- /* FIXME verify that this is the
- * appripriate code for vpp enable/disable
- */
-- set_vpp: l440gx_set_vpp
-+ .set_vpp = l440gx_set_vpp
- #endif
- };
-
-@@ -113,7 +65,6 @@
- dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
-
--
- pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
-
-@@ -122,15 +73,14 @@
- return -ENODEV;
- }
-
-+ l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
-
-- l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
--
-- if (!l440gx_map.map_priv_1) {
-+ if (!l440gx_map.virt) {
- printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
- return -ENOMEM;
- }
--
-- printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1);
-+ simple_map_init(&l440gx_map);
-+ printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt);
-
- /* Setup the pm iobase resource
- * This code should move into some kind of generic bridge
-@@ -153,7 +103,7 @@
- /* Allocate the resource region */
- if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
- printk(KERN_WARNING "Could not allocate pm iobase resource\n");
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap((void *)l440gx_map.virt);
- return -ENXIO;
- }
- }
-@@ -181,13 +131,13 @@
- mymtd = do_map_probe("map_rom", &l440gx_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- add_mtd_device(mymtd);
- return 0;
- }
-
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap((void *)l440gx_map.virt);
- return -ENXIO;
- }
-
-@@ -196,7 +146,7 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
-
-- iounmap((void *)l440gx_map.map_priv_1);
-+ iounmap((void *)l440gx_map.virt);
- }
-
- module_init(init_l440gx);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/lasat.c linux/drivers/mtd/maps/lasat.c
---- linux-mips-2.4.27/drivers/mtd/maps/lasat.c 2003-08-18 04:59:02.000000000 +0200
-+++ linux/drivers/mtd/maps/lasat.c 2004-11-19 10:25:11.928195384 +0100
-@@ -1,11 +1,20 @@
- /*
-- * Flash device on lasat 100 and 200 boards
-+ * Flash device on Lasat 100 and 200 boards
-+ *
-+ * (C) 2002 Brian Murphy <brian@murphy.dk>
-+ *
-+ * 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.
-+ *
-+ * $Id$
- *
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -13,123 +22,80 @@
- #include <linux/config.h>
- #include <asm/lasat/lasat.h>
-
--static struct mtd_info *mymtd;
--
--static __u8 sp_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sp_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sp_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-+static struct mtd_info *lasat_mtd;
-
--static void sp_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void sp_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void sp_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+static struct mtd_partition partition_info[LASAT_MTD_LAST];
-+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
-
--static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+static void lasat_set_vpp(struct map_info *map, int vpp)
- {
-- memcpy_toio(map->map_priv_1 + to, from, len);
-+ if (vpp)
-+ *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
-+ else
-+ *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit);
- }
-
--static struct map_info sp_map = {
-- name: "SP flash",
-- buswidth: 4,
-- read8: sp_read8,
-- read16: sp_read16,
-- read32: sp_read32,
-- copy_from: sp_copy_from,
-- write8: sp_write8,
-- write16: sp_write16,
-- write32: sp_write32,
-- copy_to: sp_copy_to
-+static struct map_info lasat_map = {
-+ .name = "LASAT flash",
-+ .buswidth = 4,
-+ .set_vpp = lasat_set_vpp
- };
-
--static struct mtd_partition partition_info[LASAT_MTD_LAST];
--static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Config", "Filesystem"};
--
--static int __init init_sp(void)
-+static int __init init_lasat(void)
- {
- int i;
-- int nparts = 0;
-- /* this does not play well with the old flash code which
-- * protects and uprotects the flash when necessary */
-+ /* since we use AMD chips and set_vpp is not implimented
-+ * for these (yet) we still have to permanently enable flash write */
- printk(KERN_NOTICE "Unprotecting flash\n");
-- *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
-+ ENABLE_VPP((&lasat_map));
-
-- sp_map.map_priv_1 = ioremap_nocache(
-- lasat_flash_partition_start(LASAT_MTD_BOOTLOADER),
-- lasat_board_info.li_flash_size);
-- sp_map.size = lasat_board_info.li_flash_size;
-+ lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
-+ lasat_map.virt = (unsigned long)ioremap_nocache(
-+ lasat_map.phys, lasat_board_info.li_flash_size);
-+ lasat_map.size = lasat_board_info.li_flash_size;
-
-- printk(KERN_NOTICE "sp flash device: %lx at %lx\n",
-- sp_map.size, sp_map.map_priv_1);
-+ simple_map_init(&lasat_map);
-
- for (i=0; i < LASAT_MTD_LAST; i++)
- partition_info[i].name = lasat_mtd_partnames[i];
-
-- mymtd = do_map_probe("cfi_probe", &sp_map);
-- if (mymtd) {
-+ lasat_mtd = do_map_probe("cfi_probe", &lasat_map);
-+
-+ if (!lasat_mtd)
-+ lasat_mtd = do_map_probe("jedec_probe", &lasat_map);
-+
-+ if (lasat_mtd) {
- u32 size, offset = 0;
-
-- mymtd->module = THIS_MODULE;
-+ lasat_mtd->owner = THIS_MODULE;
-
- for (i=0; i < LASAT_MTD_LAST; i++) {
- size = lasat_flash_partition_size(i);
-- if (size != 0) {
-- nparts++;
- partition_info[i].size = size;
- partition_info[i].offset = offset;
- offset += size;
- }
-- }
-
-- add_mtd_partitions( mymtd, partition_info, nparts );
-+ add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST );
- return 0;
- }
-
- return -ENXIO;
- }
-
--static void __exit cleanup_sp(void)
-+static void __exit cleanup_lasat(void)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-+ if (lasat_mtd) {
-+ del_mtd_partitions(lasat_mtd);
-+ map_destroy(lasat_mtd);
- }
-- if (sp_map.map_priv_1) {
-- sp_map.map_priv_1 = 0;
-+ if (lasat_map.virt) {
-+ lasat_map.virt = 0;
- }
- }
-
--module_init(init_sp);
--module_exit(cleanup_sp);
-+module_init(init_lasat);
-+module_exit(cleanup_lasat);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/lubbock-flash.c linux/drivers/mtd/maps/lubbock-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/lubbock-flash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/lubbock-flash.c 2004-11-19 10:25:11.930195080 +0100
-@@ -0,0 +1,151 @@
-+/*
-+ * $Id$
-+ *
-+ * Map driver for the Lubbock developer platform.
-+ *
-+ * Author: Nicolas Pitre
-+ * Copyright: (C) 2001 MontaVista Software Inc.
-+ *
-+ * 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/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/hardware.h>
-+
-+
-+#define ROM_ADDR 0x00000000
-+#define FLASH_ADDR 0x04000000
-+
-+#define WINDOW_SIZE 64*1024*1024
-+
-+static struct map_info lubbock_maps[2] = { {
-+ .size = WINDOW_SIZE,
-+ .phys = 0x00000000,
-+}, {
-+ .size = WINDOW_SIZE,
-+ .phys = 0x04000000,
-+} };
-+
-+static struct mtd_partition lubbock_partitions[] = {
-+ {
-+ .name = "Bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },{
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00040000,
-+ },{
-+ .name = "Filesystem",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00140000
-+ }
-+};
-+
-+static struct mtd_info *mymtds[2];
-+static struct mtd_partition *parsed_parts[2];
-+static int nr_parsed_parts[2];
-+
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static int __init init_lubbock(void)
-+{
-+ int flashboot = (CONF_SWITCHES & 1);
-+ int ret = 0, i;
-+
-+ lubbock_maps[0].buswidth = lubbock_maps[1].buswidth =
-+ (BOOT_DEF & 1) ? 2 : 4;
-+
-+ /* Compensate for the nROMBT switch which swaps the flash banks */
-+ printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
-+ flashboot?"Flash":"ROM", flashboot);
-+
-+ lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
-+ lubbock_maps[flashboot].name = "Lubbock Boot ROM";
-+
-+ for (i = 0; i < 2; i++) {
-+ lubbock_maps[i].virt = (unsigned long)__ioremap(lubbock_maps[i].phys, WINDOW_SIZE, 0);
-+ if (!lubbock_maps[i].virt) {
-+ printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
-+ if (!ret)
-+ ret = -ENOMEM;
-+ continue;
-+ }
-+ simple_map_init(&lubbock_maps[i]);
-+
-+ printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n",
-+ lubbock_maps[i].name, lubbock_maps[i].phys,
-+ lubbock_maps[i].buswidth * 8);
-+
-+ mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-+
-+ if (!mymtds[i]) {
-+ iounmap((void *)lubbock_maps[i].virt);
-+ if (!ret)
-+ ret = -EIO;
-+ continue;
-+ }
-+ mymtds[i]->owner = THIS_MODULE;
-+
-+ int ret = parse_mtd_partitions(mymtds[i], probes,
-+ &parsed_parts[i], 0);
-+
-+ if (ret > 0)
-+ nr_parsed_parts[i] = ret;
-+ }
-+
-+ if (!mymtds[0] && !mymtds[1])
-+ return ret;
-+
-+ for (i = 0; i < 2; i++) {
-+ if (!mymtds[i]) {
-+ printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
-+ } else if (nr_parsed_parts[i]) {
-+ add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
-+ } else if (!i) {
-+ printk("Using static partitions on %s\n", lubbock_maps[i].name);
-+ add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions));
-+ } else {
-+ printk("Registering %s as whole device\n", lubbock_maps[i].name);
-+ add_mtd_device(mymtds[i]);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static void __exit cleanup_lubbock(void)
-+{
-+ int i;
-+ for (i = 0; i < 2; i++) {
-+ if (!mymtds[i])
-+ continue;
-+
-+ if (nr_parsed_parts[i] || !i)
-+ del_mtd_partitions(mymtds[i]);
-+ else
-+ del_mtd_device(mymtds[i]);
-+
-+ map_destroy(mymtds[i]);
-+ iounmap((void *)lubbock_maps[i].virt);
-+
-+ if (parsed_parts[i])
-+ kfree(parsed_parts[i]);
-+ }
-+}
-+
-+module_init(init_lubbock);
-+module_exit(cleanup_lubbock);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-+MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/map_funcs.c linux/drivers/mtd/maps/map_funcs.c
---- linux-mips-2.4.27/drivers/mtd/maps/map_funcs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/map_funcs.c 2004-11-19 10:25:11.931194928 +0100
-@@ -0,0 +1,96 @@
-+/*
-+ * $Id$
-+ *
-+ * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
-+ * is enabled.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/string.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/map.h>
-+
-+static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readb(map->virt + ofs);
-+}
-+
-+static u16 simple_map_read16(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readw(map->virt + ofs);
-+}
-+
-+static u32 simple_map_read32(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readl(map->virt + ofs);
-+}
-+
-+static u64 simple_map_read64(struct map_info *map, unsigned long ofs)
-+{
-+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-+ BUG();
-+ return 0;
-+#else
-+ return __raw_readll(map->virt + ofs);
-+#endif
-+}
-+
-+static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs)
-+{
-+ __raw_writeb(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs)
-+{
-+ __raw_writew(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs)
-+{
-+ __raw_writel(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs)
-+{
-+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-+ BUG();
-+#else
-+ __raw_writell(datum, map->virt + ofs);
-+ mb();
-+#endif /* CFI_B8 */
-+}
-+
-+static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ memcpy_fromio(to, map->virt + from, len);
-+}
-+
-+static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ memcpy_toio(map->virt + to, from, len);
-+}
-+
-+void simple_map_init(struct map_info *map)
-+{
-+ map->read8 = simple_map_read8;
-+ map->read16 = simple_map_read16;
-+ map->read32 = simple_map_read32;
-+ map->read64 = simple_map_read64;
-+ map->write8 = simple_map_write8;
-+ map->write16 = simple_map_write16;
-+ map->write32 = simple_map_write32;
-+ map->write64 = simple_map_write64;
-+ map->copy_from = simple_map_copy_from;
-+ map->copy_to = simple_map_copy_to;
-+}
-+
-+EXPORT_SYMBOL(simple_map_init);
-+
-+MODULE_LICENSE("GPL");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/mbx860.c linux/drivers/mtd/maps/mbx860.c
---- linux-mips-2.4.27/drivers/mtd/maps/mbx860.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/mbx860.c 2004-11-19 10:25:11.933194624 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Handle mapping of the flash on MBX860 boards
- *
-@@ -15,6 +15,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -36,91 +37,46 @@
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
-- { name: "MBX flash BOOT partition",
-- offset: 0,
-- size: BOOT_PARTITION_SIZE_KiB*1024 },
-- { name: "MBX flash DATA partition",
-- offset: BOOT_PARTITION_SIZE_KiB*1024,
-- size: (KERNEL_PARTITION_SIZE_KiB)*1024 },
-- { name: "MBX flash APPLICATION partition",
-- offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
-+ { .name = "MBX flash BOOT partition",
-+ .offset = 0,
-+ .size = BOOT_PARTITION_SIZE_KiB*1024 },
-+ { .name = "MBX flash DATA partition",
-+ .offset = BOOT_PARTITION_SIZE_KiB*1024,
-+ .size = (KERNEL_PARTITION_SIZE_KiB)*1024 },
-+ { .name = "MBX flash APPLICATION partition",
-+ .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
- };
-
-
- static struct mtd_info *mymtd;
-
--__u8 mbx_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--__u16 mbx_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--__u32 mbx_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void mbx_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--void mbx_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--void mbx_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
- struct map_info mbx_map = {
-- name: "MBX flash",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: mbx_read8,
-- read16: mbx_read16,
-- read32: mbx_read32,
-- copy_from: mbx_copy_from,
-- write8: mbx_write8,
-- write16: mbx_write16,
-- write32: mbx_write32,
-- copy_to: mbx_copy_to
-+ .name = "MBX flash",
-+ .size = WINDOW_SIZE,
-+ .phys = WINDOW_ADDR,
-+ .buswidth = 4,
- };
-
- int __init init_mbx(void)
- {
-- printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-- mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+ printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-+ mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-
-- if (!mbx_map.map_priv_1) {
-+ if (!mbx_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&mbx_map);
-+
- mymtd = do_map_probe("jedec_probe", &mbx_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_device(mymtd);
- add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
- return 0;
- }
-
-- iounmap((void *)mbx_map.map_priv_1);
-+ iounmap((void *)mbx_map.virt);
- return -ENXIO;
- }
-
-@@ -130,9 +86,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (mbx_map.map_priv_1) {
-- iounmap((void *)mbx_map.map_priv_1);
-- mbx_map.map_priv_1 = 0;
-+ if (mbx_map.virt) {
-+ iounmap((void *)mbx_map.virt);
-+ mbx_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/mpc1211.c linux/drivers/mtd/maps/mpc1211.c
---- linux-mips-2.4.27/drivers/mtd/maps/mpc1211.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/mpc1211.c 2004-11-19 10:25:11.934194472 +0100
-@@ -0,0 +1,79 @@
-+/*
-+ * Flash on MPC-1211
-+ *
-+ * (C) 2002 Interface, Saito.K & Jeanne
-+ *
-+ * GPL'd
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+
-+static struct mtd_info *flash_mtd;
-+static struct mtd_partition *parsed_parts;
-+
-+struct map_info mpc1211_flash_map = {
-+ .name = "MPC-1211 FLASH",
-+ .size = 0x80000,
-+ .buswidth = 1,
-+};
-+
-+static struct mtd_partition mpc1211_partitions[] = {
-+ {
-+ .name = "IPL & ETH-BOOT",
-+ .offset = 0x00000000,
-+ .size = 0x10000,
-+ },
-+ {
-+ .name = "Flash FS",
-+ .offset = 0x00010000,
-+ .size = MTDPART_SIZ_FULL,
-+ }
-+};
-+
-+static int __init init_mpc1211_maps(void)
-+{
-+ int nr_parts;
-+
-+ mpc1211_flash_map.phys = 0;
-+ mpc1211_flash_map.virt = P2SEGADDR(0);
-+
-+ simple_map_init(&mpc1211_flash_map);
-+
-+ printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
-+ flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map);
-+ if (!flash_mtd) {
-+ printk(KERN_NOTICE "Flash chips not detected at either possible location.\n");
-+ return -ENXIO;
-+ }
-+ printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff);
-+ flash_mtd->module = THIS_MODULE;
-+
-+ parsed_parts = mpc1211_partitions;
-+ nr_parts = ARRAY_SIZE(mpc1211_partitions);
-+
-+ add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
-+ return 0;
-+}
-+
-+static void __exit cleanup_mpc1211_maps(void)
-+{
-+ if (parsed_parts)
-+ del_mtd_partitions(flash_mtd);
-+ else
-+ del_mtd_device(flash_mtd);
-+ map_destroy(flash_mtd);
-+}
-+
-+module_init(init_mpc1211_maps);
-+module_exit(cleanup_mpc1211_maps);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Saito.K & Jeanne <ksaito@interface.co.jp>");
-+MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/netsc520.c linux/drivers/mtd/maps/netsc520.c
---- linux-mips-2.4.27/drivers/mtd/maps/netsc520.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/netsc520.c 2004-11-19 10:25:11.935194320 +0100
-@@ -3,7 +3,7 @@
- * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
- * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -27,6 +27,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -50,95 +51,41 @@
- ** recoverable afterwards.
- */
-
--static __u8 netsc520_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 netsc520_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 netsc520_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
- /* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
- {
-- name: "NetSc520 boot kernel",
-- offset: 0,
-- size: 0xc0000
-+ .name = "NetSc520 boot kernel",
-+ .offset = 0,
-+ .size = 0xc0000
- },
- {
-- name: "NetSc520 Low BIOS",
-- offset: 0xc0000,
-- size: 0x40000
-+ .name = "NetSc520 Low BIOS",
-+ .offset = 0xc0000,
-+ .size = 0x40000
- },
- {
-- name: "NetSc520 file system",
-- offset: 0x100000,
-- size: 0xe80000
-+ .name = "NetSc520 file system",
-+ .offset = 0x100000,
-+ .size = 0xe80000
- },
- {
-- name: "NetSc520 High BIOS",
-- offset: 0xf80000,
-- size: 0x80000
-+ .name = "NetSc520 High BIOS",
-+ .offset = 0xf80000,
-+ .size = 0x80000
- },
- };
- #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
--/*
-- * If no idea what is going on here. This is taken from the FlashFX stuff.
-- */
--#define ROMCS 1
--
--
- #define WINDOW_SIZE 0x00100000
- #define WINDOW_ADDR 0x00200000
-
- static struct map_info netsc520_map = {
-- name: "netsc520 Flash Bank",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: netsc520_read8,
-- read16: netsc520_read16,
-- read32: netsc520_read32,
-- copy_from: netsc520_copy_from,
-- write8: netsc520_write8,
-- write16: netsc520_write16,
-- write32: netsc520_write32,
-- copy_to: netsc520_copy_to,
-- map_priv_2: WINDOW_ADDR
-+ .name = "netsc520 Flash Bank",
-+ .size = WINDOW_SIZE,
-+ .buswidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- #define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info))
-@@ -147,13 +94,16 @@
-
- static int __init init_netsc520(void)
- {
-- printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2);
-- netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size);
-+ printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
-+ netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size);
-
-- if (!netsc520_map.map_priv_1) {
-+ if (!netsc520_map.virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+
-+ simple_map_init(&netsc520_map);
-+
- mymtd = do_map_probe("cfi_probe", &netsc520_map);
- if(!mymtd)
- mymtd = do_map_probe("map_ram", &netsc520_map);
-@@ -161,11 +111,11 @@
- mymtd = do_map_probe("map_rom", &netsc520_map);
-
- if (!mymtd) {
-- iounmap((void *)netsc520_map.map_priv_1);
-+ iounmap((void *)netsc520_map.virt);
- return -ENXIO;
- }
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
- return 0;
- }
-@@ -176,9 +126,9 @@
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-- if (netsc520_map.map_priv_1) {
-- iounmap((void *)netsc520_map.map_priv_1);
-- netsc520_map.map_priv_1 = 0;
-+ if (netsc520_map.virt) {
-+ iounmap((void *)netsc520_map.virt);
-+ netsc520_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/nettel.c linux/drivers/mtd/maps/nettel.c
---- linux-mips-2.4.27/drivers/mtd/maps/nettel.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/nettel.c 2004-11-19 10:25:11.937194016 +0100
-@@ -6,7 +6,7 @@
- * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
- * (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
- *
-- * $Id$
-+ * $Id$
- */
-
- /****************************************************************************/
-@@ -59,128 +59,72 @@
-
- /****************************************************************************/
-
--static __u8 nettel_read8(struct map_info *map, unsigned long ofs)
--{
-- return(readb(map->map_priv_1 + ofs));
--}
--
--static __u16 nettel_read16(struct map_info *map, unsigned long ofs)
--{
-- return(readw(map->map_priv_1 + ofs));
--}
--
--static __u32 nettel_read32(struct map_info *map, unsigned long ofs)
--{
-- return(readl(map->map_priv_1 + ofs));
--}
--
--static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
- /****************************************************************************/
-
- #ifdef CONFIG_MTD_CFI_INTELEXT
- static struct map_info nettel_intel_map = {
-- name: "SnapGear Intel",
-- size: 0,
-- buswidth: INTEL_BUSWIDTH,
-- read8: nettel_read8,
-- read16: nettel_read16,
-- read32: nettel_read32,
-- copy_from: nettel_copy_from,
-- write8: nettel_write8,
-- write16: nettel_write16,
-- write32: nettel_write32,
-- copy_to: nettel_copy_to
-+ .name = "SnapGear Intel",
-+ .size = 0,
-+ .buswidth = INTEL_BUSWIDTH,
- };
-
- static struct mtd_partition nettel_intel_partitions[] = {
- {
-- name: "SnapGear kernel",
-- offset: 0,
-- size: 0x000e0000
-+ .name = "SnapGear kernel",
-+ .offset = 0,
-+ .size = 0x000e0000
- },
- {
-- name: "SnapGear filesystem",
-- offset: 0x00100000,
-+ .name = "SnapGear filesystem",
-+ .offset = 0x00100000,
- },
- {
-- name: "SnapGear config",
-- offset: 0x000e0000,
-- size: 0x00020000
-+ .name = "SnapGear config",
-+ .offset = 0x000e0000,
-+ .size = 0x00020000
- },
- {
-- name: "SnapGear Intel",
-- offset: 0
-+ .name = "SnapGear Intel",
-+ .offset = 0
- },
- {
-- name: "SnapGear BIOS Config",
-- offset: 0x007e0000,
-- size: 0x00020000
-+ .name = "SnapGear BIOS Config",
-+ .offset = 0x007e0000,
-+ .size = 0x00020000
- },
- {
-- name: "SnapGear BIOS",
-- offset: 0x007e0000,
-- size: 0x00020000
-+ .name = "SnapGear BIOS",
-+ .offset = 0x007e0000,
-+ .size = 0x00020000
- },
- };
- #endif
-
- static struct map_info nettel_amd_map = {
-- name: "SnapGear AMD",
-- size: AMD_WINDOW_MAXSIZE,
-- buswidth: AMD_BUSWIDTH,
-- read8: nettel_read8,
-- read16: nettel_read16,
-- read32: nettel_read32,
-- copy_from: nettel_copy_from,
-- write8: nettel_write8,
-- write16: nettel_write16,
-- write32: nettel_write32,
-- copy_to: nettel_copy_to
-+ .name = "SnapGear AMD",
-+ .size = AMD_WINDOW_MAXSIZE,
-+ .buswidth = AMD_BUSWIDTH,
- };
-
- static struct mtd_partition nettel_amd_partitions[] = {
- {
-- name: "SnapGear BIOS config",
-- offset: 0x000e0000,
-- size: 0x00010000
-+ .name = "SnapGear BIOS config",
-+ .offset = 0x000e0000,
-+ .size = 0x00010000
- },
- {
-- name: "SnapGear BIOS",
-- offset: 0x000f0000,
-- size: 0x00010000
-+ .name = "SnapGear BIOS",
-+ .offset = 0x000f0000,
-+ .size = 0x00010000
- },
- {
-- name: "SnapGear AMD",
-- offset: 0
-+ .name = "SnapGear AMD",
-+ .offset = 0
- },
- {
-- name: "SnapGear high BIOS",
-- offset: 0x001f0000,
-- size: 0x00010000
-+ .name = "SnapGear high BIOS",
-+ .offset = 0x001f0000,
-+ .size = 0x00010000
- }
- };
-
-@@ -328,18 +272,20 @@
- *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
- __asm__ ("wbinvd");
-
-- nettel_amd_map.map_priv_1 = (unsigned long)
-+ nettel_amd_map.phys = amdaddr;
-+ nettel_amd_map.virt = (unsigned long)
- ioremap_nocache(amdaddr, maxsize);
-- if (!nettel_amd_map.map_priv_1) {
-+ if (!nettel_amd_map.virt) {
- printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
- return(-EIO);
- }
-+ simple_map_init(&nettel_amd_map);
-
- if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
- printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
- amd_mtd->size>>10);
-
-- amd_mtd->module = THIS_MODULE;
-+ amd_mtd->owner = THIS_MODULE;
-
- /* The high BIOS partition is only present for 2MB units */
- num_amd_partitions = NUM_AMD_PARTITIONS;
-@@ -387,8 +333,8 @@
-
- /* Destroy useless AMD MTD mapping */
- amd_mtd = NULL;
-- iounmap((void *) nettel_amd_map.map_priv_1);
-- nettel_amd_map.map_priv_1 = (unsigned long) NULL;
-+ iounmap((void *) nettel_amd_map.virt);
-+ nettel_amd_map.virt = (unsigned long) NULL;
- #else
- /* Only AMD flash supported */
- return(-ENXIO);
-@@ -411,16 +357,18 @@
-
- /* Probe for the the size of the first Intel flash */
- nettel_intel_map.size = maxsize;
-- nettel_intel_map.map_priv_1 = (unsigned long)
-+ nettel_intel_map.phys = intel0addr;
-+ nettel_intel_map.virt = (unsigned long)
- ioremap_nocache(intel0addr, maxsize);
-- if (!nettel_intel_map.map_priv_1) {
-+ if (!nettel_intel_map.virt) {
- printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
- return(-EIO);
- }
-+ simple_map_init(&nettel_intel_map);
-
- intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
- if (! intel_mtd) {
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ iounmap((void *) nettel_intel_map.virt);
- return(-ENXIO);
- }
-
-@@ -441,19 +389,19 @@
- /* Delete the old map and probe again to do both chips */
- map_destroy(intel_mtd);
- intel_mtd = NULL;
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ iounmap((void *) nettel_intel_map.virt);
-
- nettel_intel_map.size = maxsize;
-- nettel_intel_map.map_priv_1 = (unsigned long)
-+ nettel_intel_map.virt = (unsigned long)
- ioremap_nocache(intel0addr, maxsize);
-- if (!nettel_intel_map.map_priv_1) {
-+ if (!nettel_intel_map.virt) {
- printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
- return(-EIO);
- }
-
- intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
- if (! intel_mtd) {
-- iounmap((void *) nettel_intel_map.map_priv_1);
-+ iounmap((void *) nettel_intel_map.virt);
- return(-ENXIO);
- }
-
-@@ -468,7 +416,7 @@
- printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
- (intel_mtd->size >> 10));
-
-- intel_mtd->module = THIS_MODULE;
-+ intel_mtd->owner = THIS_MODULE;
-
- #ifndef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
-@@ -523,18 +471,18 @@
- del_mtd_partitions(amd_mtd);
- map_destroy(amd_mtd);
- }
-- if (nettel_amd_map.map_priv_1) {
-- iounmap((void *)nettel_amd_map.map_priv_1);
-- nettel_amd_map.map_priv_1 = 0;
-+ if (nettel_amd_map.virt) {
-+ iounmap((void *)nettel_amd_map.virt);
-+ nettel_amd_map.virt = 0;
- }
- #ifdef CONFIG_MTD_CFI_INTELEXT
- if (intel_mtd) {
- del_mtd_partitions(intel_mtd);
- map_destroy(intel_mtd);
- }
-- if (nettel_intel_map.map_priv_1) {
-- iounmap((void *)nettel_intel_map.map_priv_1);
-- nettel_intel_map.map_priv_1 = 0;
-+ if (nettel_intel_map.virt) {
-+ iounmap((void *)nettel_intel_map.virt);
-+ nettel_intel_map.virt = 0;
- }
- #endif
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ocelot.c linux/drivers/mtd/maps/ocelot.c
---- linux-mips-2.4.27/drivers/mtd/maps/ocelot.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/ocelot.c 2004-11-19 10:25:11.938193864 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Flash on Momenco Ocelot
- */
-@@ -7,6 +7,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -20,47 +21,23 @@
- #define NVRAM_WINDOW_SIZE 0x00007FF0
- #define NVRAM_BUSWIDTH 1
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--
- static unsigned int cacheflush = 0;
-
- static struct mtd_info *flash_mtd;
- static struct mtd_info *nvram_mtd;
-
--__u8 ocelot_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- cacheflush = 1;
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- if (cacheflush) {
-- dma_cache_inv(map->map_priv_2, map->size);
-- cacheflush = 0;
-- }
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
- {
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-+ struct map_info *map = (struct map_info *)mtd->priv;
-+ size_t done = 0;
-
--void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
- /* If we use memcpy, it does word-wide writes. Even though we told the
- GT64120A that it's an 8-bit wide region, word-wide writes don't work.
- We end up just writing the first byte of the four to all four bytes.
- So we have this loop instead */
-+ *retlen = len;
- while(len) {
-- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-+ __raw_writeb(*(unsigned char *) from, map->virt + to);
- from++;
- to++;
- len--;
-@@ -70,24 +47,21 @@
- static struct mtd_partition *parsed_parts;
-
- struct map_info ocelot_flash_map = {
-- name: "Ocelot boot flash",
-- size: FLASH_WINDOW_SIZE,
-- buswidth: FLASH_BUSWIDTH,
-- read8: ocelot_read8,
-- copy_from: ocelot_copy_from_cache,
-- write8: ocelot_write8,
-+ .name = "Ocelot boot flash",
-+ .size = FLASH_WINDOW_SIZE,
-+ .buswidth = FLASH_BUSWIDTH,
-+ .phys = FLASH_WINDOW_ADDR,
- };
-
- struct map_info ocelot_nvram_map = {
-- name: "Ocelot NVRAM",
-- size: NVRAM_WINDOW_SIZE,
-- buswidth: NVRAM_BUSWIDTH,
-- read8: ocelot_read8,
-- copy_from: ocelot_copy_from,
-- write8: ocelot_write8,
-- copy_to: ocelot_copy_to
-+ .name = "Ocelot NVRAM",
-+ .size = NVRAM_WINDOW_SIZE,
-+ .buswidth = NVRAM_BUSWIDTH,
-+ .phys = NVRAM_WINDOW_ADDR,
- };
-
-+static const char *probes[] = { "RedBoot", NULL };
-+
- static int __init init_ocelot_maps(void)
- {
- void *pld;
-@@ -107,12 +81,13 @@
- iounmap(pld);
-
- /* Now ioremap the NVRAM space */
-- ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-- if (!ocelot_nvram_map.map_priv_1) {
-+ ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-+ if (!ocelot_nvram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
- return -EIO;
- }
-- // ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
-+
-+ simple_map_init(&ocelot_nvram_map);
-
- /* And do the RAM probe on it to get an MTD device */
- nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
-@@ -120,22 +95,21 @@
- printk("NVRAM probe failed\n");
- goto fail_1;
- }
-- nvram_mtd->module = THIS_MODULE;
-+ nvram_mtd->owner = THIS_MODULE;
- nvram_mtd->erasesize = 16;
-+ /* Override the write() method */
-+ nvram_mtd->write = ocelot_ram_write;
-
- /* Now map the flash space */
-- ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-- if (!ocelot_flash_map.map_priv_1) {
-+ ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-+ if (!ocelot_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
- goto fail_2;
- }
- /* Now the cached version */
-- ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-+ ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-
-- if (!ocelot_flash_map.map_priv_2) {
-- /* Doesn't matter if it failed. Just use the uncached version */
-- ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1;
-- }
-+ simple_map_init(&ocelot_flash_map);
-
- /* Only probe for flash if the write jumper is present */
- if (brd_status & 0x40) {
-@@ -155,10 +129,10 @@
-
- add_mtd_device(nvram_mtd);
-
-- flash_mtd->module = THIS_MODULE;
-- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
-+ flash_mtd->owner = THIS_MODULE;
-+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-
-- if (nr_parts)
-+ if (nr_parts > 0)
- add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
- else
- add_mtd_device(flash_mtd);
-@@ -166,14 +140,13 @@
- return 0;
-
- fail3:
-- iounmap((void *)ocelot_flash_map.map_priv_1);
-- if (ocelot_flash_map.map_priv_2 &&
-- ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-- iounmap((void *)ocelot_flash_map.map_priv_2);
-+ iounmap((void *)ocelot_flash_map.virt);
-+ if (ocelot_flash_map.cached)
-+ iounmap((void *)ocelot_flash_map.cached);
- fail_2:
- map_destroy(nvram_mtd);
- fail_1:
-- iounmap((void *)ocelot_nvram_map.map_priv_1);
-+ iounmap((void *)ocelot_nvram_map.virt);
-
- return -ENXIO;
- }
-@@ -182,16 +155,16 @@
- {
- del_mtd_device(nvram_mtd);
- map_destroy(nvram_mtd);
-- iounmap((void *)ocelot_nvram_map.map_priv_1);
-+ iounmap((void *)ocelot_nvram_map.virt);
-
- if (parsed_parts)
- del_mtd_partitions(flash_mtd);
- else
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
-- iounmap((void *)ocelot_flash_map.map_priv_1);
-- if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-- iounmap((void *)ocelot_flash_map.map_priv_2);
-+ iounmap((void *)ocelot_flash_map.virt);
-+ if (ocelot_flash_map.cached)
-+ iounmap((void *)ocelot_flash_map.cached);
- }
-
- module_init(init_ocelot_maps);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/octagon-5066.c linux/drivers/mtd/maps/octagon-5066.c
---- linux-mips-2.4.27/drivers/mtd/maps/octagon-5066.c 2003-08-13 19:19:18.000000000 +0200
-+++ linux/drivers/mtd/maps/octagon-5066.c 2004-11-19 10:25:11.940193560 +0100
-@@ -1,4 +1,4 @@
--// $Id$
-+// $Id$
- /* ######################################################################
-
- Octagon 5066 MTD Driver.
-@@ -31,6 +31,7 @@
- #include <asm/io.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #define WINDOW_START 0xe8000
- #define WINDOW_LENGTH 0x8000
-@@ -151,32 +152,34 @@
-
- static struct map_info oct5066_map[2] = {
- {
-- name: "Octagon 5066 Socket",
-- size: 512 * 1024,
-- buswidth: 1,
-- read8: oct5066_read8,
-- read16: oct5066_read16,
-- read32: oct5066_read32,
-- copy_from: oct5066_copy_from,
-- write8: oct5066_write8,
-- write16: oct5066_write16,
-- write32: oct5066_write32,
-- copy_to: oct5066_copy_to,
-- map_priv_1: 1<<6
-+ .name = "Octagon 5066 Socket",
-+ .phys = NO_XIP,
-+ .size = 512 * 1024,
-+ .buswidth = 1,
-+ .read8 = oct5066_read8,
-+ .read16 = oct5066_read16,
-+ .read32 = oct5066_read32,
-+ .copy_from = oct5066_copy_from,
-+ .write8 = oct5066_write8,
-+ .write16 = oct5066_write16,
-+ .write32 = oct5066_write32,
-+ .copy_to = oct5066_copy_to,
-+ .map_priv_1 = 1<<6
- },
- {
-- name: "Octagon 5066 Internal Flash",
-- size: 2 * 1024 * 1024,
-- buswidth: 1,
-- read8: oct5066_read8,
-- read16: oct5066_read16,
-- read32: oct5066_read32,
-- copy_from: oct5066_copy_from,
-- write8: oct5066_write8,
-- write16: oct5066_write16,
-- write32: oct5066_write32,
-- copy_to: oct5066_copy_to,
-- map_priv_1: 2<<6
-+ .name = "Octagon 5066 Internal Flash",
-+ .phys = NO_XIP,
-+ .size = 2 * 1024 * 1024,
-+ .buswidth = 1,
-+ .read8 = oct5066_read8,
-+ .read16 = oct5066_read16,
-+ .read32 = oct5066_read32,
-+ .copy_from = oct5066_copy_from,
-+ .write8 = oct5066_write8,
-+ .write16 = oct5066_write16,
-+ .write32 = oct5066_write32,
-+ .copy_to = oct5066_copy_to,
-+ .map_priv_1 = 2<<6
- }
- };
-
-@@ -244,6 +247,7 @@
- }
- if (OctProbe() != 0) {
- printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-+ iounmap((void *)iomapadr);
- ret = -EAGAIN;
- goto out_unmap;
- }
-@@ -261,7 +265,7 @@
- if (!oct5066_mtd[i])
- oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
- if (oct5066_mtd[i]) {
-- oct5066_mtd[i]->module = THIS_MODULE;
-+ oct5066_mtd[i]->owner = THIS_MODULE;
- add_mtd_device(oct5066_mtd[i]);
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/omap-toto-flash.c linux/drivers/mtd/maps/omap-toto-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/omap-toto-flash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/omap-toto-flash.c 2004-11-19 10:25:11.941193408 +0100
-@@ -0,0 +1,137 @@
-+/*
-+ * NOR Flash memory access on TI Toto board
-+ *
-+ * jzhang@ti.com (C) 2003 Texas Instruments.
-+ *
-+ * (C) 2002 MontVista Software, Inc.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+
-+#ifndef CONFIG_ARCH_OMAP
-+#error This is for OMAP architecture only
-+#endif
-+
-+//these lines need be moved to a hardware header file
-+#define OMAP_TOTO_FLASH_BASE 0xd8000000
-+#define OMAP_TOTO_FLASH_SIZE 0x80000
-+
-+static struct map_info omap_toto_map_flash = {
-+ .name = "OMAP Toto flash",
-+ .buswidth = 2,
-+ .virt = OMAP_TOTO_FLASH_BASE,
-+};
-+
-+
-+static struct mtd_partition toto_flash_partitions[] = {
-+ {
-+ .name = "BootLoader",
-+ .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "ReservedSpace",
-+ .size = 0x00030000,
-+ .offset = MTDPART_OFS_APPEND,
-+ //mask_flags: MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "EnvArea", /* bottom 64KiB for env vars */
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+
-+static struct mtd_info *flash_mtd;
-+
-+static int __init init_flash (void)
-+{
-+
-+ struct mtd_partition *parts;
-+ int nb_parts = 0;
-+ int parsed_nr_parts = 0;
-+ const char *part_type;
-+
-+ /*
-+ * Static partition definition selection
-+ */
-+ part_type = "static";
-+
-+ parts = toto_flash_partitions;
-+ nb_parts = ARRAY_SIZE(toto_flash_partitions);
-+ omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE;
-+ omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE);
-+
-+ simple_map_init(&omap_toto_map_flash);
-+ /*
-+ * Now let's probe for the actual flash. Do it here since
-+ * specific machine settings might have been set above.
-+ */
-+ printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n",
-+ omap_toto_map_flash.buswidth*8);
-+ flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
-+ if (!flash_mtd)
-+ return -ENXIO;
-+
-+ if (parsed_nr_parts > 0) {
-+ parts = parsed_parts;
-+ nb_parts = parsed_nr_parts;
-+ }
-+
-+ if (nb_parts == 0) {
-+ printk(KERN_NOTICE "OMAP toto flash: no partition info available,"
-+ "registering whole flash at once\n");
-+ if (add_mtd_device(flash_mtd)){
-+ return -ENXIO;
-+ }
-+ } else {
-+ printk(KERN_NOTICE "Using %s partition definition\n",
-+ part_type);
-+ return add_mtd_partitions(flash_mtd, parts, nb_parts);
-+ }
-+ return 0;
-+}
-+
-+int __init omap_toto_mtd_init(void)
-+{
-+ int status;
-+
-+ if (status = init_flash()) {
-+ printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n");
-+ }
-+ return status;
-+}
-+
-+static void __exit omap_toto_mtd_cleanup(void)
-+{
-+ if (flash_mtd) {
-+ del_mtd_partitions(flash_mtd);
-+ map_destroy(flash_mtd);
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+ }
-+}
-+
-+module_init(omap_toto_mtd_init);
-+module_exit(omap_toto_mtd_cleanup);
-+
-+MODULE_AUTHOR("Jian Zhang");
-+MODULE_DESCRIPTION("OMAP Toto board map driver");
-+MODULE_LICENSE("GPL");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pb1xxx-flash.c linux/drivers/mtd/maps/pb1xxx-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/pb1xxx-flash.c 2003-05-19 08:27:22.000000000 +0200
-+++ linux/drivers/mtd/maps/pb1xxx-flash.c 2004-11-19 10:25:11.943193104 +0100
-@@ -3,12 +3,13 @@
- *
- * (C) 2001 Pete Popov <ppopov@mvista.com>
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
-+#include <linux/init.h>
- #include <linux/kernel.h>
-
- #include <linux/mtd/mtd.h>
-@@ -25,210 +26,110 @@
- #endif
-
- #ifdef CONFIG_MIPS_PB1000
-+
- #define WINDOW_ADDR 0x1F800000
- #define WINDOW_SIZE 0x800000
--#endif
--
--__u8 physmap_read8(struct map_info *map, unsigned long ofs)
--{
-- __u8 ret;
-- ret = __raw_readb(map->map_priv_1 + ofs);
-- DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--__u16 physmap_read16(struct map_info *map, unsigned long ofs)
--{
-- __u16 ret;
-- ret = __raw_readw(map->map_priv_1 + ofs);
-- DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--__u32 physmap_read32(struct map_info *map, unsigned long ofs)
--{
-- __u32 ret;
-- ret = __raw_readl(map->map_priv_1 + ofs);
-- DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
-- return ret;
--}
--
--void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
--
--
--
--static struct map_info pb1xxx_map = {
-- name: "Pb1xxx flash",
-- read8: physmap_read8,
-- read16: physmap_read16,
-- read32: physmap_read32,
-- copy_from: physmap_copy_from,
-- write8: physmap_write8,
-- write16: physmap_write16,
-- write32: physmap_write32,
-- copy_to: physmap_copy_to,
--};
-
--
--#ifdef CONFIG_MIPS_PB1000
--
--static unsigned long flash_size = 0x00800000;
--static unsigned char flash_buswidth = 4;
- static struct mtd_partition pb1xxx_partitions[] = {
- {
-- name: "yamon env",
-- size: 0x00020000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE
-- },{
-- name: "User FS",
-- size: 0x003e0000,
-- offset: 0x20000,
-- },{
-- name: "boot code",
-- size: 0x100000,
-- offset: 0x400000,
-- mask_flags: MTD_WRITEABLE
-- },{
-- name: "raw/kernel",
-- size: 0x300000,
-- offset: 0x500000
-- }
-+ .name = "yamon env",
-+ .size = 0x00020000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE},
-+ {
-+ .name = "User FS",
-+ .size = 0x003e0000,
-+ .offset = 0x20000,},
-+ {
-+ .name = "boot code",
-+ .size = 0x100000,
-+ .offset = 0x400000,
-+ .mask_flags = MTD_WRITEABLE},
-+ {
-+ .name = "raw/kernel",
-+ .size = 0x300000,
-+ .offset = 0x500000}
- };
-
- #elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-
--static unsigned char flash_buswidth = 4;
- #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
--/* both 32MiB banks will be used. Combine the first 32MiB bank and the
-- * first 28MiB of the second bank together into a single jffs/jffs2
-+/* both 32MB banks will be used. Combine the first 32MB bank and the
-+ * first 28MB of the second bank together into a single jffs/jffs2
- * partition.
- */
--static unsigned long flash_size = 0x04000000;
- #define WINDOW_ADDR 0x1C000000
- #define WINDOW_SIZE 0x4000000
- static struct mtd_partition pb1xxx_partitions[] = {
- {
-- name: "User FS",
-- size: 0x3c00000,
-- offset: 0x0000000
-- },{
-- name: "yamon",
-- size: 0x0100000,
-- offset: 0x3c00000,
-- mask_flags: MTD_WRITEABLE
-- },{
-- name: "raw kernel",
-- size: 0x02c0000,
-- offset: 0x3d00000
-+ .name = "User FS",
-+ .size = 0x3c00000,
-+ .offset = 0x0000000
-+ },{
-+ .name = "yamon",
-+ .size = 0x0100000,
-+ .offset = 0x3c00000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "raw kernel",
-+ .size = 0x02c0000,
-+ .offset = 0x3d00000
- }
- };
- #elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
--static unsigned long flash_size = 0x02000000;
- #define WINDOW_ADDR 0x1E000000
- #define WINDOW_SIZE 0x2000000
- static struct mtd_partition pb1xxx_partitions[] = {
- {
-- name: "User FS",
-- size: 0x1c00000,
-- offset: 0x0000000
-- },{
-- name: "yamon",
-- size: 0x0100000,
-- offset: 0x1c00000,
-- mask_flags: MTD_WRITEABLE
-- },{
-- name: "raw kernel",
-- size: 0x02c0000,
-- offset: 0x1d00000
-+ .name = "User FS",
-+ .size = 0x1c00000,
-+ .offset = 0x0000000
-+ },{
-+ .name = "yamon",
-+ .size = 0x0100000,
-+ .offset = 0x1c00000,
-+ .mask_flags = MTD_WRITEABLE
-+ },{
-+ .name = "raw kernel",
-+ .size = 0x02c0000,
-+ .offset = 0x1d00000
- }
- };
- #elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
--static unsigned long flash_size = 0x02000000;
- #define WINDOW_ADDR 0x1C000000
- #define WINDOW_SIZE 0x2000000
- static struct mtd_partition pb1xxx_partitions[] = {
- {
-- name: "User FS",
-- size: 0x1e00000,
-- offset: 0x0000000
-- },{
-- name: "raw kernel",
-- size: 0x0200000,
-- offset: 0x1e00000,
-+ .name = "User FS",
-+ .size = 0x1e00000,
-+ .offset = 0x0000000
-+ },{
-+ .name = "raw kernel",
-+ .size = 0x0200000,
-+ .offset = 0x1e00000,
- }
- };
- #else
- #error MTD_PB1500 define combo error /* should never happen */
- #endif
--#elif defined(CONFIG_MTD_BOSPORUS)
--static unsigned char flash_buswidth = 2;
--static unsigned long flash_size = 0x02000000;
--#define WINDOW_ADDR 0x1F000000
--#define WINDOW_SIZE 0x2000000
--static struct mtd_partition pb1xxx_partitions[] = {
-- {
-- name: "User FS",
-- size: 0x00400000,
-- offset: 0x00000000,
-- },{
-- name: "Yamon-2",
-- size: 0x00100000,
-- offset: 0x00400000,
-- },{
-- name: "Root FS",
-- size: 0x00700000,
-- offset: 0x00500000,
-- },{
-- name: "Yamon-1",
-- size: 0x00100000,
-- offset: 0x00C00000,
-- },{
-- name: "Kernel",
-- size: 0x00300000,
-- offset: 0x00D00000,
-- }
--};
- #else
- #error Unsupported board
- #endif
-
-+#define NAME "Pb1x00 Linux Flash"
-+#define PADDR WINDOW_ADDR
-+#define BUSWIDTH 4
-+#define SIZE WINDOW_SIZE
-+#define PARTITIONS 4
-+
-+static struct map_info pb1xxx_mtd_map = {
-+ .name = NAME,
-+ .size = SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = PADDR,
-+};
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
--static struct mtd_partition *parsed_parts;
--static struct mtd_info *mymtd;
-+static struct mtd_info *pb1xxx_mtd;
-
- int __init pb1xxx_mtd_init(void)
- {
-@@ -236,40 +137,37 @@
- int nb_parts = 0;
- char *part_type;
-
-- /* Default flash buswidth */
-- pb1xxx_map.buswidth = flash_buswidth;
--
- /*
- * Static partition definition selection
- */
- part_type = "static";
- parts = pb1xxx_partitions;
-- nb_parts = NB_OF(pb1xxx_partitions);
-- pb1xxx_map.size = flash_size;
-+ nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n",
-- pb1xxx_map.buswidth*8);
-- pb1xxx_map.map_priv_1 =
-- (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-- mymtd = do_map_probe("cfi_probe", &pb1xxx_map);
-- if (!mymtd) return -ENXIO;
-- mymtd->module = THIS_MODULE;
-+ BUSWIDTH*8);
-+ pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+
-+ simple_map_init(&pb1xxx_mtd_map);
-+
-+ pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
-+ if (!pb1xxx_mtd) return -ENXIO;
-+ pb1xxx_mtd->owner = THIS_MODULE;
-
-- add_mtd_partitions(mymtd, parts, nb_parts);
-+ add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
- return 0;
- }
-
- static void __exit pb1xxx_mtd_cleanup(void)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-- if (parsed_parts)
-- kfree(parsed_parts);
-+ if (pb1xxx_mtd) {
-+ del_mtd_partitions(pb1xxx_mtd);
-+ map_destroy(pb1xxx_mtd);
-+ iounmap((void *) pb1xxx_mtd_map.virt);
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pci.c linux/drivers/mtd/maps/pci.c
---- linux-mips-2.4.27/drivers/mtd/maps/pci.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/pci.c 2004-11-19 10:25:11.944192952 +0100
-@@ -7,7 +7,7 @@
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-- * $Id$
-+ * $Id$
- *
- * Generic PCI memory map driver. We support the following boards:
- * - Intel IQ80310 ATU.
-@@ -98,10 +98,10 @@
- }
-
- static struct mtd_pci_info intel_iq80310_info = {
-- init: intel_iq80310_init,
-- exit: intel_iq80310_exit,
-- translate: intel_iq80310_translate,
-- map_name: "cfi_probe",
-+ .init = intel_iq80310_init,
-+ .exit = intel_iq80310_exit,
-+ .translate = intel_iq80310_translate,
-+ .map_name = "cfi_probe",
- };
-
- /*
-@@ -181,10 +181,10 @@
- }
-
- static struct mtd_pci_info intel_dc21285_info = {
-- init: intel_dc21285_init,
-- exit: intel_dc21285_exit,
-- translate: intel_dc21285_translate,
-- map_name: "jedec_probe",
-+ .init = intel_dc21285_init,
-+ .exit = intel_dc21285_exit,
-+ .translate = intel_dc21285_translate,
-+ .map_name = "jedec_probe",
- };
-
- /*
-@@ -193,22 +193,20 @@
-
- static struct pci_device_id mtd_pci_ids[] __devinitdata = {
- {
-- vendor: PCI_VENDOR_ID_INTEL,
-- device: 0x530d,
-- subvendor: PCI_ANY_ID,
-- subdevice: PCI_ANY_ID,
-- class: PCI_CLASS_MEMORY_OTHER << 8,
-- class_mask: 0xffff00,
-- driver_data: (unsigned long)&intel_iq80310_info,
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x530d,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .class = PCI_CLASS_MEMORY_OTHER << 8,
-+ .class_mask = 0xffff00,
-+ .driver_data = (unsigned long)&intel_iq80310_info,
- },
- {
-- vendor: PCI_VENDOR_ID_DEC,
-- device: PCI_DEVICE_ID_DEC_21285,
-- subvendor: 0, /* DC21285 defaults to 0 on reset */
-- subdevice: 0, /* DC21285 defaults to 0 on reset */
-- class: 0,
-- class_mask: 0,
-- driver_data: (unsigned long)&intel_dc21285_info,
-+ .vendor = PCI_VENDOR_ID_DEC,
-+ .device = PCI_DEVICE_ID_DEC_21285,
-+ .subvendor = 0, /* DC21285 defaults to 0 on reset */
-+ .subdevice = 0, /* DC21285 defaults to 0 on reset */
-+ .driver_data = (unsigned long)&intel_dc21285_info,
- },
- { 0, }
- };
-@@ -275,14 +273,15 @@
- }
-
- static struct map_info mtd_pci_map = {
-- read8: mtd_pci_read8,
-- read16: mtd_pci_read16,
-- read32: mtd_pci_read32,
-- copy_from: mtd_pci_copyfrom,
-- write8: mtd_pci_write8,
-- write16: mtd_pci_write16,
-- write32: mtd_pci_write32,
-- copy_to: mtd_pci_copyto,
-+ .phys = NO_XIP,
-+ .read8 = mtd_pci_read8,
-+ .read16 = mtd_pci_read16,
-+ .read32 = mtd_pci_read32,
-+ .copy_from = mtd_pci_copyfrom,
-+ .write8 = mtd_pci_write8,
-+ .write16 = mtd_pci_write16,
-+ .write32 = mtd_pci_write32,
-+ .copy_to = mtd_pci_copyto,
- };
-
- static int __devinit
-@@ -322,7 +321,7 @@
- if (!mtd)
- goto release;
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- add_mtd_device(mtd);
-
- pci_set_drvdata(dev, mtd);
-@@ -359,10 +358,10 @@
- }
-
- static struct pci_driver mtd_pci_driver = {
-- name: "MTD PCI",
-- probe: mtd_pci_probe,
-- remove: __devexit_p(mtd_pci_remove),
-- id_table: mtd_pci_ids,
-+ .name = "MTD PCI",
-+ .probe = mtd_pci_probe,
-+ .remove = __devexit_p(mtd_pci_remove),
-+ .id_table = mtd_pci_ids,
- };
-
- static int __init mtd_pci_maps_init(void)
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pcmciamtd.c linux/drivers/mtd/maps/pcmciamtd.c
---- linux-mips-2.4.27/drivers/mtd/maps/pcmciamtd.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/maps/pcmciamtd.c 2004-11-19 10:25:11.946192648 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
- *
-@@ -14,6 +14,7 @@
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/timer.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <asm/system.h>
-
-@@ -24,6 +25,7 @@
- #include <pcmcia/ds.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #ifdef CONFIG_MTD_DEBUG
- static int debug = CONFIG_MTD_DEBUG_VERBOSE;
-@@ -47,7 +49,7 @@
-
-
- #define DRIVER_DESC "PCMCIA Flash memory card driver"
--#define DRIVER_VERSION "$Revision$"
-+#define DRIVER_VERSION "$Revision$"
-
- /* Size of the PCMCIA address space: 26 bits = 64 MB */
- #define MAX_PCMCIA_ADDR 0x4000000
-@@ -96,7 +98,7 @@
- MODULE_PARM(mem_speed, "i");
- MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
- MODULE_PARM(force_size, "i");
--MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
-+MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)");
- MODULE_PARM(setvpp, "i");
- MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
- MODULE_PARM(vpp, "i");
-@@ -106,11 +108,13 @@
-
-
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)
- static inline void cs_error(client_handle_t handle, int func, int ret)
- {
- error_info_t err = { func, ret };
- CardServices(ReportError, handle, &err);
- }
-+#endif
-
-
- /* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
-@@ -529,6 +533,7 @@
-
- card_settings(dev, link, &new_name);
-
-+ dev->pcmcia_map.phys = NO_XIP;
- dev->pcmcia_map.read8 = pcmcia_read8_remap;
- dev->pcmcia_map.read16 = pcmcia_read16_remap;
- dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
-@@ -539,7 +544,7 @@
- dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
-
- /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
-- that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
-+ that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the
- whole card - otherwise we try smaller windows until we succeed */
-
- req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-@@ -552,7 +557,7 @@
-
- do {
- int ret;
-- DEBUG(2, "requesting window with size = %dKB memspeed = %d",
-+ DEBUG(2, "requesting window with size = %dKiB memspeed = %d",
- req.Size >> 10, req.AccessSpeed);
- link->win = (window_handle_t)link->handle;
- ret = CardServices(RequestWindow, &link->win, &req);
-@@ -560,7 +565,7 @@
- if(ret) {
- req.Size >>= 1;
- } else {
-- DEBUG(2, "Got window of size %dKB", req.Size >> 10);
-+ DEBUG(2, "Got window of size %dKiB", req.Size >> 10);
- dev->win_size = req.Size;
- break;
- }
-@@ -573,7 +578,7 @@
- pcmciamtd_release((u_long)link);
- return;
- }
-- DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
-+ DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
-
- /* Get write protect status */
- CS_CHECK(GetStatus, link->handle, &status);
-@@ -642,21 +647,21 @@
- }
-
- dev->mtd_info = mtd;
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
-
- if(new_name) {
- int size = 0;
- char unit = ' ';
- /* Since we are using a default name, make it better by adding in the
- size */
-- if(mtd->size < 1048576) { /* <1MB in size, show size in K */
-+ if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */
- size = mtd->size >> 10;
- unit = 'K';
- } else {
- size = mtd->size >> 20;
- unit = 'M';
- }
-- snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card");
-+ snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card");
- }
-
- /* If the memory found is fits completely into the mapped PCMCIA window,
-@@ -828,16 +833,20 @@
- }
-
-
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68)
-+static struct pcmcia_driver pcmciamtd_driver = {
-+ .drv = {
-+ .name = "pcmciamtd"
-+ },
-+ .attach = pcmciamtd_attach,
-+ .detach = pcmciamtd_detach,
-+ .owner = THIS_MODULE
-+};
-+#endif
-+
-+
- static int __init init_pcmciamtd(void)
- {
-- servinfo_t serv;
--
-- info(DRIVER_DESC " " DRIVER_VERSION);
-- CardServices(GetCardServicesInfo, &serv);
-- if (serv.Revision != CS_RELEASE_CODE) {
-- err("Card Services release does not match!");
-- return -1;
-- }
-
- if(buswidth && buswidth != 1 && buswidth != 2) {
- info("bad buswidth (%d), using default", buswidth);
-@@ -851,15 +860,24 @@
- info("bad mem_type (%d), using default", mem_type);
- mem_type = 0;
- }
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68)
-+ return pcmcia_register_driver(&pcmciamtd_driver);
-+#else
- register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
- return 0;
-+#endif
- }
-
-
- static void __exit exit_pcmciamtd(void)
- {
- DEBUG(1, DRIVER_DESC " unloading");
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68)
-+ pcmcia_unregister_driver(&pcmciamtd_driver);
-+#else
- unregister_pccard_driver(&dev_info);
-+#endif
-
- while(dev_list) {
- dev_link_t *link = dev_list;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/physmap.c linux/drivers/mtd/maps/physmap.c
---- linux-mips-2.4.27/drivers/mtd/maps/physmap.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/physmap.c 2004-11-19 10:25:11.947192496 +0100
-@@ -1,179 +1,114 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Normal mappings of chips in physical memory
-+ *
-+ * Copyright (C) 2003 MontaVista Software Inc.
-+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
-+ *
-+ * 031022 - [jsun] add run-time configure and partition setup
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/config.h>
--
--#ifdef CONFIG_MTD_PARTITIONS
- #include <linux/mtd/partitions.h>
--#endif
--
--#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
--#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
--#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
-
- static struct mtd_info *mymtd;
-
--__u8 physmap_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 physmap_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 physmap_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
-+struct map_info physmap_map = {.name = "phys_mapped_flash"};
-
--void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
-+#ifdef CONFIG_MTD_PARTITIONS
-+static struct mtd_partition *mtd_parts;
-+static int mtd_parts_nb;
-
--void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
-+static int num_physmap_partitions;
-+static struct mtd_partition *physmap_partitions;
-
--void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
-+char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
-
--void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
- {
-- memcpy_toio(map->map_priv_1 + to, from, len);
-+ physmap_partitions=parts;
-+ num_physmap_partitions=num_parts;
- }
--
--struct map_info physmap_map = {
-- name: "Physically mapped flash",
-- size: WINDOW_SIZE,
-- buswidth: BUSWIDTH,
-- read8: physmap_read8,
-- read16: physmap_read16,
-- read32: physmap_read32,
-- copy_from: physmap_copy_from,
-- write8: physmap_write8,
-- write16: physmap_write16,
-- write32: physmap_write32,
-- copy_to: physmap_copy_to
--};
--
--#ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--static struct mtd_partition *mtd_parts = 0;
--static int mtd_parts_nb = 0;
--#else
--static struct mtd_partition physmap_partitions[] = {
--/* Put your own partition definitions here */
--#if 0
-- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- }
--#endif
--};
--
--#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition))
--
--#endif
--#endif
-+#endif /* CONFIG_MTD_PARTITIONS */
-
- int __init init_physmap(void)
- {
- static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
- const char **type;
-
-- printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-- physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
-+ physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size);
-
-- if (!physmap_map.map_priv_1) {
-+ if (!physmap_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-
-+ simple_map_init(&physmap_map);
-+
- mymtd = 0;
- type = rom_probe_types;
- for(; !mymtd && *type; type++) {
- mymtd = do_map_probe(*type, &physmap_map);
- }
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
-- add_mtd_device(mymtd);
- #ifdef CONFIG_MTD_PARTITIONS
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts,
-- "phys");
-+ mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes,
-+ &mtd_parts, 0);
-+
- if (mtd_parts_nb > 0)
- {
-- printk(KERN_NOTICE
-- "Using command line partition definition\n");
- add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
-+ return 0;
- }
--#else
-- if (NUM_PARTITIONS != 0)
-+
-+ if (num_physmap_partitions != 0)
- {
- printk(KERN_NOTICE
- "Using physmap partition definition\n");
-- add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
-+ add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
-+ return 0;
- }
-
- #endif
--#endif
-+ add_mtd_device(mymtd);
-+
- return 0;
- }
-
-- iounmap((void *)physmap_map.map_priv_1);
-+ iounmap((void *)physmap_map.virt);
- return -ENXIO;
- }
-
- static void __exit cleanup_physmap(void)
- {
-- if (mymtd) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (mtd_parts_nb) {
-+ del_mtd_partitions(mymtd);
-+ kfree(mtd_parts);
-+ } else if (num_physmap_partitions) {
-+ del_mtd_partitions(mymtd);
-+ } else {
- del_mtd_device(mymtd);
-- map_destroy(mymtd);
-- }
-- if (physmap_map.map_priv_1) {
-- iounmap((void *)physmap_map.map_priv_1);
-- physmap_map.map_priv_1 = 0;
- }
-+#else
-+ del_mtd_device(mymtd);
-+#endif
-+ map_destroy(mymtd);
-+
-+ iounmap((void *)physmap_map.virt);
-+ physmap_map.virt = 0;
- }
-
- module_init(init_physmap);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pnc2000.c linux/drivers/mtd/maps/pnc2000.c
---- linux-mips-2.4.27/drivers/mtd/maps/pnc2000.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/pnc2000.c 2004-11-19 10:25:11.949192192 +0100
-@@ -5,12 +5,13 @@
- *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -24,58 +25,13 @@
- * MAP DRIVER STUFF
- */
-
--__u8 pnc_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(WINDOW_ADDR + ofs);
--}
--
--__u16 pnc_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(WINDOW_ADDR + ofs);
--}
--
--__u32 pnc_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(volatile unsigned int *)(WINDOW_ADDR + ofs);
--}
--
--void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(WINDOW_ADDR + from), len);
--}
--
--void pnc_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(WINDOW_ADDR + adr) = d;
--}
--
--void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(WINDOW_ADDR + to), from, len);
--}
-
- struct map_info pnc_map = {
-- name: "PNC-2000",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: pnc_read8,
-- read16: pnc_read16,
-- read32: pnc_read32,
-- copy_from: pnc_copy_from,
-- write8: pnc_write8,
-- write16: pnc_write16,
-- write32: pnc_write32,
-- copy_to: pnc_copy_to
-+ .name = "PNC-2000",
-+ .size = WINDOW_SIZE,
-+ .buswidth = 4,
-+ .phys = 0xFFFFFFFF,
-+ .virt = WINDOW_ADDR,
- };
-
-
-@@ -84,19 +40,19 @@
- */
- static struct mtd_partition pnc_partitions[3] = {
- {
-- name: "PNC-2000 boot firmware",
-- size: 0x20000,
-- offset: 0
-+ .name = "PNC-2000 boot firmware",
-+ .size = 0x20000,
-+ .offset = 0
- },
- {
-- name: "PNC-2000 kernel",
-- size: 0x1a0000,
-- offset: 0x20000
-+ .name = "PNC-2000 kernel",
-+ .size = 0x1a0000,
-+ .offset = 0x20000
- },
- {
-- name: "PNC-2000 filesystem",
-- size: 0x240000,
-- offset: 0x1c0000
-+ .name = "PNC-2000 filesystem",
-+ .size = 0x240000,
-+ .offset = 0x1c0000
- }
- };
-
-@@ -110,9 +66,11 @@
- {
- printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-+ simple_map_init(&pnc_map);
-+
- mymtd = do_map_probe("cfi_probe", &pnc_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- return add_mtd_partitions(mymtd, pnc_partitions, 3);
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/redwood.c linux/drivers/mtd/maps/redwood.c
---- linux-mips-2.4.27/drivers/mtd/maps/redwood.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/redwood.c 2004-11-19 10:25:11.962190216 +0100
-@@ -1,38 +1,23 @@
- /*
-- * $Id:
-+ * $Id$
- *
-- * redwood.c - mapper for IBM Redwood-4/5 board.
-+ * drivers/mtd/maps/redwood.c
- *
-- * Copyright 2001 MontaVista Softare Inc.
-+ * FLASH map for the IBM Redwood 4/5/6 boards.
- *
-- * This program is free software; you can redistribute it and/or modify it
-- * under the terms of the GNU General Public License as published by the
-- * Free Software Foundation; either version 2 of the License, or (at your
-- * option) any later version.
-- *
-- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-- *
-- * You should have received a copy of the GNU General Public License along
-- * with this program; if not, write to the Free Software Foundation, Inc.,
-- * 675 Mass Ave, Cambridge, MA 02139, USA.
-- *
-- * History: 12/17/2001 - Armin
-- * migrated to use do_map_probe
-+ * Author: MontaVista Software, Inc. <source@mvista.com>
- *
-+ * 2001-2003 (c) MontaVista, Software, Inc. This file is licensed under
-+ * the terms of the GNU General Public License version 2. This program
-+ * is licensed "as is" without any warranty of any kind, whether express
-+ * or implied.
- */
-
-+#include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -40,96 +25,102 @@
-
- #include <asm/io.h>
-
-+#if !defined (CONFIG_REDWOOD_6)
-+
- #define WINDOW_ADDR 0xffc00000
- #define WINDOW_SIZE 0x00400000
-
--__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
--{
-- return *(__u8 *)(map->map_priv_1 + ofs);
--}
--
--__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
--{
-- return *(__u16 *)(map->map_priv_1 + ofs);
--}
--
--__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
--{
-- return *(volatile unsigned int *)(map->map_priv_1 + ofs);
--}
--
--void redwood_flash_copy_from(struct map_info *map, void *to,
-- unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *(__u8 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *(__u16 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *(__u32 *)(map->map_priv_1 + adr) = d;
--}
--
--void redwood_flash_copy_to(struct map_info *map, unsigned long to,
-- const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
-+#define RW_PART0_OF 0
-+#define RW_PART0_SZ 0x10000
-+#define RW_PART1_OF RW_PART0_SZ
-+#define RW_PART1_SZ 0x200000 - 0x10000
-+#define RW_PART2_OF 0x200000
-+#define RW_PART2_SZ 0x10000
-+#define RW_PART3_OF 0x210000
-+#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000)
-+#define RW_PART4_OF 0x3e0000
-+#define RW_PART4_SZ 0x20000
-
--struct map_info redwood_flash_map = {
-- name: "IBM Redwood",
-- size: WINDOW_SIZE,
-- buswidth: 2,
-- read8: redwood_flash_read8,
-- read16: redwood_flash_read16,
-- read32: redwood_flash_read32,
-- copy_from: redwood_flash_copy_from,
-- write8: redwood_flash_write8,
-- write16: redwood_flash_write16,
-- write32: redwood_flash_write32,
-- copy_to: redwood_flash_copy_to
-+static struct mtd_partition redwood_flash_partitions[] = {
-+ {
-+ .name = "Redwood OpenBIOS Vital Product Data",
-+ .offset = RW_PART0_OF,
-+ .size = RW_PART0_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },
-+ {
-+ .name = "Redwood kernel",
-+ .offset = RW_PART1_OF,
-+ .size = RW_PART1_SZ
-+ },
-+ {
-+ .name = "Redwood OpenBIOS non-volatile storage",
-+ .offset = RW_PART2_OF,
-+ .size = RW_PART2_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },
-+ {
-+ .name = "Redwood filesystem",
-+ .offset = RW_PART3_OF,
-+ .size = RW_PART3_SZ
-+ },
-+ {
-+ .name = "Redwood OpenBIOS",
-+ .offset = RW_PART4_OF,
-+ .size = RW_PART4_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ }
- };
-
-+#else /* CONFIG_REDWOOD_6 */
-+/* FIXME: the window is bigger - armin */
-+#define WINDOW_ADDR 0xff800000
-+#define WINDOW_SIZE 0x00800000
-+
-+#define RW_PART0_OF 0
-+#define RW_PART0_SZ 0x400000 /* 4 MiB data */
-+#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ
-+#define RW_PART1_SZ 0x10000 /* 64K VPD */
-+#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ
-+#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000)
-+#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ
-+#define RW_PART3_SZ 0x20000
-
- static struct mtd_partition redwood_flash_partitions[] = {
- {
-- name: "Redwood OpenBIOS Vital Product Data",
-- offset: 0,
-- size: 0x10000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Redwood filesystem",
-+ .offset = RW_PART0_OF,
-+ .size = RW_PART0_SZ
- },
- {
-- name: "Redwood kernel",
-- offset: 0x10000,
-- size: 0x200000 - 0x10000
-+ .name = "Redwood OpenBIOS Vital Product Data",
-+ .offset = RW_PART1_OF,
-+ .size = RW_PART1_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
-- name: "Redwood OpenBIOS non-volatile storage",
-- offset: 0x200000,
-- size: 0x10000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Redwood kernel",
-+ .offset = RW_PART2_OF,
-+ .size = RW_PART2_SZ
- },
- {
-- name: "Redwood filesystem",
-- offset: 0x210000,
-- size: 0x200000 - (0x10000 + 0x20000)
-- },
-- {
-- name: "Redwood OpenBIOS",
-- offset: 0x3e0000,
-- size: 0x20000,
-- mask_flags: MTD_WRITEABLE /* force read-only */
-+ .name = "Redwood OpenBIOS",
-+ .offset = RW_PART3_OF,
-+ .size = RW_PART3_SZ,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- }
- };
-+
-+#endif /* CONFIG_REDWOOD_6 */
-+
-+struct map_info redwood_flash_map = {
-+ .name = "IBM Redwood",
-+ .size = WINDOW_SIZE,
-+ .buswidth = 2,
-+ .phys = WINDOW_ADDR,
-+};
-+
-+
- #define NUM_REDWOOD_FLASH_PARTITIONS \
- (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
-
-@@ -140,18 +131,19 @@
- printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
- WINDOW_SIZE, WINDOW_ADDR);
-
-- redwood_flash_map.map_priv_1 =
-+ redwood_flash_map.virt =
- (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-- if (!redwood_flash_map.map_priv_1) {
-+ if (!redwood_flash_map.virt) {
- printk("init_redwood_flash: failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&redwood_flash_map);
-
- redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
-
- if (redwood_mtd) {
-- redwood_mtd->module = THIS_MODULE;
-+ redwood_mtd->owner = THIS_MODULE;
- return add_mtd_partitions(redwood_mtd,
- redwood_flash_partitions,
- NUM_REDWOOD_FLASH_PARTITIONS);
-@@ -164,10 +156,15 @@
- {
- if (redwood_mtd) {
- del_mtd_partitions(redwood_mtd);
-- iounmap((void *)redwood_flash_map.map_priv_1);
-+ /* moved iounmap after map_destroy - armin */
- map_destroy(redwood_mtd);
-+ iounmap((void *)redwood_flash_map.virt);
- }
- }
-
- module_init(init_redwood_flash);
- module_exit(cleanup_redwood_flash);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("MontaVista Software <source@mvista.com>");
-+MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/rpxlite.c linux/drivers/mtd/maps/rpxlite.c
---- linux-mips-2.4.27/drivers/mtd/maps/rpxlite.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/rpxlite.c 2004-11-19 10:25:11.963190064 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Handle mapping of the flash on the RPX Lite and CLLF boards
- */
-@@ -7,6 +7,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -17,80 +18,31 @@
-
- static struct mtd_info *mymtd;
-
--__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
--struct map_info rpxlite_map = {
-- name: "RPX",
-- size: WINDOW_SIZE,
-- buswidth: 4,
-- read8: rpxlite_read8,
-- read16: rpxlite_read16,
-- read32: rpxlite_read32,
-- copy_from: rpxlite_copy_from,
-- write8: rpxlite_write8,
-- write16: rpxlite_write16,
-- write32: rpxlite_write32,
-- copy_to: rpxlite_copy_to
-+static struct map_info rpxlite_map = {
-+ .name = "RPX",
-+ .size = WINDOW_SIZE,
-+ .buswidth = 4,
-+ .phys = WINDOW_ADDR,
- };
-
- int __init init_rpxlite(void)
- {
- printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-- rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+ rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-
-- if (!rpxlite_map.map_priv_1) {
-+ if (!rpxlite_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
-+ simple_map_init(&rpxlite_map);
- mymtd = do_map_probe("cfi_probe", &rpxlite_map);
- if (mymtd) {
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
- add_mtd_device(mymtd);
- return 0;
- }
-
-- iounmap((void *)rpxlite_map.map_priv_1);
-+ iounmap((void *)rpxlite_map.virt);
- return -ENXIO;
- }
-
-@@ -100,9 +52,9 @@
- del_mtd_device(mymtd);
- map_destroy(mymtd);
- }
-- if (rpxlite_map.map_priv_1) {
-- iounmap((void *)rpxlite_map.map_priv_1);
-- rpxlite_map.map_priv_1 = 0;
-+ if (rpxlite_map.virt) {
-+ iounmap((void *)rpxlite_map.virt);
-+ rpxlite_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sa1100-flash.c linux/drivers/mtd/maps/sa1100-flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/sa1100-flash.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/sa1100-flash.c 2004-11-19 10:25:11.966189608 +0100
-@@ -3,7 +3,7 @@
- *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/config.h>
-@@ -11,278 +11,212 @@
- #include <linux/types.h>
- #include <linux/ioport.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-+#include <linux/mtd/concat.h>
-
- #include <asm/hardware.h>
-+#include <asm/mach-types.h>
- #include <asm/io.h>
-+#include <asm/sizes.h>
-
-+#include <asm/arch/h3600.h>
-
- #ifndef CONFIG_ARCH_SA1100
- #error This is for SA1100 architecture only
- #endif
-
-+/*
-+ * This isnt complete yet, so...
-+ */
-+#define CONFIG_MTD_SA1100_STATICMAP 1
-
--#define WINDOW_ADDR 0xe8000000
--
--static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sa1100_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sa1100_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *)(map->map_priv_1 + to), from, len);
--}
--
--static struct map_info sa1100_map = {
-- name: "SA1100 flash",
-- read8: sa1100_read8,
-- read16: sa1100_read16,
-- read32: sa1100_read32,
-- copy_from: sa1100_copy_from,
-- write8: sa1100_write8,
-- write16: sa1100_write16,
-- write32: sa1100_write32,
-- copy_to: sa1100_copy_to,
--
-- map_priv_1: WINDOW_ADDR,
-- map_priv_2: -1,
--};
--
--
-+#ifdef CONFIG_MTD_SA1100_STATICMAP
- /*
- * Here are partition information for all known SA1100-based devices.
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
- * structure.
- *
-- * The *_max_flash_size is the maximum possible mapped flash size which
-- * is not necessarily the actual flash size. It must be no more than
-- * the value specified in the "struct map_desc *_io_desc" mapping
-- * definition for the corresponding machine.
-+ * Please note:
-+ * 1. We no longer support static flash mappings via the machine io_desc
-+ * structure.
-+ * 2. The flash size given should be the largest flash size that can
-+ * be accommodated.
-+ *
-+ * The MTD layer will detect flash chip aliasing and reduce the size of
-+ * the map accordingly.
- *
- * Please keep these in alphabetical order, and formatted as per existing
- * entries. Thanks.
- */
-
- #ifdef CONFIG_SA1100_ADSBITSY
--#define ADSBITSY_FLASH_SIZE 0x02000000
- static struct mtd_partition adsbitsy_partitions[] = {
- {
-- name: "bootROM",
-- size: 0x80000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "zImage",
-- size: 0x100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "bootROM",
-+ .size = 0x80000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_ASSABET
- /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
--#define ASSABET4_FLASH_SIZE 0x00400000
- static struct mtd_partition assabet4_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00020000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "bootloader params",
-- size: 0x00020000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "jffs",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "bootloader",
-+ .size = 0x00020000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "bootloader params",
-+ .size = 0x00020000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "jffs",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
-
- /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
--#define ASSABET5_FLASH_SIZE 0x02000000
- static struct mtd_partition assabet5_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "bootloader params",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "jffs",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "jffs",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
-
--#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE
- #define assabet_partitions assabet5_partitions
- #endif
-
- #ifdef CONFIG_SA1100_BADGE4
--
- /*
-- * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
-+ * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
- * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
- * Sixty-three 32 KiW Main Blocks (4032 Ki b)
-+ *
-+ * <or>
-+ *
-+ * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
-+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
-+ * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
- */
--#define BADGE4_FLASH_SIZE 0x00400000
- static struct mtd_partition badge4_partitions[] = {
- {
-- name: "BLOB boot loader",
-- offset: 0,
-- size: 0x0000A000
-- }, {
-- name: "params",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x00006000
-- }, {
-- name: "kernel",
-- offset: MTDPART_OFS_APPEND,
-- size: 0x00100000
-- }, {
-- name: "root",
-- offset: MTDPART_OFS_APPEND,
-- size: MTDPART_SIZ_FULL
-+ .name = "BLOB boot loader",
-+ .offset = 0,
-+ .size = 0x0000A000
-+ }, {
-+ .name = "params",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 0x00006000
-+ }, {
-+ .name = "root",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
- }
- };
--
- #endif
-
-
- #ifdef CONFIG_SA1100_CERF
- #ifdef CONFIG_SA1100_CERF_FLASH_32MB
--#define CERF_FLASH_SIZE 0x02000000
--static struct mtd_partition cerf_partitions[] = {
-- {
-- name: "firmware",
-- size: 0x00040000,
-- offset: 0,
-- }, {
-- name: "params",
-- size: 0x00040000,
-- offset: 0x00040000,
-- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-- }, {
-- name: "rootdisk",
-- size: 0x01E80000,
-- offset: 0x00180000,
-- }
--};
-+# define CERF_FLASH_SIZE 0x02000000
- #elif defined CONFIG_SA1100_CERF_FLASH_16MB
--#define CERF_FLASH_SIZE 0x01000000
-+# define CERF_FLASH_SIZE 0x01000000
-+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
-+# define CERF_FLASH_SIZE 0x00800000
-+#else
-+# error "Undefined flash size for CERF in sa1100-flash.c"
-+#endif
-+
- static struct mtd_partition cerf_partitions[] = {
- {
-- name: "firmware",
-- size: 0x00020000,
-- offset: 0,
-- }, {
-- name: "params",
-- size: 0x00020000,
-- offset: 0x00020000,
-- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00040000,
-- }, {
-- name: "rootdisk",
-- size: 0x00EC0000,
-- offset: 0x00140000,
-+ .name = "Bootloader",
-+ .size = 0x00020000,
-+ .offset = 0x00000000,
-+ }, {
-+ .name = "Params",
-+ .size = 0x00040000,
-+ .offset = 0x00020000,
-+ }, {
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00060000,
-+ }, {
-+ .name = "Filesystem",
-+ .size = CERF_FLASH_SIZE-0x00160000,
-+ .offset = 0x00160000,
- }
- };
--#elif defined CONFIG_SA1100_CERF_FLASH_8MB
--# error "Unwritten type definition"
--#else
--# error "Undefined memory orientation for CERF in sa1100-flash.c"
--#endif
- #endif
-
- #ifdef CONFIG_SA1100_CONSUS
--#define CONSUS_FLASH_SIZE 0x02000000
- static struct mtd_partition consus_partitions[] = {
- {
-- name: "Consus boot firmware",
-- offset: 0,
-- size: 0x00040000,
-- mask_flags: MTD_WRITABLE, /* force read-only */
-- }, {
-- name: "Consus kernel",
-- offset: 0x00040000,
-- size: 0x00100000,
-- mask_flags: 0,
-+ .name = "Consus boot firmware",
-+ .offset = 0,
-+ .size = 0x00040000,
-+ .mask_flags = MTD_WRITABLE, /* force read-only */
-+ }, {
-+ .name = "Consus kernel",
-+ .offset = 0x00040000,
-+ .size = 0x00100000,
-+ .mask_flags = 0,
- }, {
-- name: "Consus disk",
-- offset: 0x00140000,
-+ .name = "Consus disk",
-+ .offset = 0x00140000,
- /* The rest (up to 16M) for jffs. We could put 0 and
- make it find the size automatically, but right now
- i have 32 megs. jffs will use all 32 megs if given
- the chance, and this leads to horrible problems
- when you try to re-flash the image because blob
- won't erase the whole partition. */
-- size: 0x01000000 - 0x00140000,
-- mask_flags: 0,
-+ .size = 0x01000000 - 0x00140000,
-+ .mask_flags = 0,
- }, {
- /* this disk is a secondary disk, which can be used as
- needed, for simplicity, make it the size of the other
- consus partition, although realistically it could be
- the remainder of the disk (depending on the file
- system used) */
-- name: "Consus disk2",
-- offset: 0x01000000,
-- size: 0x01000000 - 0x00140000,
-- mask_flags: 0,
-+ .name = "Consus disk2",
-+ .offset = 0x01000000,
-+ .size = 0x01000000 - 0x00140000,
-+ .mask_flags = 0,
- }
- };
- #endif
-@@ -292,96 +226,95 @@
- #define FLEXANET_FLASH_SIZE 0x02000000
- static struct mtd_partition flexanet_partitions[] = {
- {
-- name: "bootloader",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "bootloader params",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "kernel",
-- size: 0x000C0000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "altkernel",
-- size: 0x000C0000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "root",
-- size: 0x00400000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "free1",
-- size: 0x00300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "free2",
-- size: 0x00300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-- }, {
-- name: "free3",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "kernel",
-+ .size = 0x000C0000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "altkernel",
-+ .size = 0x000C0000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "root",
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "free1",
-+ .size = 0x00300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "free2",
-+ .size = 0x00300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
-+ }, {
-+ .name = "free3",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_FREEBIRD
--#define FREEBIRD_FLASH_SIZE 0x02000000
- static struct mtd_partition freebird_partitions[] = {
--#if CONFIG_SA1100_FREEBIRD_NEW
-+#ifdef CONFIG_SA1100_FREEBIRD_NEW
- {
-- name: "firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "kernel",
-- size: 0x00080000,
-- offset: 0x00040000,
-- }, {
-- name: "params",
-- size: 0x00040000,
-- offset: 0x000C0000,
-- }, {
-- name: "initrd",
-- size: 0x00100000,
-- offset: 0x00100000,
-- }, {
-- name: "root cramfs",
-- size: 0x00300000,
-- offset: 0x00200000,
-- }, {
-- name: "usr cramfs",
-- size: 0x00C00000,
-- offset: 0x00500000,
-- }, {
-- name: "local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x01100000,
-+ .name = "firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00040000,
-+ }, {
-+ .name = "params",
-+ .size = 0x00040000,
-+ .offset = 0x000C0000,
-+ }, {
-+ .name = "initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00100000,
-+ }, {
-+ .name = "root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00200000,
-+ }, {
-+ .name = "usr cramfs",
-+ .size = 0x00C00000,
-+ .offset = 0x00500000,
-+ }, {
-+ .name = "local",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x01100000,
- }
- #else
- {
-- size: 0x00040000,
-- offset: 0,
-+ .size = 0x00040000,
-+ .offset = 0,
- }, {
-- size: 0x000c0000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x000c0000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0x00400000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- #endif
- };
-@@ -389,178 +322,215 @@
-
- #ifdef CONFIG_SA1100_FRODO
- /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
--#define FRODO_FLASH_SIZE 0x02000000
- static struct mtd_partition frodo_partitions[] =
- {
- {
-- name: "Boot Loader",
-- size: 0x00040000,
-- offset: 0x00000000
-- }, {
-- name: "Parameter Block",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND
-- }, {
-- name: "Linux Kernel",
-- size: 0x00100000,
-- offset: MTDPART_OFS_APPEND
-- }, {
-- name: "Ramdisk",
-- size: 0x00680000,
-- offset: MTDPART_OFS_APPEND
-- }, {
-- name: "Flash File System",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND
-+ .name = "bootloader",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE
-+ }, {
-+ .name = "bootloader params",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
-+ }, {
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
-+ }, {
-+ .name = "ramdisk",
-+ .size = 0x00400000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE
-+ }, {
-+ .name = "file system",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_GRAPHICSCLIENT
--#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000
- static struct mtd_partition graphicsclient_partitions[] = {
- {
-- name: "zImage",
-- size: 0x100000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_GRAPHICSMASTER
--#define GRAPHICSMASTER_FLASH_SIZE 0x01000000
- static struct mtd_partition graphicsmaster_partitions[] = {
- {
-- name: "zImage",
-- size: 0x100000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "zImage",
-+ .size = 0x100000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "ramdisk.gz",
-- size: 0x300000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ramdisk.gz",
-+ .size = 0x300000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "User FS",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "User FS",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
--#ifdef CONFIG_SA1100_H3600
--#define H3600_FLASH_SIZE 0x02000000
--static struct mtd_partition h3600_partitions[] = {
-+#ifdef CONFIG_SA1100_H3XXX
-+static struct mtd_partition h3xxx_partitions[] = {
- {
-- name: "H3600 boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "H3600 kernel",
-- size: 0x00080000,
-- offset: 0x00040000,
-+ .name = "H3XXX boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "H3600 params",
-- size: 0x00040000,
-- offset: 0x000C0000,
-+#ifdef CONFIG_MTD_2PARTS_IPAQ
-+ .name = "H3XXX root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00040000,
-+#else
-+ .name = "H3XXX kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00040000,
-+ }, {
-+ .name = "H3XXX params",
-+ .size = 0x00040000,
-+ .offset = 0x000C0000,
- }, {
- #ifdef CONFIG_JFFS2_FS
-- name: "H3600 root jffs2",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00100000,
-+ .name = "H3XXX root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00100000,
- #else
-- name: "H3600 initrd",
-- size: 0x00100000,
-- offset: 0x00100000,
-+ .name = "H3XXX initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00100000,
- }, {
-- name: "H3600 root cramfs",
-- size: 0x00300000,
-- offset: 0x00200000,
-+ .name = "H3XXX root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00200000,
- }, {
-- name: "H3600 usr cramfs",
-- size: 0x00800000,
-- offset: 0x00500000,
-+ .name = "H3XXX usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00500000,
- }, {
-- name: "H3600 usr local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00d00000,
-+ .name = "H3XXX usr local",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = 0x00d00000,
-+#endif
- #endif
- }
- };
-
--static void h3600_set_vpp(struct map_info *map, int vpp)
-+static void h3xxx_set_vpp(struct map_info *map, int vpp)
- {
- assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
- }
-+#else
-+#define h3xxx_set_vpp NULL
-+#endif
-+
-+#ifdef CONFIG_SA1100_HACKKIT
-+static struct mtd_partition hackkit_partitions[] = {
-+ {
-+ .name = "BLOB",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "config",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "initrd",
-+ .size = 0x00180000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "rootfs",
-+ .size = 0x700000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "data",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
-+ }
-+};
- #endif
-
- #ifdef CONFIG_SA1100_HUW_WEBPANEL
--#define HUW_WEBPANEL_FLASH_SIZE 0x01000000
- static struct mtd_partition huw_webpanel_partitions[] = {
- {
-- name: "Loader",
-- size: 0x00040000,
-- offset: 0,
-- }, {
-- name: "Sector 1",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "Loader",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ }, {
-+ .name = "Sector 1",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_JORNADA720
--#define JORNADA720_FLASH_SIZE 0x02000000
- static struct mtd_partition jornada720_partitions[] = {
- {
-- name: "JORNADA720 boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "JORNADA720 boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "JORNADA720 kernel",
-- size: 0x000c0000,
-- offset: 0x00040000,
-+ .name = "JORNADA720 kernel",
-+ .size = 0x000c0000,
-+ .offset = 0x00040000,
- }, {
-- name: "JORNADA720 params",
-- size: 0x00040000,
-- offset: 0x00100000,
-+ .name = "JORNADA720 params",
-+ .size = 0x00040000,
-+ .offset = 0x00100000,
- }, {
-- name: "JORNADA720 initrd",
-- size: 0x00100000,
-- offset: 0x00140000,
-+ .name = "JORNADA720 initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00140000,
- }, {
-- name: "JORNADA720 root cramfs",
-- size: 0x00300000,
-- offset: 0x00240000,
-+ .name = "JORNADA720 root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00240000,
- }, {
-- name: "JORNADA720 usr cramfs",
-- size: 0x00800000,
-- offset: 0x00540000,
-+ .name = "JORNADA720 usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00540000,
- }, {
-- name: "JORNADA720 usr local",
-- size: 0 /* will expand to the end of the flash */
-- offset: 0x00d00000,
-+ .name = "JORNADA720 usr local",
-+ .size = 0, /* will expand to the end of the flash */
-+ .offset = 0x00d00000,
- }
- };
-
--static void jornada720_set_vpp(int vpp)
-+static void jornada720_set_vpp(struct map_info *map, int vpp)
- {
- if (vpp)
- PPSR |= 0x80;
-@@ -568,454 +538,811 @@
- PPSR &= ~0x80;
- PPDR |= 0x80;
- }
--
-+#else
-+#define jornada720_set_vpp NULL
- #endif
-
- #ifdef CONFIG_SA1100_PANGOLIN
--#define PANGOLIN_FLASH_SIZE 0x04000000
- static struct mtd_partition pangolin_partitions[] = {
- {
-- name: "boot firmware",
-- size: 0x00080000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-- }, {
-- name: "initrd",
-- size: 0x00280000,
-- offset: 0x00180000,
-- }, {
-- name: "initrd-test",
-- size: 0x03C00000,
-- offset: 0x00400000,
-+ .name = "boot firmware",
-+ .size = 0x00080000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00080000,
-+ }, {
-+ .name = "initrd",
-+ .size = 0x00280000,
-+ .offset = 0x00180000,
-+ }, {
-+ .name = "initrd-test",
-+ .size = 0x03C00000,
-+ .offset = 0x00400000,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_PT_SYSTEM3
- /* erase size is 0x40000 == 256k partitions have to have this boundary */
--#define SYSTEM3_FLASH_SIZE 0x01000000
- static struct mtd_partition system3_partitions[] = {
- {
-- name: "BLOB",
-- size: 0x00040000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "config",
-- size: 0x00040000,
-- offset: MTDPART_OFS_APPEND,
-- }, {
-- name: "kernel",
-- size: 0x00100000,
-- offset: MTDPART_OFS_APPEND,
-- }, {
-- name: "root",
-- size: MTDPART_SIZ_FULL,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "BLOB",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "config",
-+ .size = 0x00040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "root",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_SHANNON
--#define SHANNON_FLASH_SIZE 0x00400000
- static struct mtd_partition shannon_partitions[] = {
- {
-- name: "BLOB boot loader",
-- offset: 0,
-- size: 0x20000
-+ .name = "BLOB boot loader",
-+ .offset = 0,
-+ .size = 0x20000
- },
- {
-- name: "kernel",
-- offset: MTDPART_OFS_APPEND,
-- size: 0xe0000
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 0xe0000
- },
- {
-- name: "initrd",
-- offset: MTDPART_OFS_APPEND,
-- size: MTDPART_SIZ_FULL
-+ .name = "initrd",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL
- }
- };
-
- #endif
-
- #ifdef CONFIG_SA1100_SHERMAN
--#define SHERMAN_FLASH_SIZE 0x02000000
- static struct mtd_partition sherman_partitions[] = {
- {
-- size: 0x50000,
-- offset: 0,
-+ .size = 0x50000,
-+ .offset = 0,
- }, {
-- size: 0x70000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x70000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0x600000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0x600000,
-+ .offset = MTDPART_OFS_APPEND,
- }, {
-- size: 0xA0000,
-- offset: MTDPART_OFS_APPEND,
-+ .size = 0xA0000,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_SIMPAD
--#define SIMPAD_FLASH_SIZE 0x02000000
- static struct mtd_partition simpad_partitions[] = {
- {
-- name: "SIMpad boot firmware",
-- size: 0x00080000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "SIMpad kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-- }, {
--#ifdef CONFIG_JFFS2_FS
-- name: "SIMpad root jffs2",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00180000,
-+ .name = "SIMpad boot firmware",
-+ .size = 0x00080000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "SIMpad kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+#ifdef CONFIG_ROOT_CRAMFS
-+ .name = "SIMpad root cramfs",
-+ .size =0x00D80000,
-+ .offset = MTDPART_OFS_APPEND
-+
-+ }, {
-+ .name = "SIMpad local jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
- #else
-- name: "SIMpad initrd",
-- size: 0x00300000,
-- offset: 0x00180000,
-- }, {
-- name: "SIMpad root cramfs",
-- size: 0x00300000,
-- offset: 0x00480000,
-- }, {
-- name: "SIMpad usr cramfs",
-- size: 0x005c0000,
-- offset: 0x00780000,
-- }, {
-- name: "SIMpad usr local",
-- size: MTDPART_SIZ_FULL,
-- offset: 0x00d40000,
-+ .name = "SIMpad root jffs2",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND
- #endif
- }
- };
- #endif /* CONFIG_SA1100_SIMPAD */
-
- #ifdef CONFIG_SA1100_STORK
--#define STORK_FLASH_SIZE 0x02000000
- static struct mtd_partition stork_partitions[] = {
- {
-- name: "STORK boot firmware",
-- size: 0x00040000,
-- offset: 0,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-- }, {
-- name: "STORK params",
-- size: 0x00040000,
-- offset: 0x00040000,
-- }, {
-- name: "STORK kernel",
-- size: 0x00100000,
-- offset: 0x00080000,
-+ .name = "STORK boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ }, {
-+ .name = "STORK params",
-+ .size = 0x00040000,
-+ .offset = 0x00040000,
-+ }, {
-+ .name = "STORK kernel",
-+ .size = 0x00100000,
-+ .offset = 0x00080000,
- }, {
- #ifdef CONFIG_JFFS2_FS
-- name: "STORK root jffs2",
-- offset: 0x00180000,
-- size: MTDPART_SIZ_FULL,
-+ .name = "STORK root jffs2",
-+ .offset = 0x00180000,
-+ .size = MTDPART_SIZ_FULL,
- #else
-- name: "STORK initrd",
-- size: 0x00100000,
-- offset: 0x00180000,
-- }, {
-- name: "STORK root cramfs",
-- size: 0x00300000,
-- offset: 0x00280000,
-- }, {
-- name: "STORK usr cramfs",
-- size: 0x00800000,
-- offset: 0x00580000,
-- }, {
-- name: "STORK usr local",
-- offset: 0x00d80000,
-- size: MTDPART_SIZ_FULL,
-+ .name = "STORK initrd",
-+ .size = 0x00100000,
-+ .offset = 0x00180000,
-+ }, {
-+ .name = "STORK root cramfs",
-+ .size = 0x00300000,
-+ .offset = 0x00280000,
-+ }, {
-+ .name = "STORK usr cramfs",
-+ .size = 0x00800000,
-+ .offset = 0x00580000,
-+ }, {
-+ .name = "STORK usr local",
-+ .offset = 0x00d80000,
-+ .size = MTDPART_SIZ_FULL,
-+#endif
-+ }
-+};
- #endif
-+
-+#ifdef CONFIG_SA1100_TRIZEPS
-+static struct mtd_partition trizeps_partitions[] = {
-+ {
-+ .name = "Bootloader",
-+ .size = 0x00100000,
-+ .offset = 0,
-+ }, {
-+ .name = "Kernel",
-+ .size = 0x00100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ }, {
-+ .name = "root",
-+ .size = MTDPART_SIZ_FULL,
-+ .offset = MTDPART_OFS_APPEND,
- }
- };
- #endif
-
- #ifdef CONFIG_SA1100_YOPY
--#define YOPY_FLASH_SIZE 0x08000000
- static struct mtd_partition yopy_partitions[] = {
- {
-- name: "boot firmware",
-- size: 0x00040000,
-- offset: 0x00000000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "boot firmware",
-+ .size = 0x00040000,
-+ .offset = 0x00000000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
-- name: "kernel",
-- size: 0x00080000,
-- offset: 0x00080000,
-+ .name = "kernel",
-+ .size = 0x00080000,
-+ .offset = 0x00080000,
- }, {
-- name: "initrd",
-- size: 0x00300000,
-- offset: 0x00100000,
-+ .name = "initrd",
-+ .size = 0x00300000,
-+ .offset = 0x00100000,
- }, {
-- name: "root",
-- size: 0x01000000,
-- offset: 0x00400000,
-+ .name = "root",
-+ .size = 0x01000000,
-+ .offset = 0x00400000,
- }
- };
- #endif
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--
--static struct mtd_partition *parsed_parts;
--static struct mtd_info *mymtd;
--
--int __init sa1100_mtd_init(void)
-+static int __init sa1100_static_partitions(struct mtd_partition **parts)
- {
-- struct mtd_partition *parts;
-- int nb_parts = 0, ret;
-- int parsed_nr_parts = 0;
-- const char *part_type;
-- unsigned long base = -1UL;
--
-- /* Default flash buswidth */
-- sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
--
-- /*
-- * Static partition definition selection
-- */
-- part_type = "static";
-+ int nb_parts = 0;
-
- #ifdef CONFIG_SA1100_ADSBITSY
- if (machine_is_adsbitsy()) {
-- parts = adsbitsy_partitions;
-+ *parts = adsbitsy_partitions;
- nb_parts = ARRAY_SIZE(adsbitsy_partitions);
-- sa1100_map.size = ADSBITSY_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
- }
- #endif
- #ifdef CONFIG_SA1100_ASSABET
- if (machine_is_assabet()) {
-- parts = assabet_partitions;
-+ *parts = assabet_partitions;
- nb_parts = ARRAY_SIZE(assabet_partitions);
-- sa1100_map.size = ASSABET_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4()) {
-- parts = badge4_partitions;
-+ *parts = badge4_partitions;
- nb_parts = ARRAY_SIZE(badge4_partitions);
-- sa1100_map.size = BADGE4_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_CERF
- if (machine_is_cerf()) {
-- parts = cerf_partitions;
-+ *parts = cerf_partitions;
- nb_parts = ARRAY_SIZE(cerf_partitions);
-- sa1100_map.size = CERF_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_CONSUS
- if (machine_is_consus()) {
-- parts = consus_partitions;
-+ *parts = consus_partitions;
- nb_parts = ARRAY_SIZE(consus_partitions);
-- sa1100_map.size = CONSUS_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FLEXANET
- if (machine_is_flexanet()) {
-- parts = flexanet_partitions;
-+ *parts = flexanet_partitions;
- nb_parts = ARRAY_SIZE(flexanet_partitions);
-- sa1100_map.size = FLEXANET_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FREEBIRD
- if (machine_is_freebird()) {
-- parts = freebird_partitions;
-+ *parts = freebird_partitions;
- nb_parts = ARRAY_SIZE(freebird_partitions);
-- sa1100_map.size = FREEBIRD_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_FRODO
- if (machine_is_frodo()) {
-- parts = frodo_partitions;
-+ *parts = frodo_partitions;
- nb_parts = ARRAY_SIZE(frodo_partitions);
-- sa1100_map.size = FRODO_FLASH_SIZE;
-- base = 0x00000000;
- }
- #endif
- #ifdef CONFIG_SA1100_GRAPHICSCLIENT
- if (machine_is_graphicsclient()) {
-- parts = graphicsclient_partitions;
-+ *parts = graphicsclient_partitions;
- nb_parts = ARRAY_SIZE(graphicsclient_partitions);
-- sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
- }
- #endif
- #ifdef CONFIG_SA1100_GRAPHICSMASTER
- if (machine_is_graphicsmaster()) {
-- parts = graphicsmaster_partitions;
-+ *parts = graphicsmaster_partitions;
- nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
-- sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE;
-- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
- }
- #endif
--#ifdef CONFIG_SA1100_H3600
-- if (machine_is_h3600()) {
-- parts = h3600_partitions;
-- nb_parts = ARRAY_SIZE(h3600_partitions);
-- sa1100_map.size = H3600_FLASH_SIZE;
-- sa1100_map.set_vpp = h3600_set_vpp;
-+#ifdef CONFIG_SA1100_H3XXX
-+ if (machine_is_h3xxx()) {
-+ *parts = h3xxx_partitions;
-+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
-+ }
-+#endif
-+#ifdef CONFIG_SA1100_HACKKIT
-+ if (machine_is_hackkit()) {
-+ *parts = hackkit_partitions;
-+ nb_parts = ARRAY_SIZE(hackkit_partitions);
- }
- #endif
- #ifdef CONFIG_SA1100_HUW_WEBPANEL
- if (machine_is_huw_webpanel()) {
-- parts = huw_webpanel_partitions;
-+ *parts = huw_webpanel_partitions;
- nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
-- sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_JORNADA720
- if (machine_is_jornada720()) {
-- parts = jornada720_partitions;
-+ *parts = jornada720_partitions;
- nb_parts = ARRAY_SIZE(jornada720_partitions);
-- sa1100_map.size = JORNADA720_FLASH_SIZE;
-- sa1100_map.set_vpp = jornada720_set_vpp;
- }
- #endif
- #ifdef CONFIG_SA1100_PANGOLIN
- if (machine_is_pangolin()) {
-- parts = pangolin_partitions;
-+ *parts = pangolin_partitions;
- nb_parts = ARRAY_SIZE(pangolin_partitions);
-- sa1100_map.size = PANGOLIN_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_PT_SYSTEM3
- if (machine_is_pt_system3()) {
-- parts = system3_partitions;
-+ *parts = system3_partitions;
- nb_parts = ARRAY_SIZE(system3_partitions);
-- sa1100_map.size = SYSTEM3_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SHANNON
- if (machine_is_shannon()) {
-- parts = shannon_partitions;
-+ *parts = shannon_partitions;
- nb_parts = ARRAY_SIZE(shannon_partitions);
-- sa1100_map.size = SHANNON_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SHERMAN
- if (machine_is_sherman()) {
-- parts = sherman_partitions;
-+ *parts = sherman_partitions;
- nb_parts = ARRAY_SIZE(sherman_partitions);
-- sa1100_map.size = SHERMAN_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_SIMPAD
- if (machine_is_simpad()) {
-- parts = simpad_partitions;
-+ *parts = simpad_partitions;
- nb_parts = ARRAY_SIZE(simpad_partitions);
-- sa1100_map.size = SIMPAD_FLASH_SIZE;
- }
- #endif
- #ifdef CONFIG_SA1100_STORK
- if (machine_is_stork()) {
-- parts = stork_partitions;
-+ *parts = stork_partitions;
- nb_parts = ARRAY_SIZE(stork_partitions);
-- sa1100_map.size = STORK_FLASH_SIZE;
-+ }
-+#endif
-+#ifdef CONFIG_SA1100_TRIZEPS
-+ if (machine_is_trizeps()) {
-+ *parts = trizeps_partitions;
-+ nb_parts = ARRAY_SIZE(trizeps_partitions);
- }
- #endif
- #ifdef CONFIG_SA1100_YOPY
- if (machine_is_yopy()) {
-- parts = yopy_partitions;
-+ *parts = yopy_partitions;
- nb_parts = ARRAY_SIZE(yopy_partitions);
-- sa1100_map.size = YOPY_FLASH_SIZE;
- }
- #endif
-
-+ return nb_parts;
-+}
-+#endif
-+
-+struct sa_info {
-+ unsigned long base;
-+ unsigned long size;
-+ int width;
-+ void *vbase;
-+ void (*set_vpp)(struct map_info *, int);
-+ struct map_info *map;
-+ struct mtd_info *mtd;
-+ struct resource *res;
-+};
-+
-+#define NR_SUBMTD 4
-+
-+static struct sa_info info[NR_SUBMTD];
-+
-+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
-+{
-+ struct mtd_info *subdev[nr];
-+ struct map_info *maps;
-+ int i, found = 0, ret = 0;
-+
- /*
-- * For simple flash devices, use ioremap to map the flash.
-+ * Allocate the map_info structs in one go.
- */
-- if (base != (unsigned long)-1) {
-- if (!request_mem_region(base, sa1100_map.size, "flash"))
-- return -EBUSY;
-- sa1100_map.map_priv_2 = base;
-- sa1100_map.map_priv_1 = (unsigned long)
-- ioremap(base, sa1100_map.size);
-+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
-+ if (!maps)
-+ return -ENOMEM;
-+
-+ memset(maps, 0, sizeof(struct map_info) * nr);
-+
-+ /*
-+ * Claim and then map the memory regions.
-+ */
-+ for (i = 0; i < nr; i++) {
-+ if (sa[i].base == (unsigned long)-1)
-+ break;
-+
-+ sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
-+ if (!sa[i].res) {
-+ ret = -EBUSY;
-+ break;
-+ }
-+
-+ sa[i].map = maps + i;
-+
-+ sa[i].vbase = ioremap(sa[i].base, sa[i].size);
-+ if (!sa[i].vbase) {
- ret = -ENOMEM;
-- if (!sa1100_map.map_priv_1)
-- goto out_err;
-+ break;
- }
-
-+ sa[i].map->virt = (unsigned long)sa[i].vbase;
-+ sa[i].map->phys = sa[i].base;
-+ sa[i].map->set_vpp = sa[i].set_vpp;
-+ sa[i].map->buswidth = sa[i].width;
-+ sa[i].map->size = sa[i].size;
-+
-+ simple_map_init(sa[i].map);
-+
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
-- printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
-- mymtd = do_map_probe("cfi_probe", &sa1100_map);
-+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
-+ if (sa[i].mtd == NULL) {
- ret = -ENXIO;
-- if (!mymtd)
-- goto out_err;
-- mymtd->module = THIS_MODULE;
-+ break;
-+ }
-+ sa[i].mtd->owner = THIS_MODULE;
-+ subdev[i] = sa[i].mtd;
-+
-+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
-+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
-+ sa[i].width * 8);
-+ found += 1;
-+ }
-
- /*
-- * Dynamic partition selection stuff (might override the static ones)
-+ * ENXIO is special. It means we didn't find a chip when
-+ * we probed. We need to tear down the mapping, free the
-+ * resource and mark it as such.
- */
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-+ if (ret == -ENXIO) {
-+ iounmap(sa[i].vbase);
-+ sa[i].vbase = NULL;
-+ release_resource(sa[i].res);
-+ sa[i].res = NULL;
-+ }
-
-- if (ret > 0) {
-- part_type = "RedBoot";
-- parsed_nr_parts = ret;
-+ /*
-+ * If we found one device, don't bother with concat support.
-+ * If we found multiple devices, use concat if we have it
-+ * available, otherwise fail.
-+ */
-+ if (ret == 0 || ret == -ENXIO) {
-+ if (found == 1) {
-+ *rmtd = subdev[0];
-+ ret = 0;
-+ } else if (found > 1) {
-+ /*
-+ * We detected multiple devices. Concatenate
-+ * them together.
-+ */
-+#ifdef CONFIG_MTD_CONCAT
-+ *rmtd = mtd_concat_create(subdev, found,
-+ "sa1100 flash");
-+ if (*rmtd == NULL)
-+ ret = -ENXIO;
-+#else
-+ printk(KERN_ERR "SA1100 flash: multiple devices "
-+ "found but MTD concat support disabled.\n");
-+ ret = -ENXIO;
-+#endif
- }
- }
-+
-+ /*
-+ * If we failed, clean up.
-+ */
-+ if (ret) {
-+ do {
-+ if (sa[i].mtd)
-+ map_destroy(sa[i].mtd);
-+ if (sa[i].vbase)
-+ iounmap(sa[i].vbase);
-+ if (sa[i].res)
-+ release_resource(sa[i].res);
-+ } while (i--);
-+
-+ kfree(maps);
-+ }
-+
-+ return ret;
-+}
-+
-+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
-+{
-+ int i;
-+
-+ del_mtd_partitions(mtd);
-+
-+#ifdef CONFIG_MTD_CONCAT
-+ if (mtd != sa[0].mtd)
-+ mtd_concat_destroy(mtd);
- #endif
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- if (parsed_nr_parts == 0) {
-- int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100");
-- if (ret > 0) {
-- part_type = "Command Line";
-- parsed_nr_parts = ret;
-+
-+ for (i = NR_SUBMTD; i >= 0; i--) {
-+ if (sa[i].mtd)
-+ map_destroy(sa[i].mtd);
-+ if (sa[i].vbase)
-+ iounmap(sa[i].vbase);
-+ if (sa[i].res)
-+ release_resource(sa[i].res);
- }
-+ kfree(sa[0].map);
-+}
-+
-+/*
-+ * A Thought: can we automatically detect the flash?
-+ * - Check to see if the region is busy (yes -> failure)
-+ * - Is the MSC setup for flash (no -> failure)
-+ * - Probe for flash
-+ */
-+
-+static struct map_info sa1100_probe_map __initdata = {
-+ .name = "SA1100-flash",
-+};
-+
-+static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
-+{
-+ struct mtd_info *mtd;
-+
-+ printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
-+ phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
-+
-+ if (check_mem_region(phys, 0x08000000)) {
-+ printk("busy\n");
-+ return;
- }
--#endif
-
-- if (parsed_nr_parts > 0) {
-- parts = parsed_parts;
-- nb_parts = parsed_nr_parts;
-+ if ((msc & 3) == 1) {
-+ printk("wrong type\n");
-+ return;
- }
-
-- if (nb_parts == 0) {
-- printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n");
-- add_mtd_device(mymtd);
-- } else {
-- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-- add_mtd_partitions(mymtd, parts, nb_parts);
-+ sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
-+ sa1100_probe_map.size = SZ_1M;
-+ sa1100_probe_map.phys = phys;
-+ sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
-+ if (sa1100_probe_map.virt == 0)
-+ goto fail;
-+ simple_map_init(&sa1100_probe_map);
-+
-+ /* Shame cfi_probe blurts out kernel messages... */
-+ mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
-+ if (mtd)
-+ map_destroy(mtd);
-+ iounmap((void *)sa1100_probe_map.virt);
-+
-+ if (!mtd)
-+ goto fail;
-+
-+ printk("pass\n");
-+ return;
-+
-+ fail:
-+ printk("failed\n");
-+}
-+
-+static void __init sa1100_probe_flash(void)
-+{
-+ printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n");
-+ sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
-+ sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
-+ sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
-+ sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
-+ sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
-+ sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
-+ printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
-+}
-+
-+static int __init sa1100_locate_flash(void)
-+{
-+ int i, nr = -ENODEV;
-+
-+ sa1100_probe_flash();
-+
-+ if (machine_is_adsbitsy()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_assabet()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ info[1].base = SA1100_CS1_PHYS; /* neponset */
-+ info[1].size = SZ_32M;
-+ nr = 2;
-+ }
-+ if (machine_is_badge4()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ nr = 1;
-+ }
-+ if (machine_is_cerf()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_consus()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_flexanet()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_freebird()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_frodo()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_graphicsclient()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
- }
-- return 0;
-+ if (machine_is_graphicsmaster()) {
-+ info[0].base = SA1100_CS1_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_h3xxx()) {
-+ info[0].set_vpp = h3xxx_set_vpp;
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_huw_webpanel()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_itsy()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_jornada720()) {
-+ info[0].set_vpp = jornada720_set_vpp;
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_nanoengine()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[1].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_pangolin()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ nr = 1;
-+ }
-+ if (machine_is_pfs168()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_pleb()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_4M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_4M;
-+ nr = 2;
-+ }
-+ if (machine_is_pt_system3()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_shannon()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_4M;
-+ nr = 1;
-+ }
-+ if (machine_is_sherman()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_simpad()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_16M;
-+ nr = 2;
-+ }
-+ if (machine_is_stork()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_32M;
-+ nr = 1;
-+ }
-+ if (machine_is_trizeps()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_16M;
-+ nr = 1;
-+ }
-+ if (machine_is_victor()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_2M;
-+ nr = 1;
-+ }
-+ if (machine_is_yopy()) {
-+ info[0].base = SA1100_CS0_PHYS;
-+ info[0].size = SZ_64M;
-+ info[1].base = SA1100_CS1_PHYS;
-+ info[1].size = SZ_64M;
-+ nr = 2;
-+ }
-+
-+ if (nr < 0)
-+ return nr;
-
-- out_err:
-- if (sa1100_map.map_priv_2 != -1) {
-- iounmap((void *)sa1100_map.map_priv_1);
-- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
-+ /*
-+ * Retrieve the buswidth from the MSC registers.
-+ * We currently only implement CS0 and CS1 here.
-+ */
-+ for (i = 0; i < nr; i++) {
-+ switch (info[i].base) {
-+ default:
-+ printk(KERN_WARNING "SA1100 flash: unknown base address "
-+ "0x%08lx, assuming CS0\n", info[i].base);
-+ case SA1100_CS0_PHYS:
-+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
-+ break;
-+
-+ case SA1100_CS1_PHYS:
-+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
-+ break;
- }
-- return ret;
-+ }
-+
-+ return nr;
- }
-
--static void __exit sa1100_mtd_cleanup(void)
-+static struct mtd_partition *parsed_parts;
-+const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-+
-+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
- {
-- if (mymtd) {
-- del_mtd_partitions(mymtd);
-- map_destroy(mymtd);
-- if (parsed_parts)
-- kfree(parsed_parts);
-+ const char *part_type = NULL;
-+ int nr_parts = 0;
-+
-+ do {
-+ /*
-+ * Partition selection stuff.
-+ */
-+#ifdef CONFIG_MTD_PARTITIONS
-+ nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
-+ if (nr_parts > 0) {
-+ part_type = "dynamic";
-+ break;
- }
-- if (sa1100_map.map_priv_2 != -1) {
-- iounmap((void *)sa1100_map.map_priv_1);
-- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
-+#endif
-+#ifdef CONFIG_MTD_SA1100_STATICMAP
-+ nr_parts = sa1100_static_partitions(&parsed_parts);
-+ if (nr_parts > 0) {
-+ part_type = "static";
-+ break;
- }
-+#endif
-+ } while (0);
-+
-+ if (nr_parts == 0) {
-+ printk(KERN_NOTICE "SA1100 flash: no partition info "
-+ "available, registering whole flash\n");
-+ add_mtd_device(mtd);
-+ } else {
-+ printk(KERN_NOTICE "SA1100 flash: using %s partition "
-+ "definition\n", part_type);
-+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
-+ }
-+
-+ /* Always succeeds. */
-+}
-+
-+static void __exit sa1100_destroy_partitions(void)
-+{
-+ if (parsed_parts)
-+ kfree(parsed_parts);
-+}
-+
-+static struct mtd_info *mymtd;
-+
-+static int __init sa1100_mtd_init(void)
-+{
-+ int ret;
-+ int nr;
-+
-+ nr = sa1100_locate_flash();
-+ if (nr < 0)
-+ return nr;
-+
-+ ret = sa1100_setup_mtd(info, nr, &mymtd);
-+ if (ret == 0)
-+ sa1100_locate_partitions(mymtd);
-+
-+ return ret;
-+}
-+
-+static void __exit sa1100_mtd_cleanup(void)
-+{
-+ sa1100_destroy_mtd(info, mymtd);
-+ sa1100_destroy_partitions();
- }
-
- module_init(sa1100_mtd_init);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sbc8240.c linux/drivers/mtd/maps/sbc8240.c
---- linux-mips-2.4.27/drivers/mtd/maps/sbc8240.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/maps/sbc8240.c 2004-11-19 10:25:11.967189456 +0100
-@@ -0,0 +1,417 @@
-+/*
-+ * Handle mapping of the flash memory access routines on the SBC8240 board.
-+ *
-+ * Carolyn Smith, Tektronix, Inc.
-+ *
-+ * This code is GPLed
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+/*
-+ * The SBC8240 has 2 flash banks.
-+ * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
-+ * It contains the U-Boot code (7 sectors) and the environment (1 sector).
-+ * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
-+ * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
-+ * Both parts are JEDEC compatible.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#include <linux/mtd/partitions.h>
-+#endif
-+
-+#define DEBUG
-+
-+#ifdef DEBUG
-+# define debugk(fmt,args...) printk(fmt ,##args)
-+#else
-+# define debugk(fmt,args...)
-+#endif
-+
-+
-+#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */
-+#define WINDOW_SIZE0 0x00080000
-+#define BUSWIDTH0 1
-+
-+#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */
-+#define WINDOW_SIZE1 0x00400000
-+#define BUSWIDTH1 8
-+
-+#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */
-+#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */
-+
-+
-+static __u8 sbc8240_read8 (struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readb(map->map_priv_1 + ofs);
-+}
-+
-+static __u16 sbc8240_read16 (struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readw(map->map_priv_1 + ofs);
-+}
-+
-+static __u32 sbc8240_read32 (struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readl(map->map_priv_1 + ofs);
-+}
-+
-+unsigned long long result64;
-+
-+static __u64 sbc8240_read64 (struct map_info *map, unsigned long ofs)
-+{
-+ unsigned long flags, msr, saved_msr;
-+ volatile long saved_fr[2];
-+ volatile unsigned long long result;
-+ volatile unsigned long *p;
-+
-+ save_flags(flags);
-+ cli();
-+
-+ /* turn off floating point unavailable exceptions */
-+
-+ __asm__ __volatile__ (
-+ "mfmsr %0"
-+ : "=r" (msr) :);
-+
-+ saved_msr = msr;
-+ msr |= MSR_FP;
-+ msr &= ~(MSR_FE0 | MSR_FE1);
-+
-+ __asm__ __volatile__ (
-+ "mtmsr %0\n"
-+ "isync\n"
-+ : : "r" (msr));
-+
-+ /* read the data via a floating point register */
-+
-+ ofs = map->map_priv_1 + ofs;
-+ p = (unsigned long *) &result64;
-+
-+ __asm__ __volatile__ (
-+ "lfd 1,0(%1)\n"
-+ "stfd 1,0(%0)\n"
-+ : : "r" (p), "r" (ofs)
-+ );
-+
-+ /* restore state */
-+
-+ __asm__ __volatile__ (
-+ "mtmsr %0\n"
-+ "isync\n"
-+ : : "r" (saved_msr));
-+
-+ restore_flags(flags);
-+
-+ p = (unsigned long *) &result64;
-+ debugk("sbc8240_read64 ofs 0x%x result 0x%08x%08x\n", ofs, *p, *(p+1));
-+
-+ return result64;
-+}
-+
-+static void sbc8240_copy_from (struct map_info *map,
-+ void *to, unsigned long from, ssize_t len)
-+{
-+ memcpy_fromio (to, (void *) (map->map_priv_1 + from), len);
-+}
-+
-+static void sbc8240_write8 (struct map_info *map, __u8 d, unsigned long adr)
-+{
-+ __raw_writeb(d, map->map_priv_1 + adr);
-+ mb();
-+}
-+
-+static void sbc8240_write16 (struct map_info *map, __u16 d,
-+ unsigned long adr)
-+{
-+ __raw_writew(d, map->map_priv_1 + adr);
-+ mb();
-+}
-+
-+static void sbc8240_write32 (struct map_info *map, __u32 d,
-+ unsigned long adr)
-+{
-+ __raw_writel(d, map->map_priv_1 + adr);
-+ mb();
-+}
-+
-+static void sbc8240_write64 (struct map_info *map, __u64 data,
-+ unsigned long adr)
-+{
-+ unsigned long long tmp;
-+ unsigned long flags, msr, saved_msr, *p;
-+ volatile long saved_fr[2];
-+
-+ save_flags(flags);
-+ cli();
-+
-+ /* turn off floating point unavailable exceptions */
-+
-+ __asm__ __volatile__ (
-+ "mfmsr %0"
-+ : "=r" (msr) :);
-+
-+ saved_msr = msr;
-+ msr |= MSR_FP;
-+ msr &= ~(MSR_FE0 | MSR_FE1);
-+
-+ __asm__ __volatile__ (
-+ "mtmsr %0\n"
-+ "isync\n"
-+ : : "r" (msr));
-+
-+
-+ /* write the data via a floating point register */
-+
-+ tmp = data;
-+ p = (unsigned long *) &tmp;
-+ adr = map->map_priv_1 + adr;
-+ debugk("sbc8240_write64 adr 0x%x data 0x%08x%08x\n", adr, *p, *(p+1));
-+
-+ __asm__ __volatile__ (
-+ "stfd 1,0(%2)\n"
-+ "lfd 1,0(%0)\n"
-+ "stfd 1,0(%1)\n"
-+ "lfd 1,0(%2)\n"
-+ : : "r" (p), "r" (adr), "b" (saved_fr)
-+ );
-+
-+ /* restore state */
-+
-+ __asm__ __volatile__ (
-+ "mtmsr %0\n"
-+ "isync\n"
-+ : : "r" (saved_msr));
-+
-+ restore_flags(flags);
-+}
-+
-+static void sbc8240_copy_to (struct map_info *map,
-+ unsigned long to, const void *from, ssize_t len)
-+{
-+ memcpy_toio ((void *) (map->map_priv_1 + to), from, len);
-+}
-+
-+static struct map_info sbc8240_map[2] = {
-+ {
-+ .name = "sbc8240 Flash Bank #0",
-+ .size = WINDOW_SIZE0,
-+ .buswidth = BUSWIDTH0,
-+ .read8 = sbc8240_read8,
-+ .read16 = sbc8240_read16,
-+ .read32 = sbc8240_read32,
-+ .read64 = sbc8240_read64,
-+ .copy_from = sbc8240_copy_from,
-+ .write8 = sbc8240_write8,
-+ .write16 = sbc8240_write16,
-+ .write32 = sbc8240_write32,
-+ .write64 = sbc8240_write64,
-+ .copy_to = sbc8240_copy_to
-+ },
-+ {
-+ .name = "sbc8240 Flash Bank #1",
-+ .size = WINDOW_SIZE1,
-+ .buswidth = BUSWIDTH1,
-+ .read8 = sbc8240_read8,
-+ .read16 = sbc8240_read16,
-+ .read32 = sbc8240_read32,
-+ .read64 = sbc8240_read64,
-+ .copy_from = sbc8240_copy_from,
-+ .write8 = sbc8240_write8,
-+ .write16 = sbc8240_write16,
-+ .write32 = sbc8240_write32,
-+ .write64 = sbc8240_write64,
-+ .copy_to = sbc8240_copy_to
-+ }
-+};
-+
-+#define NUM_FLASH_BANKS (sizeof(sbc8240_map) / sizeof(struct map_info))
-+
-+/*
-+ * The following defines the partition layout of SBC8240 boards.
-+ *
-+ * See include/linux/mtd/partitions.h for definition of the
-+ * mtd_partition structure.
-+ *
-+ * The *_max_flash_size is the maximum possible mapped flash size
-+ * which is not necessarily the actual flash size. It must correspond
-+ * to the value specified in the mapping definition defined by the
-+ * "struct map_desc *_io_desc" for the corresponding machine.
-+ */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+
-+static struct mtd_partition sbc8240_uboot_partitions [] = {
-+ /* Bank 0 */
-+ {
-+ .name = "U-boot", /* U-Boot Firmware */
-+ .offset = 0,
-+ .size = 0x00070000, /* 7 x 64 KiB sectors */
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ },
-+ {
-+ .name = "environment", /* U-Boot environment */
-+ .offset = 0x00070000,
-+ .size = 0x00010000, /* 1 x 64 KiB sector */
-+ },
-+};
-+
-+static struct mtd_partition sbc8240_fs_partitions [] = {
-+ {
-+ .name = "jffs", /* JFFS filesystem */
-+ .offset = 0,
-+ .size = 0x003C0000, /* 4 * 15 * 64KiB */
-+ },
-+ {
-+ .name = "tmp32",
-+ .offset = 0x003C0000,
-+ .size = 0x00020000, /* 4 * 32KiB */
-+ },
-+ {
-+ .name = "tmp8a",
-+ .offset = 0x003E0000,
-+ .size = 0x00008000, /* 4 * 8KiB */
-+ },
-+ {
-+ .name = "tmp8b",
-+ .offset = 0x003E8000,
-+ .size = 0x00008000, /* 4 * 8KiB */
-+ },
-+ {
-+ .name = "tmp16",
-+ .offset = 0x003F0000,
-+ .size = 0x00010000, /* 4 * 16KiB */
-+ }
-+};
-+
-+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-+
-+/* trivial struct to describe partition information */
-+struct mtd_part_def
-+{
-+ int nums;
-+ unsigned char *type;
-+ struct mtd_partition* mtd_part;
-+};
-+
-+static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-+static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-+
-+
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+
-+int __init init_sbc8240_mtd (void)
-+{
-+ static struct _cjs {
-+ u_long addr;
-+ u_long size;
-+ } pt[NUM_FLASH_BANKS] = {
-+ {
-+ .addr = WINDOW_ADDR0,
-+ .size = WINDOW_SIZE0
-+ },
-+ {
-+ .addr = WINDOW_ADDR1,
-+ .size = WINDOW_SIZE1
-+ },
-+ };
-+
-+ int devicesfound = 0;
-+ int i;
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-+
-+ sbc8240_map[i].map_priv_1 =
-+ (unsigned long) ioremap (pt[i].addr, pt[i].size);
-+ if (!sbc8240_map[i].map_priv_1) {
-+ printk (MSG_PREFIX "failed to ioremap\n");
-+ return -EIO;
-+ }
-+
-+ sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-+
-+ if (sbc8240_mtd[i]) {
-+ sbc8240_mtd[i]->module = THIS_MODULE;
-+ devicesfound++;
-+ }
-+ }
-+
-+ if (!devicesfound) {
-+ printk(KERN_NOTICE MSG_PREFIX
-+ "No suppported flash chips found!\n");
-+ return -ENXIO;
-+ }
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions;
-+ sbc8240_part_banks[0].type = "static image";
-+ sbc8240_part_banks[0].nums = NB_OF(sbc8240_uboot_partitions);
-+ sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions;
-+ sbc8240_part_banks[1].type = "static file system";
-+ sbc8240_part_banks[1].nums = NB_OF(sbc8240_fs_partitions);
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+
-+ if (!sbc8240_mtd[i]) continue;
-+ if (sbc8240_part_banks[i].nums == 0) {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "No partition info available, registering whole device\n");
-+ add_mtd_device(sbc8240_mtd[i]);
-+ } else {
-+ printk (KERN_NOTICE MSG_PREFIX
-+ "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
-+ add_mtd_partitions (sbc8240_mtd[i],
-+ sbc8240_part_banks[i].mtd_part,
-+ sbc8240_part_banks[i].nums);
-+ }
-+ }
-+#else
-+ printk(KERN_NOTICE MSG_PREFIX
-+ "Registering %d flash banks at once\n", devicesfound);
-+
-+ for (i = 0; i < devicesfound; i++) {
-+ add_mtd_device(sbc8240_mtd[i]);
-+ }
-+#endif /* CONFIG_MTD_PARTITIONS */
-+
-+ return devicesfound == 0 ? -ENXIO : 0;
-+}
-+
-+static void __exit cleanup_sbc8240_mtd (void)
-+{
-+ int i;
-+
-+ for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+ if (sbc8240_mtd[i]) {
-+ del_mtd_device (sbc8240_mtd[i]);
-+ map_destroy (sbc8240_mtd[i]);
-+ }
-+ if (sbc8240_map[i].map_priv_1) {
-+ iounmap ((void *) sbc8240_map[i].map_priv_1);
-+ sbc8240_map[i].map_priv_1 = 0;
-+ }
-+ }
-+}
-+
-+module_init (init_sbc8240_mtd);
-+module_exit (cleanup_sbc8240_mtd);
-+
-+MODULE_LICENSE ("GPL");
-+MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-+MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-+
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sbc_gxx.c linux/drivers/mtd/maps/sbc_gxx.c
---- linux-mips-2.4.27/drivers/mtd/maps/sbc_gxx.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/sbc_gxx.c 2004-11-19 10:25:11.969189152 +0100
-@@ -17,7 +17,7 @@
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-- $Id$
-+ $Id$
-
- The SBC-MediaGX / SBC-GXx has up to 16 MiB of
- Intel StrataFlash (28F320/28F640) in x8 mode.
-@@ -91,14 +91,14 @@
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
- static struct mtd_partition partition_info[]={
-- { name: "SBC-GXx flash boot partition",
-- offset: 0,
-- size: BOOT_PARTITION_SIZE_KiB*1024 },
-- { name: "SBC-GXx flash data partition",
-- offset: BOOT_PARTITION_SIZE_KiB*1024,
-- size: (DATA_PARTITION_SIZE_KiB)*1024 },
-- { name: "SBC-GXx flash application partition",
-- offset: (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
-+ { .name = "SBC-GXx flash boot partition",
-+ .offset = 0,
-+ .size = BOOT_PARTITION_SIZE_KiB*1024 },
-+ { .name = "SBC-GXx flash data partition",
-+ .offset = BOOT_PARTITION_SIZE_KiB*1024,
-+ .size = (DATA_PARTITION_SIZE_KiB)*1024 },
-+ { .name = "SBC-GXx flash application partition",
-+ .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
- };
-
- #define NUM_PARTITIONS 3
-@@ -203,19 +203,20 @@
- }
-
- static struct map_info sbc_gxx_map = {
-- name: "SBC-GXx flash",
-- size: MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
-+ .name = "SBC-GXx flash",
-+ .phys = NO_XIP,
-+ .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
- of flash so the cfi probe routines find all
- the chips */
-- buswidth: 1,
-- read8: sbc_gxx_read8,
-- read16: sbc_gxx_read16,
-- read32: sbc_gxx_read32,
-- copy_from: sbc_gxx_copy_from,
-- write8: sbc_gxx_write8,
-- write16: sbc_gxx_write16,
-- write32: sbc_gxx_write32,
-- copy_to: sbc_gxx_copy_to
-+ .buswidth = 1,
-+ .read8 = sbc_gxx_read8,
-+ .read16 = sbc_gxx_read16,
-+ .read32 = sbc_gxx_read32,
-+ .copy_from = sbc_gxx_copy_from,
-+ .write8 = sbc_gxx_write8,
-+ .write16 = sbc_gxx_write16,
-+ .write32 = sbc_gxx_write32,
-+ .copy_to = sbc_gxx_copy_to
- };
-
- /* MTD device for all of the flash. */
-@@ -234,12 +235,6 @@
-
- int __init init_sbc_gxx(void)
- {
-- if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) {
-- printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-- sbc_gxx_map.name,
-- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-- return -EAGAIN;
-- }
- iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
- if (!iomapadr) {
- printk( KERN_ERR"%s: failed to ioremap memory region\n",
-@@ -247,7 +242,14 @@
- return -EIO;
- }
-
-- request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" );
-+ if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) {
-+ printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-+ sbc_gxx_map.name,
-+ PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-+ iounmap((void *)iomapadr);
-+ return -EAGAIN;
-+ }
-+
-
- printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
- sbc_gxx_map.name,
-@@ -261,7 +263,7 @@
- return -ENXIO;
- }
-
-- all_mtd->module=THIS_MODULE;
-+ all_mtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS );
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sc520cdp.c linux/drivers/mtd/maps/sc520cdp.c
---- linux-mips-2.4.27/drivers/mtd/maps/sc520cdp.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/sc520cdp.c 2004-11-19 10:25:11.970189000 +0100
-@@ -16,7 +16,7 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *
-- * $Id$
-+ * $Id$
- *
- *
- * The SC520CDP is an evaluation board for the Elan SC520 processor available
-@@ -29,6 +29,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -84,88 +85,25 @@
- #define WINDOW_SIZE_1 0x00800000
- #define WINDOW_SIZE_2 0x00080000
-
--static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs)
--{
-- return readb(map->map_priv_1 + ofs);
--}
--
--static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs)
--{
-- return readw(map->map_priv_1 + ofs);
--}
--
--static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs)
--{
-- return readl(map->map_priv_1 + ofs);
--}
--
--static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- writeb(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- writew(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- writel(d, map->map_priv_1 + adr);
--}
--
--static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
-
- static struct map_info sc520cdp_map[] = {
- {
-- name: "SC520CDP Flash Bank #0",
-- size: WINDOW_SIZE_0,
-- buswidth: 4,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_0
-+ .name = "SC520CDP Flash Bank #0",
-+ .size = WINDOW_SIZE_0,
-+ .buswidth = 4,
-+ .phys = WINDOW_ADDR_0
- },
- {
-- name: "SC520CDP Flash Bank #1",
-- size: WINDOW_SIZE_1,
-- buswidth: 4,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_1
-+ .name = "SC520CDP Flash Bank #1",
-+ .size = WINDOW_SIZE_1,
-+ .buswidth = 4,
-+ .phys = WINDOW_ADDR_1
- },
- {
-- name: "SC520CDP DIL Flash",
-- size: WINDOW_SIZE_2,
-- buswidth: 1,
-- read8: sc520cdp_read8,
-- read16: sc520cdp_read16,
-- read32: sc520cdp_read32,
-- copy_from: sc520cdp_copy_from,
-- write8: sc520cdp_write8,
-- write16: sc520cdp_write16,
-- write32: sc520cdp_write32,
-- copy_to: sc520cdp_copy_to,
-- map_priv_2: WINDOW_ADDR_2
-+ .name = "SC520CDP DIL Flash",
-+ .size = WINDOW_SIZE_2,
-+ .buswidth = 1,
-+ .phys = WINDOW_ADDR_2
- },
- };
-
-@@ -255,9 +193,9 @@
- /* map in SC520's MMCR area */
- mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
- if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */
-- /* force map_priv_2 fields to BIOS defaults: */
-+ /* force physical address fields to BIOS defaults: */
- for(i = 0; i < NUM_FLASH_BANKS; i++)
-- sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
-+ sc520cdp_map[i].phys = par_table[i].default_address;
- return;
- }
-
-@@ -282,7 +220,7 @@
- sc520cdp_map[i].name);
- printk(KERN_NOTICE "Trying default address 0x%lx\n",
- par_table[i].default_address);
-- sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
-+ sc520cdp_map[i].phys = par_table[i].default_address;
- }
- }
- iounmap((void *)mmcr);
-@@ -300,13 +238,18 @@
- #endif
-
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
-- printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2);
-- sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size);
-+ printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
-+ sc520cdp_map[i].size, sc520cdp_map[i].phys);
-
-- if (!sc520cdp_map[i].map_priv_1) {
-+ sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
-+
-+ if (!sc520cdp_map[i].virt) {
- printk("Failed to ioremap_nocache\n");
- return -EIO;
- }
-+
-+ simple_map_init(&sc520cdp_map[i]);
-+
- mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
- if(!mymtd[i])
- mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
-@@ -314,11 +257,11 @@
- mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
-
- if (mymtd[i]) {
-- mymtd[i]->module = THIS_MODULE;
-+ mymtd[i]->owner = THIS_MODULE;
- ++devices_found;
- }
- else {
-- iounmap((void *)sc520cdp_map[i].map_priv_1);
-+ iounmap((void *)sc520cdp_map[i].virt);
- }
- }
- if(devices_found >= 2) {
-@@ -346,9 +289,9 @@
- for (i = 0; i < NUM_FLASH_BANKS; i++) {
- if (mymtd[i])
- map_destroy(mymtd[i]);
-- if (sc520cdp_map[i].map_priv_1) {
-- iounmap((void *)sc520cdp_map[i].map_priv_1);
-- sc520cdp_map[i].map_priv_1 = 0;
-+ if (sc520cdp_map[i].virt) {
-+ iounmap((void *)sc520cdp_map[i].virt);
-+ sc520cdp_map[i].virt = 0;
- }
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/scb2_flash.c linux/drivers/mtd/maps/scb2_flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/scb2_flash.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/scb2_flash.c 2004-11-19 10:25:11.972188696 +0100
-@@ -1,6 +1,6 @@
- /*
- * MTD map driver for BIOS Flash on Intel SCB2 boards
-- * $Id$
-+ * $Id$
- * Copyright (C) 2002 Sun Microsystems, Inc.
- * Tim Hockin <thockin@sun.com>
- *
-@@ -14,7 +14,7 @@
- * try to request it here, but if it fails, we carry on anyway.
- *
- * This is how the chip is attached, so said the schematic:
-- * * a 4 MiB (32 Mb) 16 bit chip
-+ * * a 4 MiB (32 Mib) 16 bit chip
- * * a 1 MiB memory region
- * * A20 and A21 pulled up
- * * D8-D15 ignored
-@@ -48,6 +48,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -60,65 +61,13 @@
- #define SCB2_ADDR 0xfff00000
- #define SCB2_WINDOW 0x00100000
-
--static __u8 scb2_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 scb2_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static __u32 scb2_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--static void scb2_copy_from(struct map_info *map, void *to,
-- unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scb2_copy_to(struct map_info *map, unsigned long to,
-- const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- static void *scb2_ioaddr;
- static struct mtd_info *scb2_mtd;
- struct map_info scb2_map = {
-- name: "SCB2 BIOS Flash",
-- size: 0,
-- buswidth: 1,
-- read8: scb2_read8,
-- read16: scb2_read16,
-- read32: scb2_read32,
-- copy_from: scb2_copy_from,
-- write8: scb2_write8,
-- write16: scb2_write16,
-- write32: scb2_write32,
-- copy_to: scb2_copy_to,
-+ .name = "SCB2 BIOS Flash",
-+ .size = 0,
-+ .buswidth = 1,
- };
- static int region_fail;
-
-@@ -137,6 +86,8 @@
- return -1;
- }
-
-+ /* I wasn't here. I didn't see. dwmw2. */
-+
- /* the chip is sometimes bigger than the map - what a waste */
- mtd->size = map->size;
-
-@@ -211,9 +162,12 @@
- return -ENOMEM;
- }
-
-- scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr;
-+ scb2_map.phys = SCB2_ADDR;
-+ scb2_map.virt = (unsigned long)scb2_ioaddr;
- scb2_map.size = SCB2_WINDOW;
-
-+ simple_map_init(&scb2_map);
-+
- /* try to find a chip */
- scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
-
-@@ -225,7 +179,7 @@
- return -ENODEV;
- }
-
-- scb2_mtd->module = THIS_MODULE;
-+ scb2_mtd->owner = THIS_MODULE;
- if (scb2_fixup_mtd(scb2_mtd) < 0) {
- del_mtd_device(scb2_mtd);
- map_destroy(scb2_mtd);
-@@ -235,7 +189,7 @@
- return -ENODEV;
- }
-
-- printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n",
-+ printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n",
- scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
-
- add_mtd_device(scb2_mtd);
-@@ -266,19 +220,19 @@
-
- static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
- {
-- vendor: PCI_VENDOR_ID_SERVERWORKS,
-- device: PCI_DEVICE_ID_SERVERWORKS_CSB5,
-- subvendor: PCI_ANY_ID,
-- subdevice: PCI_ANY_ID
-+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
-+ .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID
- },
- { 0, }
- };
-
- static struct pci_driver scb2_flash_driver = {
-- name: "Intel SCB2 BIOS Flash",
-- id_table: scb2_flash_pci_ids,
-- probe: scb2_flash_probe,
-- remove: __devexit_p(scb2_flash_remove),
-+ .name = "Intel SCB2 BIOS Flash",
-+ .id_table = scb2_flash_pci_ids,
-+ .probe = scb2_flash_probe,
-+ .remove = __devexit_p(scb2_flash_remove),
- };
-
- static int __init
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/scx200_docflash.c linux/drivers/mtd/maps/scx200_docflash.c
---- linux-mips-2.4.27/drivers/mtd/maps/scx200_docflash.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/scx200_docflash.c 2004-11-19 10:25:11.973188544 +0100
-@@ -2,7 +2,7 @@
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
-- $Id$
-+ $Id$
-
- National Semiconductor SCx200 flash mapped with DOCCS
- */
-@@ -11,6 +11,7 @@
- #include <linux/config.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -75,46 +76,9 @@
- #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
- #endif
-
--static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readb(map->map_priv_1 + ofs);
--}
--
--static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readw(map->map_priv_1 + ofs);
--}
--
--static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
-- mb();
--}
--
--static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- static struct map_info scx200_docflash_map = {
- .name = "NatSemi SCx200 DOCCS Flash",
-- .read8 = scx200_docflash_read8,
-- .read16 = scx200_docflash_read16,
-- .copy_from = scx200_docflash_copy_from,
-- .write8 = scx200_docflash_write8,
-- .write16 = scx200_docflash_write16,
-- .copy_to = scx200_docflash_copy_to
- };
-
- int __init init_scx200_docflash(void)
-@@ -213,8 +177,11 @@
- else
- scx200_docflash_map.buswidth = 2;
-
-- scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
-- if (!scx200_docflash_map.map_priv_1) {
-+ simple_map_init(&scx200_docflash_map);
-+
-+ scx200_docflash_map.phys = docmem.start;
-+ scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
-+ if (!scx200_docflash_map.virt) {
- printk(KERN_ERR NAME ": failed to ioremap the flash\n");
- release_resource(&docmem);
- return -EIO;
-@@ -223,7 +190,7 @@
- mymtd = do_map_probe(flashtype, &scx200_docflash_map);
- if (!mymtd) {
- printk(KERN_ERR NAME ": unable to detect flash\n");
-- iounmap((void *)scx200_docflash_map.map_priv_1);
-+ iounmap((void *)scx200_docflash_map.virt);
- release_resource(&docmem);
- return -ENXIO;
- }
-@@ -231,7 +198,7 @@
- if (size < mymtd->size)
- printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
-
-- mymtd->module = THIS_MODULE;
-+ mymtd->owner = THIS_MODULE;
-
- #if PARTITION
- partition_info[3].offset = mymtd->size-partition_info[3].size;
-@@ -253,8 +220,8 @@
- #endif
- map_destroy(mymtd);
- }
-- if (scx200_docflash_map.map_priv_1) {
-- iounmap((void *)scx200_docflash_map.map_priv_1);
-+ if (scx200_docflash_map.virt) {
-+ iounmap((void *)scx200_docflash_map.virt);
- release_resource(&docmem);
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/solutionengine.c linux/drivers/mtd/maps/solutionengine.c
---- linux-mips-2.4.27/drivers/mtd/maps/solutionengine.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/solutionengine.c 2004-11-19 10:25:11.975188240 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Flash and EPROM on Hitachi Solution Engine and similar boards.
- *
-@@ -11,6 +11,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -18,60 +19,39 @@
- #include <linux/config.h>
-
-
--extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
--
--__u32 soleng_read32(struct map_info *map, unsigned long ofs)
--{
-- return __raw_readl(map->map_priv_1 + ofs);
--}
--
--void soleng_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
-- mb();
--}
--
--void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--
- static struct mtd_info *flash_mtd;
- static struct mtd_info *eprom_mtd;
-
- static struct mtd_partition *parsed_parts;
-
- struct map_info soleng_eprom_map = {
-- name: "Solution Engine EPROM",
-- size: 0x400000,
-- buswidth: 4,
-- copy_from: soleng_copy_from,
-+ .name = "Solution Engine EPROM",
-+ .size = 0x400000,
-+ .buswidth = 4,
- };
-
- struct map_info soleng_flash_map = {
-- name: "Solution Engine FLASH",
-- size: 0x400000,
-- buswidth: 4,
-- read32: soleng_read32,
-- copy_from: soleng_copy_from,
-- write32: soleng_write32,
-+ .name = "Solution Engine FLASH",
-+ .size = 0x400000,
-+ .buswidth = 4,
- };
-
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
- #ifdef CONFIG_MTD_SUPERH_RESERVE
- static struct mtd_partition superh_se_partitions[] = {
- /* Reserved for boot code, read-only */
- {
-- name: "flash_boot",
-- offset: 0x00000000,
-- size: CONFIG_MTD_SUPERH_RESERVE,
-- mask_flags: MTD_WRITEABLE,
-+ .name = "flash_boot",
-+ .offset = 0x00000000,
-+ .size = CONFIG_MTD_SUPERH_RESERVE,
-+ .mask_flags = MTD_WRITEABLE,
- },
- /* All else is writable (e.g. JFFS) */
- {
-- name: "Flash FS",
-- offset: MTDPART_OFS_NXTBLK,
-- size: MTDPART_SIZ_FULL,
-+ .name = "Flash FS",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL,
- }
- };
- #endif /* CONFIG_MTD_SUPERH_RESERVE */
-@@ -81,16 +61,22 @@
- int nr_parts = 0;
-
- /* First probe at offset 0 */
-- soleng_flash_map.map_priv_1 = P2SEGADDR(0);
-- soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000);
-+ soleng_flash_map.phys = 0;
-+ soleng_flash_map.virt = P2SEGADDR(0);
-+ soleng_eprom_map.phys = 0x01000000;
-+ soleng_eprom_map.virt = P1SEGADDR(0x01000000);
-+ simple_map_init(&soleng_eprom_map);
-+ simple_map_init(&soleng_flash_map);
-
- printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
- flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
- if (!flash_mtd) {
- /* Not there. Try swapping */
- printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n");
-- soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000);
-- soleng_eprom_map.map_priv_1 = P1SEGADDR(0);
-+ soleng_flash_map.phys = 0x01000000;
-+ soleng_flash_map.virt = P2SEGADDR(0x01000000);
-+ soleng_eprom_map.phys = 0;
-+ soleng_eprom_map.virt = P1SEGADDR(0);
- flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
- if (!flash_mtd) {
- /* Eep. */
-@@ -99,25 +85,20 @@
- }
- }
- printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
-- soleng_flash_map.map_priv_1 & 0x1fffffff,
-- soleng_eprom_map.map_priv_1 & 0x1fffffff);
-- flash_mtd->module = THIS_MODULE;
-+ soleng_flash_map.phys & 0x1fffffff,
-+ soleng_eprom_map.phys & 0x1fffffff);
-+ flash_mtd->owner = THIS_MODULE;
-
- eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
- if (eprom_mtd) {
-- eprom_mtd->module = THIS_MODULE;
-+ eprom_mtd->owner = THIS_MODULE;
- add_mtd_device(eprom_mtd);
- }
-
--#ifdef CONFIG_MTD_REDBOOT_PARTS
-- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
-- if (nr_parts > 0)
-- printk(KERN_NOTICE "Found RedBoot partition table.\n");
-- else if (nr_parts < 0)
-- printk(KERN_NOTICE "Error looking for RedBoot partitions.\n");
--#endif /* CONFIG_MTD_REDBOOT_PARTS */
-+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-+
- #if CONFIG_MTD_SUPERH_RESERVE
-- if (nr_parts == 0) {
-+ if (nr_parts <= 0) {
- printk(KERN_NOTICE "Using configured partition at 0x%08x.\n",
- CONFIG_MTD_SUPERH_RESERVE);
- parsed_parts = superh_se_partitions;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sun_uflash.c linux/drivers/mtd/maps/sun_uflash.c
---- linux-mips-2.4.27/drivers/mtd/maps/sun_uflash.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/sun_uflash.c 2004-11-19 10:25:11.976188088 +0100
-@@ -1,4 +1,4 @@
--/* $Id$
-+/* $Id$
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
-@@ -48,60 +48,11 @@
- struct list_head list;
- };
-
--__u8 uflash_read8(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readb(map->map_priv_1 + ofs));
--}
--
--__u16 uflash_read16(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readw(map->map_priv_1 + ofs));
--}
--
--__u32 uflash_read32(struct map_info *map, unsigned long ofs)
--{
-- return(__raw_readl(map->map_priv_1 + ofs));
--}
--
--void uflash_copy_from(struct map_info *map, void *to, unsigned long from,
-- ssize_t len)
--{
-- memcpy_fromio(to, map->map_priv_1 + from, len);
--}
--
--void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- __raw_writeb(d, map->map_priv_1 + adr);
--}
--
--void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- __raw_writew(d, map->map_priv_1 + adr);
--}
--
--void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- __raw_writel(d, map->map_priv_1 + adr);
--}
--
--void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
-- ssize_t len)
--{
-- memcpy_toio(map->map_priv_1 + to, from, len);
--}
-
- struct map_info uflash_map_templ = {
-- name: "SUNW,???-????",
-- size: UFLASH_WINDOW_SIZE,
-- buswidth: UFLASH_BUSWIDTH,
-- read8: uflash_read8,
-- read16: uflash_read16,
-- read32: uflash_read32,
-- copy_from: uflash_copy_from,
-- write8: uflash_write8,
-- write16: uflash_write16,
-- write32: uflash_write32,
-- copy_to: uflash_copy_to
-+ .name = "SUNW,???-????",
-+ .size = UFLASH_WINDOW_SIZE,
-+ .buswidth = UFLASH_BUSWIDTH,
- };
-
- int uflash_devinit(struct linux_ebus_device* edev)
-@@ -145,20 +96,22 @@
- if(0 != pdev->name && 0 < strlen(pdev->name)) {
- pdev->map.name = pdev->name;
- }
--
-- pdev->map.map_priv_1 =
-+ pdev->phys = edev->resource[0].start;
-+ pdev->virt =
- (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
-- if(0 == pdev->map.map_priv_1) {
-+ if(0 == pdev->map.virt) {
- printk("%s: failed to map device\n", __FUNCTION__);
- kfree(pdev->name);
- kfree(pdev);
- return(-1);
- }
-
-+ simple_map_init(&pdev->map);
-+
- /* MTD registration */
- pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
- if(0 == pdev->mtd) {
-- iounmap((void *)pdev->map.map_priv_1);
-+ iounmap((void *)pdev->map.virt);
- kfree(pdev->name);
- kfree(pdev);
- return(-ENXIO);
-@@ -166,7 +119,7 @@
-
- list_add(&pdev->list, &device_list);
-
-- pdev->mtd->module = THIS_MODULE;
-+ pdev->mtd->owner = THIS_MODULE;
-
- add_mtd_device(pdev->mtd);
- return(0);
-@@ -211,9 +164,9 @@
- del_mtd_device(udev->mtd);
- map_destroy(udev->mtd);
- }
-- if(0 != udev->map.map_priv_1) {
-- iounmap((void*)udev->map.map_priv_1);
-- udev->map.map_priv_1 = 0;
-+ if(0 != udev->map.virt) {
-+ iounmap((void*)udev->map.virt);
-+ udev->map.virt = 0;
- }
- if(0 != udev->name) {
- kfree(udev->name);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/tqm8xxl.c linux/drivers/mtd/maps/tqm8xxl.c
---- linux-mips-2.4.27/drivers/mtd/maps/tqm8xxl.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/tqm8xxl.c 2004-11-19 10:25:11.978187784 +0100
-@@ -2,7 +2,7 @@
- * Handle mapping of the flash memory access routines
- * on TQM8xxL based devices.
- *
-- * $Id$
-+ * $Id$
- *
- * based on rpxlite.c
- *
-@@ -26,6 +26,7 @@
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-+#include <linux/init.h>
- #include <asm/io.h>
-
- #include <linux/mtd/mtd.h>
-@@ -51,46 +52,6 @@
- static unsigned long num_banks;
- static unsigned long start_scan_addr;
-
--__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs)
--{
-- return *((__u8 *)(map->map_priv_1 + ofs));
--}
--
--__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs)
--{
-- return *((__u16 *)(map->map_priv_1 + ofs));
--}
--
--__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs)
--{
-- return *((__u32 *)(map->map_priv_1 + ofs));
--}
--
--void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *((__u8 *)(map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *((__u16 *)( map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *((__u32 *)(map->map_priv_1 + adr)) = d;
--}
--
--void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy_toio((void *)(map->map_priv_1 + to), from, len);
--}
--
- /*
- * Here are partition information for all known TQM8xxL series devices.
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
-@@ -107,50 +68,48 @@
- static unsigned long tqm8xxl_max_flash_size = 0x00800000;
-
- /* partition definition for first flash bank
-- * also ref. to "drivers\char\flash_config.c"
-+ * (cf. "drivers/char/flash_config.c")
- */
- static struct mtd_partition tqm8xxl_partitions[] = {
- {
-- name: "ppcboot",
-- offset: 0x00000000,
-- size: 0x00020000, /* 128KB */
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "ppcboot",
-+ .offset = 0x00000000,
-+ .size = 0x00020000, /* 128KB */
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "kernel", /* default kernel image */
-- offset: 0x00020000,
-- size: 0x000e0000,
-- mask_flags: MTD_WRITEABLE, /* force read-only */
-+ .name = "kernel", /* default kernel image */
-+ .offset = 0x00020000,
-+ .size = 0x000e0000,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
-- name: "user",
-- offset: 0x00100000,
-- size: 0x00100000,
-+ .name = "user",
-+ .offset = 0x00100000,
-+ .size = 0x00100000,
- },
- {
-- name: "initrd",
-- offset: 0x00200000,
-- size: 0x00200000,
-+ .name = "initrd",
-+ .offset = 0x00200000,
-+ .size = 0x00200000,
- }
- };
--/* partition definition for second flahs bank */
-+/* partition definition for second flash bank */
- static struct mtd_partition tqm8xxl_fs_partitions[] = {
- {
-- name: "cramfs",
-- offset: 0x00000000,
-- size: 0x00200000,
-+ .name = "cramfs",
-+ .offset = 0x00000000,
-+ .size = 0x00200000,
- },
- {
-- name: "jffs",
-- offset: 0x00200000,
-- size: 0x00200000,
-- //size: MTDPART_SIZ_FULL,
-+ .name = "jffs",
-+ .offset = 0x00200000,
-+ .size = 0x00200000,
-+ .//size = MTDPART_SIZ_FULL,
- }
- };
- #endif
-
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
- int __init init_tqm_mtd(void)
- {
- int idx = 0, ret = 0;
-@@ -160,67 +119,73 @@
-
- flash_addr = bd->bi_flashstart;
- flash_size = bd->bi_flashsize;
-- //request maximum flash size address spzce
-+
-+ //request maximum flash size address space
- start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
- if (!start_scan_addr) {
-- //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR);
-- printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
-+ printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
- return -EIO;
- }
-- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-- {
-+
-+ for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if(mtd_size >= flash_size)
- break;
-
-- printk("%s: chip probing count %d\n", __FUNCTION__, idx);
-+ printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
-
- map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
-- if(map_banks[idx] == NULL)
-- {
-- //return -ENOMEM;
-+ if(map_banks[idx] == NULL) {
- ret = -ENOMEM;
-+ /* FIXME: What if some MTD devices were probed already? */
- goto error_mem;
- }
-+
- memset((void *)map_banks[idx], 0, sizeof(struct map_info));
- map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
-- if(map_banks[idx]->name == NULL)
-- {
-- //return -ENOMEM;
-+
-+ if (!map_banks[idx]->name) {
- ret = -ENOMEM;
-+ /* FIXME: What if some MTD devices were probed already? */
- goto error_mem;
- }
-- memset((void *)map_banks[idx]->name, 0, 16);
--
- sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
-+
- map_banks[idx]->size = flash_size;
- map_banks[idx]->buswidth = 4;
-- map_banks[idx]->read8 = tqm8xxl_read8;
-- map_banks[idx]->read16 = tqm8xxl_read16;
-- map_banks[idx]->read32 = tqm8xxl_read32;
-- map_banks[idx]->copy_from = tqm8xxl_copy_from;
-- map_banks[idx]->write8 = tqm8xxl_write8;
-- map_banks[idx]->write16 = tqm8xxl_write16;
-- map_banks[idx]->write32 = tqm8xxl_write32;
-- map_banks[idx]->copy_to = tqm8xxl_copy_to;
-+
-+ simple_map_init(map_banks[idx]);
-+
-+ map_banks[idx]->virt = start_scan_addr;
-+ map_banks[idx]->phys = flash_addr;
-+ /* FIXME: This looks utterly bogus, but I'm trying to
-+ preserve the behaviour of the original (shown here)...
-+
- map_banks[idx]->map_priv_1 =
- start_scan_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
-+ */
-+
-+ if (idx && mtd_banks[idx-1]) {
-+ map_banks[idx]->virt += mtd_banks[idx-1]->size;
-+ map_banks[idx]->phys += mtd_banks[idx-1]->size;
-+ }
-+
- //start to probe flash chips
- mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
-- if(mtd_banks[idx])
-- {
-- mtd_banks[idx]->module = THIS_MODULE;
-+
-+ if (mtd_banks[idx]) {
-+ mtd_banks[idx]->owner = THIS_MODULE;
- mtd_size += mtd_banks[idx]->size;
- num_banks++;
-- printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
-+
-+ printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
- mtd_banks[idx]->name, mtd_banks[idx]->size);
- }
- }
-
- /* no supported flash chips found */
-- if(!num_banks)
-- {
-- printk("TQM8xxL: No support flash chips found!\n");
-+ if (!num_banks) {
-+ printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n");
- ret = -ENXIO;
- goto error_mem;
- }
-@@ -231,12 +196,13 @@
- */
- part_banks[0].mtd_part = tqm8xxl_partitions;
- part_banks[0].type = "Static image";
-- part_banks[0].nums = NB_OF(tqm8xxl_partitions);
-+ part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions);
-+
- part_banks[1].mtd_part = tqm8xxl_fs_partitions;
- part_banks[1].type = "Static file system";
-- part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions);
-- for(idx = 0; idx < num_banks ; idx++)
-- {
-+ part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions);
-+
-+ for(idx = 0; idx < num_banks ; idx++) {
- if (part_banks[idx].nums == 0) {
- printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
- add_mtd_device(mtd_banks[idx]);
-@@ -254,12 +220,9 @@
- #endif
- return 0;
- error_mem:
-- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-- {
-- if(map_banks[idx] != NULL)
-- {
-- if(map_banks[idx]->name != NULL)
-- {
-+ for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
-+ if(map_banks[idx] != NULL) {
-+ if(map_banks[idx]->name != NULL) {
- kfree(map_banks[idx]->name);
- map_banks[idx]->name = NULL;
- }
-@@ -267,18 +230,15 @@
- map_banks[idx] = NULL;
- }
- }
-- //return -ENOMEM;
- error:
- iounmap((void *)start_scan_addr);
-- //return -ENXIO;
- return ret;
- }
-
- static void __exit cleanup_tqm_mtd(void)
- {
- unsigned int idx = 0;
-- for(idx = 0 ; idx < num_banks ; idx++)
-- {
-+ for(idx = 0 ; idx < num_banks ; idx++) {
- /* destroy mtd_info previously allocated */
- if (mtd_banks[idx]) {
- del_mtd_partitions(mtd_banks[idx]);
-@@ -288,6 +248,7 @@
- kfree(map_banks[idx]->name);
- kfree(map_banks[idx]);
- }
-+
- if (start_scan_addr) {
- iounmap((void *)start_scan_addr);
- start_scan_addr = 0;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/tsunami_flash.c linux/drivers/mtd/maps/tsunami_flash.c
---- linux-mips-2.4.27/drivers/mtd/maps/tsunami_flash.c 2002-06-27 00:35:50.000000000 +0200
-+++ linux/drivers/mtd/maps/tsunami_flash.c 2004-11-19 10:25:11.979187632 +0100
-@@ -2,11 +2,13 @@
- * tsunami_flash.c
- *
- * flash chip on alpha ds10...
-- * $Id$
-+ * $Id$
- */
- #include <asm/io.h>
- #include <asm/core_tsunami.h>
-+#include <linux/init.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
- #define FLASH_ENABLE_PORT 0x00C00001
- #define FLASH_ENABLE_BYTE 0x01
-@@ -58,18 +60,12 @@
- static struct map_info tsunami_flash_map = {
- .name = "flash chip on the Tsunami TIG bus",
- .size = MAX_TIG_FLASH_SIZE,
-+ .phys = NO_XIP;
- .buswidth = 1,
- .read8 = tsunami_flash_read8,
-- .read16 = 0,
-- .read32 = 0,
- .copy_from = tsunami_flash_copy_from,
- .write8 = tsunami_flash_write8,
-- .write16 = 0,
-- .write32 = 0,
- .copy_to = tsunami_flash_copy_to,
-- .set_vpp = 0,
-- .map_priv_1 = 0,
--
- };
-
- static struct mtd_info *tsunami_flash_mtd;
-@@ -99,7 +95,7 @@
- tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map);
- }
- if (tsunami_flash_mtd) {
-- tsunami_flash_mtd->module = THIS_MODULE;
-+ tsunami_flash_mtd->owner = THIS_MODULE;
- add_mtd_device(tsunami_flash_mtd);
- return 0;
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/uclinux.c linux/drivers/mtd/maps/uclinux.c
---- linux-mips-2.4.27/drivers/mtd/maps/uclinux.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/maps/uclinux.c 2004-11-19 10:25:11.980187480 +0100
-@@ -5,7 +5,7 @@
- *
- * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
- *
-- * $Id$
-+ * $Id$
- */
-
- /****************************************************************************/
-@@ -24,58 +24,11 @@
-
- /****************************************************************************/
-
--__u8 uclinux_read8(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u8 *) (map->map_priv_1 + ofs)));
--}
--
--__u16 uclinux_read16(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u16 *) (map->map_priv_1 + ofs)));
--}
--
--__u32 uclinux_read32(struct map_info *map, unsigned long ofs)
--{
-- return(*((__u32 *) (map->map_priv_1 + ofs)));
--}
--
--void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
--{
-- memcpy(to, (void *)(map->map_priv_1 + from), len);
--}
--
--void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr)
--{
-- *((__u8 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr)
--{
-- *((__u16 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr)
--{
-- *((__u32 *) (map->map_priv_1 + adr)) = d;
--}
--
--void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
--{
-- memcpy((void *) (map->map_priv_1 + to), from, len);
--}
-
- /****************************************************************************/
-
- struct map_info uclinux_ram_map = {
-- name: "RAM",
-- read8: uclinux_read8,
-- read16: uclinux_read16,
-- read32: uclinux_read32,
-- copy_from: uclinux_copy_from,
-- write8: uclinux_write8,
-- write16: uclinux_write16,
-- write32: uclinux_write32,
-- copy_to: uclinux_copy_to,
-+ .name = "RAM",
- };
-
- struct mtd_info *uclinux_ram_mtdinfo;
-@@ -83,7 +36,7 @@
- /****************************************************************************/
-
- struct mtd_partition uclinux_romfs[] = {
-- { name: "ROMfs", offset: 0 }
-+ { .name = "ROMfs" }
- };
-
- #define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
-@@ -94,7 +47,7 @@
- size_t *retlen, u_char **mtdbuf)
- {
- struct map_info *map = (struct map_info *) mtd->priv;
-- *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from));
-+ *mtdbuf = (u_char *) (map->virt + ((int) from));
- *retlen = len;
- return(0);
- }
-@@ -108,29 +61,31 @@
- extern char _ebss;
-
- mapp = &uclinux_ram_map;
-- mapp->map_priv_2 = (unsigned long) &_ebss;
-+ mapp->phys = (unsigned long) &_ebss;
- mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
- mapp->buswidth = 4;
-
- printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
- (int) mapp->map_priv_2, (int) mapp->size);
-
-- mapp->map_priv_1 = (unsigned long)
-- ioremap_nocache(mapp->map_priv_2, mapp->size);
-+ mapp->virt = (unsigned long)
-+ ioremap_nocache(mapp->phys, mapp->size);
-
-- if (mapp->map_priv_1 == 0) {
-+ if (mapp->virt == 0) {
- printk("uclinux[mtd]: ioremap_nocache() failed\n");
- return(-EIO);
- }
-
-+ simple_map_init(mapp);
-+
- mtd = do_map_probe("map_ram", mapp);
- if (!mtd) {
- printk("uclinux[mtd]: failed to find a mapping?\n");
-- iounmap((void *) mapp->map_priv_1);
-+ iounmap((void *) mapp->virt);
- return(-ENXIO);
- }
-
-- mtd->module = THIS_MODULE;
-+ mtd->owner = THIS_MODULE;
- mtd->point = uclinux_point;
- mtd->priv = mapp;
-
-@@ -155,8 +110,8 @@
- uclinux_ram_mtdinfo = NULL;
- }
- if (uclinux_ram_map.map_priv_1) {
-- iounmap((void *) uclinux_ram_map.map_priv_1);
-- uclinux_ram_map.map_priv_1 = 0;
-+ iounmap((void *) uclinux_ram_map.virt);
-+ uclinux_ram_map.virt = 0;
- }
- }
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/vmax301.c linux/drivers/mtd/maps/vmax301.c
---- linux-mips-2.4.27/drivers/mtd/maps/vmax301.c 2001-11-05 21:15:52.000000000 +0100
-+++ linux/drivers/mtd/maps/vmax301.c 2004-11-19 10:25:11.982187176 +0100
-@@ -1,4 +1,4 @@
--// $Id$
-+// $Id$
- /* ######################################################################
-
- Tempustech VMAX SBC301 MTD Driver.
-@@ -24,6 +24,7 @@
- #include <asm/io.h>
-
- #include <linux/mtd/map.h>
-+#include <linux/mtd/mtd.h>
-
-
- #define WINDOW_START 0xd8000
-@@ -142,34 +143,36 @@
-
- static struct map_info vmax_map[2] = {
- {
-- name: "VMAX301 Internal Flash",
-- size: 3*2*1024*1024,
-- buswidth: 1,
-- read8: vmax301_read8,
-- read16: vmax301_read16,
-- read32: vmax301_read32,
-- copy_from: vmax301_copy_from,
-- write8: vmax301_write8,
-- write16: vmax301_write16,
-- write32: vmax301_write32,
-- copy_to: vmax301_copy_to,
-- map_priv_1: WINDOW_START + WINDOW_LENGTH,
-- map_priv_2: 0xFFFFFFFF
-+ .name = "VMAX301 Internal Flash",
-+ .phys = NO_XIP,
-+ .size = 3*2*1024*1024,
-+ .buswidth = 1,
-+ .read8 = vmax301_read8,
-+ .read16 = vmax301_read16,
-+ .read32 = vmax301_read32,
-+ .copy_from = vmax301_copy_from,
-+ .write8 = vmax301_write8,
-+ .write16 = vmax301_write16,
-+ .write32 = vmax301_write32,
-+ .copy_to = vmax301_copy_to,
-+ .map_priv_1 = WINDOW_START + WINDOW_LENGTH,
-+ .map_priv_2 = 0xFFFFFFFF
- },
- {
-- name: "VMAX301 Socket",
-- size: 0,
-- buswidth: 1,
-- read8: vmax301_read8,
-- read16: vmax301_read16,
-- read32: vmax301_read32,
-- copy_from: vmax301_copy_from,
-- write8: vmax301_write8,
-- write16: vmax301_write16,
-- write32: vmax301_write32,
-- copy_to: vmax301_copy_to,
-- map_priv_1: WINDOW_START + (3*WINDOW_LENGTH),
-- map_priv_2: 0xFFFFFFFF
-+ .name = "VMAX301 Socket",
-+ .phys = NO_XIP,
-+ .size = 0,
-+ .buswidth = 1,
-+ .read8 = vmax301_read8,
-+ .read16 = vmax301_read16,
-+ .read32 = vmax301_read32,
-+ .copy_from = vmax301_copy_from,
-+ .write8 = vmax301_write8,
-+ .write16 = vmax301_write16,
-+ .write32 = vmax301_write32,
-+ .copy_to = vmax301_copy_to,
-+ .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
-+ .map_priv_2 = 0xFFFFFFFF
- }
- };
-
-@@ -206,8 +209,8 @@
- address of the first half, because it's used more
- often.
- */
-- vmax_map[0].map_priv_1 = iomapadr + WINDOW_START;
-- vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START);
-+ vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
-+ vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
-
- for (i=0; i<2; i++) {
- vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
-@@ -218,7 +221,7 @@
- if (!vmax_mtd[i])
- vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
- if (vmax_mtd[i]) {
-- vmax_mtd[i]->module = THIS_MODULE;
-+ vmax_mtd[i]->owner = THIS_MODULE;
- add_mtd_device(vmax_mtd[i]);
- }
- }
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtd_blkdevs-24.c linux/drivers/mtd/mtd_blkdevs-24.c
---- linux-mips-2.4.27/drivers/mtd/mtd_blkdevs-24.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/mtd_blkdevs-24.c 2004-11-19 10:25:11.640239160 +0100
-@@ -0,0 +1,699 @@
-+/*
-+ * $Id$
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux 2.4 block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/blkdev.h>
-+#include <linux/blk.h>
-+#include <linux/blkpg.h>
-+#include <linux/spinlock.h>
-+#include <linux/hdreg.h>
-+#include <linux/init.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+static LIST_HEAD(blktrans_majors);
-+
-+extern struct semaphore mtd_table_mutex;
-+extern struct mtd_info *mtd_table[];
-+
-+struct mtd_blkcore_priv {
-+ devfs_handle_t devfs_dir_handle;
-+ int blksizes[256];
-+ int sizes[256];
-+ struct hd_struct part_table[256];
-+ struct gendisk gd;
-+ spinlock_t devs_lock; /* See comment in _request function */
-+ struct completion thread_dead;
-+ int exiting;
-+ wait_queue_head_t thread_wq;
-+};
-+
-+static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr,
-+ int devnum)
-+{
-+ struct list_head *this;
-+ struct mtd_blktrans_dev *d;
-+
-+ list_for_each(this, &tr->devs) {
-+ d = list_entry(this, struct mtd_blktrans_dev, list);
-+
-+ if (d->devnum == devnum)
-+ return d;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct mtd_blktrans_ops *get_tr(int major)
-+{
-+ struct list_head *this;
-+ struct mtd_blktrans_ops *t;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ t = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ if (t->major == major)
-+ return t;
-+ }
-+ return NULL;
-+}
-+
-+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev,
-+ struct request *req)
-+{
-+ unsigned long block, nsect;
-+ char *buf;
-+ int minor;
-+
-+ minor = MINOR(req->rq_dev);
-+ block = req->sector;
-+ nsect = req->current_nr_sectors;
-+ buf = req->buffer;
-+
-+ if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) {
-+ printk(KERN_WARNING "Access beyond end of device.\n");
-+ return 0;
-+ }
-+ block += tr->blkcore_priv->part_table[minor].start_sect;
-+
-+ switch(req->cmd) {
-+ case READ:
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->readsect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ case WRITE:
-+ if (!tr->writesect)
-+ return 0;
-+
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->writesect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ default:
-+ printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd);
-+ return 0;
-+ }
-+}
-+
-+static int mtd_blktrans_thread(void *arg)
-+{
-+ struct mtd_blktrans_ops *tr = arg;
-+ struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major);
-+
-+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
-+ current->flags |= PF_MEMALLOC;
-+
-+ snprintf(current->comm, sizeof(current->comm), "%sd", tr->name);
-+
-+ /* daemonize() doesn't do this for us since some kernel threads
-+ actually want to deal with signals. We can't just call
-+ exit_sighand() since that'll cause an oops when we finally
-+ do exit. */
-+
-+#ifndef __rh_config_h__ /* HAVE_NPTL */
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending(current);
-+ spin_unlock_irq(&current->sigmask_lock);
-+#else
-+ spin_lock_irq(&current->sighand->siglock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sighand->siglock);
-+#endif
-+ daemonize();
-+
-+ while (!tr->blkcore_priv->exiting) {
-+ struct request *req;
-+ struct mtd_blktrans_dev *dev;
-+ int devnum;
-+ int res = 0;
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ spin_lock_irq(&io_request_lock);
-+
-+ if (list_empty(&rq->queue_head)) {
-+
-+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ spin_unlock_irq(&io_request_lock);
-+
-+ schedule();
-+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+
-+ continue;
-+ }
-+
-+ req = blkdev_entry_next_request(&rq->queue_head);
-+
-+ devnum = MINOR(req->rq_dev) >> tr->part_bits;
-+
-+ /* The ll_rw_blk code knows not to touch the request
-+ at the head of the queue */
-+ spin_unlock_irq(&io_request_lock);
-+
-+ /* FIXME: Where can we store the dev, on which
-+ we already have a refcount anyway? We need to
-+ lock against concurrent addition/removal of devices,
-+ but if we use the mtd_table_mutex we deadlock when
-+ grok_partitions is called from the registration
-+ callbacks. */
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+ dev = tr_get_dev(tr, devnum);
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ BUG_ON(!dev);
-+
-+ /* Ensure serialisation of requests */
-+ down(&dev->sem);
-+
-+ res = do_blktrans_request(tr, dev, req);
-+ up(&dev->sem);
-+
-+ if (!end_that_request_first(req, res, tr->name)) {
-+ spin_lock_irq(&io_request_lock);
-+ blkdev_dequeue_request(req);
-+ end_that_request_last(req);
-+ spin_unlock_irq(&io_request_lock);
-+ }
-+ }
-+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
-+}
-+
-+static void mtd_blktrans_request(struct request_queue *rq)
-+{
-+ struct mtd_blktrans_ops *tr = rq->queuedata;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+}
-+
-+int blktrans_open(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_ops *tr = NULL;
-+ struct mtd_blktrans_dev *dev = NULL;
-+ int major_nr = MAJOR(i->i_rdev);
-+ int minor_nr = MINOR(i->i_rdev);
-+ int devnum;
-+ int ret = -ENODEV;
-+
-+ if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE))
-+ return -EROFS;
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(major_nr);
-+
-+ if (!tr)
-+ goto out;
-+
-+ devnum = minor_nr >> tr->part_bits;
-+
-+ dev = tr_get_dev(tr, devnum);
-+
-+ if (!dev)
-+ goto out;
-+
-+ if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) {
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ if (!try_inc_mod_count(dev->mtd->owner))
-+ goto out;
-+
-+ if (!try_inc_mod_count(tr->owner))
-+ goto out_tr;
-+
-+ dev->mtd->usecount++;
-+
-+ ret = 0;
-+ if (tr->open && (ret = tr->open(dev))) {
-+ dev->mtd->usecount--;
-+ if (dev->mtd->owner)
-+ __MOD_DEC_USE_COUNT(dev->mtd->owner);
-+ out_tr:
-+ if (tr->owner)
-+ __MOD_DEC_USE_COUNT(tr->owner);
-+ }
-+ out:
-+ up(&mtd_table_mutex);
-+
-+ return ret;
-+}
-+
-+int blktrans_release(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = 0;
-+ int devnum;
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(MAJOR(i->i_rdev));
-+ if (!tr) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ devnum = MINOR(i->i_rdev) >> tr->part_bits;
-+ dev = tr_get_dev(tr, devnum);
-+
-+ if (!dev) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ if (tr->release)
-+ ret = tr->release(dev);
-+
-+ if (!ret) {
-+ dev->mtd->usecount--;
-+ if (dev->mtd->owner)
-+ __MOD_DEC_USE_COUNT(dev->mtd->owner);
-+ if (tr->owner)
-+ __MOD_DEC_USE_COUNT(tr->owner);
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ return ret;
-+}
-+
-+static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev)
-+{
-+ struct gendisk *gd = &(tr->blkcore_priv->gd);
-+ int i;
-+ int minor = MINOR(rdev);
-+
-+ if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) {
-+ /* BLKRRPART on a partition. Go away. */
-+ return -ENOTTY;
-+ }
-+
-+ if (!capable(CAP_SYS_ADMIN))
-+ return -EACCES;
-+
-+ /* We are required to prevent simultaneous open() ourselves.
-+ The core doesn't do that for us. Did I ever mention how
-+ much the Linux block layer sucks? Sledgehammer approach... */
-+ down(&mtd_table_mutex);
-+
-+ for (i=0; i < (1<<tr->part_bits); i++) {
-+ invalidate_device(MKDEV(tr->major, minor+i), 1);
-+ gd->part[minor + i].start_sect = 0;
-+ gd->part[minor + i].nr_sects = 0;
-+ }
-+
-+ grok_partitions(gd, minor, 1 << tr->part_bits,
-+ tr->blkcore_priv->sizes[minor]);
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+static int blktrans_ioctl(struct inode *inode, struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int devnum;
-+
-+ switch(cmd) {
-+ case BLKGETSIZE:
-+ case BLKGETSIZE64:
-+ case BLKBSZSET:
-+ case BLKBSZGET:
-+ case BLKROSET:
-+ case BLKROGET:
-+ case BLKRASET:
-+ case BLKRAGET:
-+ case BLKPG:
-+ case BLKELVGET:
-+ case BLKELVSET:
-+ return blk_ioctl(inode->i_rdev, cmd, arg);
-+ }
-+
-+ down(&mtd_table_mutex);
-+
-+ tr = get_tr(MAJOR(inode->i_rdev));
-+ if (!tr) {
-+ up(&mtd_table_mutex);
-+ return -ENODEV;
-+ }
-+
-+ devnum = MINOR(inode->i_rdev) >> tr->part_bits;
-+ dev = tr_get_dev(tr, devnum);
-+
-+ up(&mtd_table_mutex);
-+
-+ if (!dev)
-+ return -ENODEV;
-+
-+ switch(cmd) {
-+ case BLKRRPART:
-+ return mtd_blktrans_rrpart(inode->i_rdev, tr, dev);
-+
-+ case BLKFLSBUF:
-+ blk_ioctl(inode->i_rdev, cmd, arg);
-+ if (tr->flush)
-+ return tr->flush(dev);
-+ /* The core code did the work, we had nothing to do. */
-+ return 0;
-+
-+ case HDIO_GETGEO:
-+ if (tr->getgeo) {
-+ struct hd_geometry g;
-+ struct gendisk *gd = &(tr->blkcore_priv->gd);
-+ int ret;
-+
-+ memset(&g, 0, sizeof(g));
-+ ret = tr->getgeo(dev, &g);
-+ if (ret)
-+ return ret;
-+
-+ g.start = gd->part[MINOR(inode->i_rdev)].start_sect;
-+ if (copy_to_user((void *)arg, &g, sizeof(g)))
-+ return -EFAULT;
-+ return 0;
-+ } /* else */
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
-+struct block_device_operations mtd_blktrans_ops = {
-+ .owner = THIS_MODULE,
-+ .open = blktrans_open,
-+ .release = blktrans_release,
-+ .ioctl = blktrans_ioctl,
-+};
-+
-+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
-+{
-+ struct mtd_blktrans_ops *tr = new->tr;
-+ struct list_head *this;
-+ int last_devnum = -1;
-+ int i;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+
-+ list_for_each(this, &tr->devs) {
-+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
-+ if (new->devnum == -1) {
-+ /* Use first free number */
-+ if (d->devnum != last_devnum+1) {
-+ /* Found a free devnum. Plug it in here */
-+ new->devnum = last_devnum+1;
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ } else if (d->devnum == new->devnum) {
-+ /* Required number taken */
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+ return -EBUSY;
-+ } else if (d->devnum > new->devnum) {
-+ /* Required number was free */
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ last_devnum = d->devnum;
-+ }
-+ if (new->devnum == -1)
-+ new->devnum = last_devnum+1;
-+
-+ if ((new->devnum << tr->part_bits) > 256) {
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+ return -EBUSY;
-+ }
-+
-+ init_MUTEX(&new->sem);
-+ list_add_tail(&new->list, &tr->devs);
-+ added:
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ if (!tr->writesect)
-+ new->readonly = 1;
-+
-+ for (i = new->devnum << tr->part_bits;
-+ i < (new->devnum+1) << tr->part_bits;
-+ i++) {
-+ set_device_ro(MKDEV(tr->major, i), new->readonly);
-+ tr->blkcore_priv->blksizes[i] = new->blksize;
-+ tr->blkcore_priv->sizes[i] = 0;
-+ tr->blkcore_priv->part_table[i].nr_sects = 0;
-+ tr->blkcore_priv->part_table[i].start_sect = 0;
-+ }
-+
-+ /*
-+ <viro_zzz> dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices
-+ <viro> dwmw2: any code which sets blk_size[][] should be
-+ size >> 10 /+ 2.4 and its dumb units */
-+
-+ tr->blkcore_priv->sizes[new->devnum << tr->part_bits] =
-+ (new->size * new->blksize) >> 10; /* 2.4 and its dumb units */
-+
-+ /* But this is still in device's sectors? $DEITY knows */
-+ tr->blkcore_priv->part_table[new->devnum << tr->part_bits].nr_sects = new->size;
-+
-+ if (tr->part_bits) {
-+ grok_partitions(&tr->blkcore_priv->gd, new->devnum,
-+ 1 << tr->part_bits, new->size);
-+ }
-+#ifdef CONFIG_DEVFS_FS
-+ if (!tr->part_bits) {
-+ char name[2];
-+
-+ name[0] = '0' + new->devnum;
-+ name[1] = 0;
-+
-+ new->blkcore_priv =
-+ devfs_register(tr->blkcore_priv->devfs_dir_handle,
-+ name, DEVFS_FL_DEFAULT, tr->major,
-+ new->devnum, S_IFBLK|S_IRUGO|S_IWUGO,
-+ &mtd_blktrans_ops, NULL);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
-+{
-+ struct mtd_blktrans_ops *tr = old->tr;
-+ int i;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+#ifdef CONFIG_DEVFS_FS
-+ if (!tr->part_bits) {
-+ devfs_unregister(old->blkcore_priv);
-+ old->blkcore_priv = NULL;
-+ } else {
-+ devfs_register_partitions(&tr->blkcore_priv->gd,
-+ old->devnum << tr->part_bits, 1);
-+ }
-+#endif
-+ spin_lock(&tr->blkcore_priv->devs_lock);
-+ list_del(&old->list);
-+ spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+ for (i = (old->devnum << tr->part_bits);
-+ i < ((old->devnum+1) << tr->part_bits); i++) {
-+ tr->blkcore_priv->sizes[i] = 0;
-+ tr->blkcore_priv->part_table[i].nr_sects = 0;
-+ tr->blkcore_priv->part_table[i].start_sect = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+void blktrans_notify_remove(struct mtd_info *mtd)
-+{
-+ struct list_head *this, *this2, *next;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ list_for_each_safe(this2, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
-+
-+ if (dev->mtd == mtd)
-+ tr->remove_dev(dev);
-+ }
-+ }
-+}
-+
-+void blktrans_notify_add(struct mtd_info *mtd)
-+{
-+ struct list_head *this;
-+
-+ if (mtd->type == MTD_ABSENT)
-+ return;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ tr->add_mtd(tr, mtd);
-+ }
-+
-+}
-+
-+static struct mtd_notifier blktrans_notifier = {
-+ .add = blktrans_notify_add,
-+ .remove = blktrans_notify_remove,
-+};
-+
-+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ int ret, i;
-+
-+ /* Register the notifier if/when the first device type is
-+ registered, to prevent the link/init ordering from fucking
-+ us over. */
-+ if (!blktrans_notifier.list.next)
-+ register_mtd_user(&blktrans_notifier);
-+
-+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
-+ if (!tr->blkcore_priv)
-+ return -ENOMEM;
-+
-+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-+
-+ down(&mtd_table_mutex);
-+
-+ ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops);
-+ if (ret) {
-+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
-+ tr->name, tr->major, ret);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request);
-+ (BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr;
-+
-+ init_completion(&tr->blkcore_priv->thread_dead);
-+ init_waitqueue_head(&tr->blkcore_priv->thread_wq);
-+
-+ ret = kernel_thread(mtd_blktrans_thread, tr,
-+ CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-+ if (ret < 0) {
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+ devfs_unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ tr->blkcore_priv->devfs_dir_handle =
-+ devfs_mk_dir(NULL, tr->name, NULL);
-+
-+ blksize_size[tr->major] = tr->blkcore_priv->blksizes;
-+ blk_size[tr->major] = tr->blkcore_priv->sizes;
-+
-+ tr->blkcore_priv->gd.major = tr->major;
-+ tr->blkcore_priv->gd.major_name = tr->name;
-+ tr->blkcore_priv->gd.minor_shift = tr->part_bits;
-+ tr->blkcore_priv->gd.max_p = (1<<tr->part_bits) - 1;
-+ tr->blkcore_priv->gd.part = tr->blkcore_priv->part_table;
-+ tr->blkcore_priv->gd.sizes = tr->blkcore_priv->sizes;
-+ tr->blkcore_priv->gd.nr_real = 256 >> tr->part_bits;
-+
-+ spin_lock_init(&tr->blkcore_priv->devs_lock);
-+
-+ add_gendisk(&tr->blkcore_priv->gd);
-+
-+ INIT_LIST_HEAD(&tr->devs);
-+ list_add(&tr->list, &blktrans_majors);
-+
-+ for (i=0; i<MAX_MTD_DEVICES; i++) {
-+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
-+ tr->add_mtd(tr, mtd_table[i]);
-+ }
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ struct list_head *this, *next;
-+
-+ down(&mtd_table_mutex);
-+
-+ /* Clean up the kernel thread */
-+ tr->blkcore_priv->exiting = 1;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+ wait_for_completion(&tr->blkcore_priv->thread_dead);
-+
-+ /* Remove it from the list of active majors */
-+ list_del(&tr->list);
-+
-+ /* Remove each of its devices */
-+ list_for_each_safe(this, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
-+ tr->remove_dev(dev);
-+ }
-+
-+ blksize_size[tr->major] = NULL;
-+ blk_size[tr->major] = NULL;
-+
-+ del_gendisk(&tr->blkcore_priv->gd);
-+
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+ devfs_unregister_blkdev(tr->major, tr->name);
-+
-+ devfs_unregister(tr->blkcore_priv->devfs_dir_handle);
-+
-+ up(&mtd_table_mutex);
-+
-+ kfree(tr->blkcore_priv);
-+
-+ if (!list_empty(&tr->devs))
-+ BUG();
-+ return 0;
-+}
-+
-+static void __exit mtd_blktrans_exit(void)
-+{
-+ /* No race here -- if someone's currently in register_mtd_blktrans
-+ we're screwed anyway. */
-+ if (blktrans_notifier.list.next)
-+ unregister_mtd_user(&blktrans_notifier);
-+}
-+
-+module_exit(mtd_blktrans_exit);
-+
-+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
-+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtd_blkdevs.c linux/drivers/mtd/mtd_blkdevs.c
---- linux-mips-2.4.27/drivers/mtd/mtd_blkdevs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/mtd_blkdevs.c 2004-11-19 10:25:11.642238856 +0100
-@@ -0,0 +1,479 @@
-+/*
-+ * $Id$
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux 2.5 block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/blkdev.h>
-+#include <linux/blk.h>
-+#include <linux/blkpg.h>
-+#include <linux/spinlock.h>
-+#include <linux/hdreg.h>
-+#include <linux/init.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+#include <linux/devfs_fs_kernel.h>
-+
-+static LIST_HEAD(blktrans_majors);
-+
-+extern struct semaphore mtd_table_mutex;
-+extern struct mtd_info *mtd_table[];
-+
-+struct mtd_blkcore_priv {
-+ struct completion thread_dead;
-+ int exiting;
-+ wait_queue_head_t thread_wq;
-+ struct request_queue *rq;
-+ spinlock_t queue_lock;
-+};
-+
-+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
-+ struct mtd_blktrans_dev *dev,
-+ struct request *req)
-+{
-+ unsigned long block, nsect;
-+ char *buf;
-+
-+ block = req->sector;
-+ nsect = req->current_nr_sectors;
-+ buf = req->buffer;
-+
-+ if (!(req->flags & REQ_CMD))
-+ return 0;
-+
-+ if (block + nsect > get_capacity(req->rq_disk))
-+ return 0;
-+
-+ switch(rq_data_dir(req)) {
-+ case READ:
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->readsect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ case WRITE:
-+ if (!tr->writesect)
-+ return 0;
-+
-+ for (; nsect > 0; nsect--, block++, buf += 512)
-+ if (tr->writesect(dev, block, buf))
-+ return 0;
-+ return 1;
-+
-+ default:
-+ printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req));
-+ return 0;
-+ }
-+}
-+
-+static int mtd_blktrans_thread(void *arg)
-+{
-+ struct mtd_blktrans_ops *tr = arg;
-+ struct request_queue *rq = tr->blkcore_priv->rq;
-+
-+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
-+ current->flags |= PF_MEMALLOC;
-+
-+ daemonize("%sd", tr->name);
-+
-+ /* daemonize() doesn't do this for us since some kernel threads
-+ actually want to deal with signals. We can't just call
-+ exit_sighand() since that'll cause an oops when we finally
-+ do exit. */
-+ spin_lock_irq(&current->sighand->siglock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sighand->siglock);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ while (!tr->blkcore_priv->exiting) {
-+ struct request *req;
-+ struct mtd_blktrans_dev *dev;
-+ int res = 0;
-+ DECLARE_WAITQUEUE(wait, current);
-+
-+ req = elv_next_request(rq);
-+
-+ if (!req) {
-+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ spin_unlock_irq(rq->queue_lock);
-+
-+ schedule();
-+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ continue;
-+ }
-+
-+ dev = req->rq_disk->private_data;
-+ tr = dev->tr;
-+
-+ spin_unlock_irq(rq->queue_lock);
-+
-+ down(&dev->sem);
-+ res = do_blktrans_request(tr, dev, req);
-+ up(&dev->sem);
-+
-+ spin_lock_irq(rq->queue_lock);
-+
-+ end_request(req, res);
-+ }
-+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
-+}
-+
-+static void mtd_blktrans_request(struct request_queue *rq)
-+{
-+ struct mtd_blktrans_ops *tr = rq->queuedata;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+}
-+
-+
-+int blktrans_open(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = -ENODEV;
-+
-+ dev = i->i_bdev->bd_disk->private_data;
-+ tr = dev->tr;
-+
-+ if (!try_module_get(dev->mtd->owner))
-+ goto out;
-+
-+ if (!try_module_get(tr->owner))
-+ goto out_tr;
-+
-+ /* FIXME: Locking. A hot pluggable device can go away
-+ (del_mtd_device can be called for it) without its module
-+ being unloaded. */
-+ dev->mtd->usecount++;
-+
-+ ret = 0;
-+ if (tr->open && (ret = tr->open(dev))) {
-+ dev->mtd->usecount--;
-+ module_put(dev->mtd->owner);
-+ out_tr:
-+ module_put(tr->owner);
-+ }
-+ out:
-+ return ret;
-+}
-+
-+int blktrans_release(struct inode *i, struct file *f)
-+{
-+ struct mtd_blktrans_dev *dev;
-+ struct mtd_blktrans_ops *tr;
-+ int ret = 0;
-+
-+ dev = i->i_bdev->bd_disk->private_data;
-+ tr = dev->tr;
-+
-+ if (tr->release)
-+ ret = tr->release(dev);
-+
-+ if (!ret) {
-+ dev->mtd->usecount--;
-+ module_put(dev->mtd->owner);
-+ module_put(tr->owner);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int blktrans_ioctl(struct inode *inode, struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
-+ struct mtd_blktrans_ops *tr = dev->tr;
-+
-+ switch (cmd) {
-+ case BLKFLSBUF:
-+ if (tr->flush)
-+ return tr->flush(dev);
-+ /* The core code did the work, we had nothing to do. */
-+ return 0;
-+
-+ case HDIO_GETGEO:
-+ if (tr->getgeo) {
-+ struct hd_geometry g;
-+ int ret;
-+
-+ memset(&g, 0, sizeof(g));
-+ ret = tr->getgeo(dev, &g);
-+
-+ if (ret)
-+ return ret;
-+
-+ g.start = get_start_sect(inode->i_bdev);
-+ if (copy_to_user((void *)arg, &g, sizeof(g)))
-+ return -EFAULT;
-+ return 0;
-+ } /* else */
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
-+struct block_device_operations mtd_blktrans_ops = {
-+ .owner = THIS_MODULE,
-+ .open = blktrans_open,
-+ .release = blktrans_release,
-+ .ioctl = blktrans_ioctl,
-+};
-+
-+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
-+{
-+ struct mtd_blktrans_ops *tr = new->tr;
-+ struct list_head *this;
-+ int last_devnum = -1;
-+ struct gendisk *gd;
-+
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ list_for_each(this, &tr->devs) {
-+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
-+ if (new->devnum == -1) {
-+ /* Use first free number */
-+ if (d->devnum != last_devnum+1) {
-+ /* Found a free devnum. Plug it in here */
-+ new->devnum = last_devnum+1;
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ } else if (d->devnum == new->devnum) {
-+ /* Required number taken */
-+ return -EBUSY;
-+ } else if (d->devnum > new->devnum) {
-+ /* Required number was free */
-+ list_add_tail(&new->list, &d->list);
-+ goto added;
-+ }
-+ last_devnum = d->devnum;
-+ }
-+ if (new->devnum == -1)
-+ new->devnum = last_devnum+1;
-+
-+ if ((new->devnum << tr->part_bits) > 256) {
-+ return -EBUSY;
-+ }
-+
-+ init_MUTEX(&new->sem);
-+ list_add_tail(&new->list, &tr->devs);
-+ added:
-+ if (!tr->writesect)
-+ new->readonly = 1;
-+
-+ gd = alloc_disk(1 << tr->part_bits);
-+ if (!gd) {
-+ list_del(&new->list);
-+ return -ENOMEM;
-+ }
-+ gd->major = tr->major;
-+ gd->first_minor = (new->devnum) << tr->part_bits;
-+ gd->fops = &mtd_blktrans_ops;
-+
-+ snprintf(gd->disk_name, sizeof(gd->disk_name),
-+ "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
-+ snprintf(gd->devfs_name, sizeof(gd->devfs_name),
-+ "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
-+
-+ /* 2.5 has capacity in units of 512 bytes while still
-+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
-+ set_capacity(gd, (new->size * new->blksize) >> 9);
-+
-+ gd->private_data = new;
-+ new->blkcore_priv = gd;
-+ gd->queue = tr->blkcore_priv->rq;
-+
-+ if (new->readonly)
-+ set_disk_ro(gd, 1);
-+
-+ add_disk(gd);
-+
-+ return 0;
-+}
-+
-+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
-+{
-+ if (!down_trylock(&mtd_table_mutex)) {
-+ up(&mtd_table_mutex);
-+ BUG();
-+ }
-+
-+ list_del(&old->list);
-+
-+ del_gendisk(old->blkcore_priv);
-+ put_disk(old->blkcore_priv);
-+
-+ return 0;
-+}
-+
-+void blktrans_notify_remove(struct mtd_info *mtd)
-+{
-+ struct list_head *this, *this2, *next;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ list_for_each_safe(this2, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
-+
-+ if (dev->mtd == mtd)
-+ tr->remove_dev(dev);
-+ }
-+ }
-+}
-+
-+void blktrans_notify_add(struct mtd_info *mtd)
-+{
-+ struct list_head *this;
-+
-+ if (mtd->type == MTD_ABSENT)
-+ return;
-+
-+ list_for_each(this, &blktrans_majors) {
-+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+ tr->add_mtd(tr, mtd);
-+ }
-+
-+}
-+
-+static struct mtd_notifier blktrans_notifier = {
-+ .add = blktrans_notify_add,
-+ .remove = blktrans_notify_remove,
-+};
-+
-+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ int ret, i;
-+
-+ /* Register the notifier if/when the first device type is
-+ registered, to prevent the link/init ordering from fucking
-+ us over. */
-+ if (!blktrans_notifier.list.next)
-+ register_mtd_user(&blktrans_notifier);
-+
-+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
-+ if (!tr->blkcore_priv)
-+ return -ENOMEM;
-+
-+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-+
-+ down(&mtd_table_mutex);
-+
-+ ret = register_blkdev(tr->major, tr->name);
-+ if (ret) {
-+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
-+ tr->name, tr->major, ret);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+ spin_lock_init(&tr->blkcore_priv->queue_lock);
-+ init_completion(&tr->blkcore_priv->thread_dead);
-+ init_waitqueue_head(&tr->blkcore_priv->thread_wq);
-+
-+ tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
-+ if (!tr->blkcore_priv->rq) {
-+ unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return -ENOMEM;
-+ }
-+
-+ tr->blkcore_priv->rq->queuedata = tr;
-+
-+ ret = kernel_thread(mtd_blktrans_thread, tr,
-+ CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-+ if (ret < 0) {
-+ blk_cleanup_queue(tr->blkcore_priv->rq);
-+ unregister_blkdev(tr->major, tr->name);
-+ kfree(tr->blkcore_priv);
-+ up(&mtd_table_mutex);
-+ return ret;
-+ }
-+
-+ devfs_mk_dir(tr->name);
-+
-+ INIT_LIST_HEAD(&tr->devs);
-+ list_add(&tr->list, &blktrans_majors);
-+
-+ for (i=0; i<MAX_MTD_DEVICES; i++) {
-+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
-+ tr->add_mtd(tr, mtd_table[i]);
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+ struct list_head *this, *next;
-+
-+ down(&mtd_table_mutex);
-+
-+ /* Clean up the kernel thread */
-+ tr->blkcore_priv->exiting = 1;
-+ wake_up(&tr->blkcore_priv->thread_wq);
-+ wait_for_completion(&tr->blkcore_priv->thread_dead);
-+
-+ /* Remove it from the list of active majors */
-+ list_del(&tr->list);
-+
-+ list_for_each_safe(this, next, &tr->devs) {
-+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
-+ tr->remove_dev(dev);
-+ }
-+
-+ devfs_remove(tr->name);
-+ blk_cleanup_queue(tr->blkcore_priv->rq);
-+ unregister_blkdev(tr->major, tr->name);
-+
-+ up(&mtd_table_mutex);
-+
-+ kfree(tr->blkcore_priv);
-+
-+ if (!list_empty(&tr->devs))
-+ BUG();
-+ return 0;
-+}
-+
-+static void __exit mtd_blktrans_exit(void)
-+{
-+ /* No race here -- if someone's currently in register_mtd_blktrans
-+ we're screwed anyway. */
-+ if (blktrans_notifier.list.next)
-+ unregister_mtd_user(&blktrans_notifier);
-+}
-+
-+module_exit(mtd_blktrans_exit);
-+
-+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
-+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c
---- linux-mips-2.4.27/drivers/mtd/mtdblock.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/mtdblock.c 2004-11-19 10:25:11.643238704 +0100
-@@ -1,52 +1,25 @@
- /*
- * Direct MTD block device access
- *
-- * $Id$
-+ * $Id$
- *
-- * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache
-+ * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
-+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
- */
-
- #include <linux/config.h>
- #include <linux/types.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
- #include <linux/slab.h>
-+#include <linux/vmalloc.h>
- #include <linux/mtd/mtd.h>
--#include <linux/mtd/compatmac.h>
--
--#define MAJOR_NR MTD_BLOCK_MAJOR
--#define DEVICE_NAME "mtdblock"
--#define DEVICE_REQUEST mtdblock_request
--#define DEVICE_NR(device) (device)
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--#define DEVICE_NO_RANDOM
--#include <linux/blk.h>
--/* for old kernels... */
--#ifndef QUEUE_EMPTY
--#define QUEUE_EMPTY (!CURRENT)
--#endif
--#if LINUX_VERSION_CODE < 0x20300
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
--#else
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
--#endif
--
--#ifdef CONFIG_DEVFS_FS
--#include <linux/devfs_fs_kernel.h>
--static void mtd_notify_add(struct mtd_info* mtd);
--static void mtd_notify_remove(struct mtd_info* mtd);
--static struct mtd_notifier notifier = {
-- mtd_notify_add,
-- mtd_notify_remove,
-- NULL
--};
--static devfs_handle_t devfs_dir_handle = NULL;
--static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
--#endif
-+#include <linux/mtd/blktrans.h>
-
- static struct mtdblk_dev {
-- struct mtd_info *mtd; /* Locked */
-+ struct mtd_info *mtd;
- int count;
- struct semaphore cache_sem;
- unsigned char *cache_data;
-@@ -55,19 +28,6 @@
- enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
- } *mtdblks[MAX_MTD_DEVICES];
-
--static spinlock_t mtdblks_lock;
--
--static int mtd_sizes[MAX_MTD_DEVICES];
--static int mtd_blksizes[MAX_MTD_DEVICES];
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
- /*
- * Cache stuff...
- *
-@@ -151,7 +111,7 @@
- return ret;
-
- /*
-- * Here we could argably set the cache state to STATE_CLEAN.
-+ * Here we could argubly set the cache state to STATE_CLEAN.
- * However this could lead to inconsistency since we will not
- * be notified if this content is altered on the flash by other
- * means. Let's declare it empty and leave buffering tasks to
-@@ -277,57 +237,47 @@
- return 0;
- }
-
-+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-+ return do_cached_read(mtdblk, block<<9, 512, buf);
-+}
-
-+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
-+{
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-+ if (unlikely(!mtdblk->cache_data)) {
-+ mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-+ if (!mtdblk->cache_data)
-+ return -EINTR;
-+ /* -EINTR is not really correct, but it is the best match
-+ * documented in man 2 write for all cases. We could also
-+ * return -EAGAIN sometimes, but why bother?
-+ */
-+ }
-+ return do_cached_write(mtdblk, block<<9, 512, buf);
-+}
-
--static int mtdblock_open(struct inode *inode, struct file *file)
-+static int mtdblock_open(struct mtd_blktrans_dev *mbd)
- {
- struct mtdblk_dev *mtdblk;
-- struct mtd_info *mtd;
-- int dev;
-+ struct mtd_info *mtd = mbd->mtd;
-+ int dev = mbd->devnum;
-
- DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
-
-- if (!inode)
-- return -EINVAL;
--
-- dev = MINOR(inode->i_rdev);
-- if (dev >= MAX_MTD_DEVICES)
-- return -EINVAL;
--
-- BLK_INC_USE_COUNT;
--
-- mtd = get_mtd_device(NULL, dev);
-- if (!mtd)
-- return -ENODEV;
-- if (MTD_ABSENT == mtd->type) {
-- put_mtd_device(mtd);
-- BLK_DEC_USE_COUNT;
-- return -ENODEV;
-- }
--
-- spin_lock(&mtdblks_lock);
--
-- /* If it's already open, no need to piss about. */
- if (mtdblks[dev]) {
- mtdblks[dev]->count++;
-- spin_unlock(&mtdblks_lock);
-- put_mtd_device(mtd);
- return 0;
- }
-
-- /* OK, it's not open. Try to find it */
--
-- /* First we have to drop the lock, because we have to
-- to things which might sleep.
-- */
-- spin_unlock(&mtdblks_lock);
--
-+ /* OK, it's not open. Create cache info for it */
- mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-- if (!mtdblk) {
-- put_mtd_device(mtd);
-- BLK_DEC_USE_COUNT;
-+ if (!mtdblk)
- return -ENOMEM;
-- }
-+
- memset(mtdblk, 0, sizeof(*mtdblk));
- mtdblk->count = 1;
- mtdblk->mtd = mtd;
-@@ -337,336 +287,102 @@
- if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
- mtdblk->mtd->erasesize) {
- mtdblk->cache_size = mtdblk->mtd->erasesize;
-- mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-- if (!mtdblk->cache_data) {
-- put_mtd_device(mtdblk->mtd);
-- kfree(mtdblk);
-- BLK_DEC_USE_COUNT;
-- return -ENOMEM;
-- }
-- }
--
-- /* OK, we've created a new one. Add it to the list. */
--
-- spin_lock(&mtdblks_lock);
--
-- if (mtdblks[dev]) {
-- /* Another CPU made one at the same time as us. */
-- mtdblks[dev]->count++;
-- spin_unlock(&mtdblks_lock);
-- put_mtd_device(mtdblk->mtd);
-- vfree(mtdblk->cache_data);
-- kfree(mtdblk);
-- return 0;
-+ mtdblk->cache_data = NULL;
- }
-
- mtdblks[dev] = mtdblk;
-- mtd_sizes[dev] = mtdblk->mtd->size/1024;
-- if (mtdblk->mtd->erasesize)
-- mtd_blksizes[dev] = mtdblk->mtd->erasesize;
-- if (mtd_blksizes[dev] > PAGE_SIZE)
-- mtd_blksizes[dev] = PAGE_SIZE;
-- set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
--
-- spin_unlock(&mtdblks_lock);
-
- DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
-
- return 0;
- }
-
--static release_t mtdblock_release(struct inode *inode, struct file *file)
-+static int mtdblock_release(struct mtd_blktrans_dev *mbd)
- {
-- int dev;
-- struct mtdblk_dev *mtdblk;
-- DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
-+ int dev = mbd->devnum;
-+ struct mtdblk_dev *mtdblk = mtdblks[dev];
-
-- if (inode == NULL)
-- release_return(-ENODEV);
--
-- dev = MINOR(inode->i_rdev);
-- mtdblk = mtdblks[dev];
-+ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
-
- down(&mtdblk->cache_sem);
- write_cached_data(mtdblk);
- up(&mtdblk->cache_sem);
-
-- spin_lock(&mtdblks_lock);
- if (!--mtdblk->count) {
- /* It was the last usage. Free the device */
- mtdblks[dev] = NULL;
-- spin_unlock(&mtdblks_lock);
- if (mtdblk->mtd->sync)
- mtdblk->mtd->sync(mtdblk->mtd);
-- put_mtd_device(mtdblk->mtd);
- vfree(mtdblk->cache_data);
- kfree(mtdblk);
-- } else {
-- spin_unlock(&mtdblks_lock);
- }
--
- DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
-
-- BLK_DEC_USE_COUNT;
-- release_return(0);
--}
--
--
--/*
-- * This is a special request_fn because it is executed in a process context
-- * to be able to sleep independently of the caller. The io_request_lock
-- * is held upon entry and exit.
-- * The head of our request queue is considered active so there is no need
-- * to dequeue requests before we are done.
-- */
--static void handle_mtdblock_request(void)
--{
-- struct request *req;
-- struct mtdblk_dev *mtdblk;
-- unsigned int res;
--
-- for (;;) {
-- INIT_REQUEST;
-- req = CURRENT;
-- spin_unlock_irq(&io_request_lock);
-- mtdblk = mtdblks[MINOR(req->rq_dev)];
-- res = 0;
--
-- if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
-- panic("%s: minor out of bounds", __FUNCTION__);
--
-- if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
-- goto end_req;
--
-- // Handle the request
-- switch (req->cmd)
-- {
-- int err;
--
-- case READ:
-- down(&mtdblk->cache_sem);
-- err = do_cached_read (mtdblk, req->sector << 9,
-- req->current_nr_sectors << 9,
-- req->buffer);
-- up(&mtdblk->cache_sem);
-- if (!err)
-- res = 1;
-- break;
--
-- case WRITE:
-- // Read only device
-- if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) )
-- break;
--
-- // Do the write
-- down(&mtdblk->cache_sem);
-- err = do_cached_write (mtdblk, req->sector << 9,
-- req->current_nr_sectors << 9,
-- req->buffer);
-- up(&mtdblk->cache_sem);
-- if (!err)
-- res = 1;
-- break;
-- }
--
--end_req:
-- spin_lock_irq(&io_request_lock);
-- end_request(res);
-- }
--}
--
--static volatile int leaving = 0;
--static DECLARE_MUTEX_LOCKED(thread_sem);
--static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
--
--int mtdblock_thread(void *dummy)
--{
-- struct task_struct *tsk = current;
-- DECLARE_WAITQUEUE(wait, tsk);
--
-- /* we might get involved when memory gets low, so use PF_MEMALLOC */
-- tsk->flags |= PF_MEMALLOC;
-- strcpy(tsk->comm, "mtdblockd");
-- spin_lock_irq(&tsk->sigmask_lock);
-- sigfillset(&tsk->blocked);
-- recalc_sigpending(tsk);
-- spin_unlock_irq(&tsk->sigmask_lock);
-- daemonize();
--
-- while (!leaving) {
-- add_wait_queue(&thr_wq, &wait);
-- set_current_state(TASK_INTERRUPTIBLE);
-- spin_lock_irq(&io_request_lock);
-- if (QUEUE_EMPTY || QUEUE_PLUGGED) {
-- spin_unlock_irq(&io_request_lock);
-- schedule();
-- remove_wait_queue(&thr_wq, &wait);
-- } else {
-- remove_wait_queue(&thr_wq, &wait);
-- set_current_state(TASK_RUNNING);
-- handle_mtdblock_request();
-- spin_unlock_irq(&io_request_lock);
-- }
-- }
--
-- up(&thread_sem);
- return 0;
- }
-
--#if LINUX_VERSION_CODE < 0x20300
--#define RQFUNC_ARG void
--#else
--#define RQFUNC_ARG request_queue_t *q
--#endif
--
--static void mtdblock_request(RQFUNC_ARG)
-+static int mtdblock_flush(struct mtd_blktrans_dev *dev)
- {
-- /* Don't do anything, except wake the thread if necessary */
-- wake_up(&thr_wq);
--}
-+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-
--
--static int mtdblock_ioctl(struct inode * inode, struct file * file,
-- unsigned int cmd, unsigned long arg)
--{
-- struct mtdblk_dev *mtdblk;
--
-- mtdblk = mtdblks[MINOR(inode->i_rdev)];
--
--#ifdef PARANOIA
-- if (!mtdblk)
-- BUG();
--#endif
--
-- switch (cmd) {
-- case BLKGETSIZE: /* Return device size */
-- return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
--#endif
--
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if(!capable(CAP_SYS_ADMIN))
-- return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
- down(&mtdblk->cache_sem);
- write_cached_data(mtdblk);
- up(&mtdblk->cache_sem);
-+
- if (mtdblk->mtd->sync)
- mtdblk->mtd->sync(mtdblk->mtd);
- return 0;
--
-- default:
-- return -EINVAL;
-- }
- }
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations mtd_fops =
-+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- open: mtdblock_open,
-- ioctl: mtdblock_ioctl,
-- release: mtdblock_release,
-- read: block_read,
-- write: block_write
--};
--#else
--static struct block_device_operations mtd_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: mtdblock_open,
-- release: mtdblock_release,
-- ioctl: mtdblock_ioctl
--};
--#endif
-+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-
--#ifdef CONFIG_DEVFS_FS
--/* Notification that a new device has been added. Create the devfs entry for
-- * it. */
--
--static void mtd_notify_add(struct mtd_info* mtd)
--{
-- char name[8];
--
-- if (!mtd || mtd->type == MTD_ABSENT)
-+ if (!dev)
- return;
-
-- sprintf(name, "%d", mtd->index);
-- devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
-- DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index,
-- S_IFBLK | S_IRUGO | S_IWUGO,
-- &mtd_fops, NULL);
--}
--
--static void mtd_notify_remove(struct mtd_info* mtd)
--{
-- if (!mtd || mtd->type == MTD_ABSENT)
-- return;
-+ memset(dev, 0, sizeof(*dev));
-
-- devfs_unregister(devfs_rw_handle[mtd->index]);
--}
--#endif
-+ dev->mtd = mtd;
-+ dev->devnum = mtd->index;
-+ dev->blksize = 512;
-+ dev->size = mtd->size >> 9;
-+ dev->tr = tr;
-+
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ dev->readonly = 1;
-+
-+ add_mtd_blktrans_dev(dev);
-+}
-+
-+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
-+{
-+ del_mtd_blktrans_dev(dev);
-+ kfree(dev);
-+}
-+
-+struct mtd_blktrans_ops mtdblock_tr = {
-+ .name = "mtdblock",
-+ .major = 31,
-+ .part_bits = 0,
-+ .open = mtdblock_open,
-+ .flush = mtdblock_flush,
-+ .release = mtdblock_release,
-+ .readsect = mtdblock_readsect,
-+ .writesect = mtdblock_writesect,
-+ .add_mtd = mtdblock_add_mtd,
-+ .remove_dev = mtdblock_remove_dev,
-+ .owner = THIS_MODULE,
-+};
-
- int __init init_mtdblock(void)
- {
-- int i;
--
-- spin_lock_init(&mtdblks_lock);
--#ifdef CONFIG_DEVFS_FS
-- if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
-- {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--
-- devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
-- register_mtd_user(&notifier);
--#else
-- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--#endif
--
-- /* We fill it in at open() time. */
-- for (i=0; i< MAX_MTD_DEVICES; i++) {
-- mtd_sizes[i] = 0;
-- mtd_blksizes[i] = BLOCK_SIZE;
-- }
-- init_waitqueue_head(&thr_wq);
-- /* Allow the block size to default to BLOCK_SIZE. */
-- blksize_size[MAJOR_NR] = mtd_blksizes;
-- blk_size[MAJOR_NR] = mtd_sizes;
--
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
-- kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-- return 0;
-+ return register_mtd_blktrans(&mtdblock_tr);
- }
-
- static void __exit cleanup_mtdblock(void)
- {
-- leaving = 1;
-- wake_up(&thr_wq);
-- down(&thread_sem);
--#ifdef CONFIG_DEVFS_FS
-- unregister_mtd_user(&notifier);
-- devfs_unregister(devfs_dir_handle);
-- devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
--#else
-- unregister_blkdev(MAJOR_NR,DEVICE_NAME);
--#endif
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-- blksize_size[MAJOR_NR] = NULL;
-- blk_size[MAJOR_NR] = NULL;
-+ deregister_mtd_blktrans(&mtdblock_tr);
- }
-
- module_init(init_mtdblock);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdblock_ro.c linux/drivers/mtd/mtdblock_ro.c
---- linux-mips-2.4.27/drivers/mtd/mtdblock_ro.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/mtdblock_ro.c 2004-11-19 10:25:11.645238400 +0100
-@@ -1,301 +1,87 @@
- /*
-- * $Id$
-+ * $Id$
- *
-- * Read-only version of the mtdblock device, without the
-- * read/erase/modify/writeback stuff
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Simple read-only (writable only for RAM) mtdblock driver
- */
-
--#ifdef MTDBLOCK_DEBUG
--#define DEBUGLVL debug
--#endif
--
--
--#include <linux/module.h>
--#include <linux/types.h>
--
-+#include <linux/init.h>
-+#include <linux/slab.h>
- #include <linux/mtd/mtd.h>
--#include <linux/mtd/compatmac.h>
--
--#define MAJOR_NR MTD_BLOCK_MAJOR
--#define DEVICE_NAME "mtdblock"
--#define DEVICE_REQUEST mtdblock_request
--#define DEVICE_NR(device) (device)
--#define DEVICE_ON(device)
--#define DEVICE_OFF(device)
--#define DEVICE_NO_RANDOM
--#include <linux/blk.h>
--
--#if LINUX_VERSION_CODE < 0x20300
--#define RQFUNC_ARG void
--#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
--#else
--#define RQFUNC_ARG request_queue_t *q
--#endif
--
--#ifdef MTDBLOCK_DEBUG
--static int debug = MTDBLOCK_DEBUG;
--MODULE_PARM(debug, "i");
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
--static int mtd_sizes[MAX_MTD_DEVICES];
-+#include <linux/mtd/blktrans.h>
-
--
--static int mtdblock_open(struct inode *inode, struct file *file)
-+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- struct mtd_info *mtd = NULL;
--
-- int dev;
--
-- DEBUG(1,"mtdblock_open\n");
--
-- if (inode == 0)
-- return -EINVAL;
--
-- dev = MINOR(inode->i_rdev);
--
-- mtd = get_mtd_device(NULL, dev);
-- if (!mtd)
-- return -EINVAL;
-- if (MTD_ABSENT == mtd->type) {
-- put_mtd_device(mtd);
-- return -EINVAL;
-- }
--
-- BLK_INC_USE_COUNT;
--
-- mtd_sizes[dev] = mtd->size>>9;
--
-- DEBUG(1, "ok\n");
-+ size_t retlen;
-
-+ if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf))
-+ return 1;
- return 0;
- }
-
--static release_t mtdblock_release(struct inode *inode, struct file *file)
-+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buf)
- {
-- int dev;
-- struct mtd_info *mtd;
--
-- DEBUG(1, "mtdblock_release\n");
--
-- if (inode == NULL)
-- release_return(-ENODEV);
--
-- dev = MINOR(inode->i_rdev);
-- mtd = __get_mtd_device(NULL, dev);
--
-- if (!mtd) {
-- printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
-- BLK_DEC_USE_COUNT;
-- release_return(-ENODEV);
-- }
--
-- if (mtd->sync)
-- mtd->sync(mtd);
--
-- put_mtd_device(mtd);
--
-- DEBUG(1, "ok\n");
-+ size_t retlen;
-
-- BLK_DEC_USE_COUNT;
-- release_return(0);
-+ if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf))
-+ return 1;
-+ return 0;
- }
-
--
--static void mtdblock_request(RQFUNC_ARG)
-+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- struct request *current_request;
-- unsigned int res = 0;
-- struct mtd_info *mtd;
--
-- while (1)
-- {
-- /* Grab the Request and unlink it from the request list, INIT_REQUEST
-- will execute a return if we are done. */
-- INIT_REQUEST;
-- current_request = CURRENT;
--
-- if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
-- {
-- printk("mtd: Unsupported device!\n");
-- end_request(0);
-- continue;
-- }
--
-- // Grab our MTD structure
--
-- mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
-- if (!mtd) {
-- printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
-- end_request(0);
-- }
--
-- if (current_request->sector << 9 > mtd->size ||
-- (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size)
-- {
-- printk("mtd: Attempt to read past end of device!\n");
-- printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size,
-- current_request->sector, current_request->current_nr_sectors);
-- end_request(0);
-- continue;
-- }
--
-- /* Remove the request we are handling from the request list so nobody messes
-- with it */
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- /* Now drop the lock that the ll_rw_blk functions grabbed for us
-- and process the request. This is necessary due to the extreme time
-- we spend processing it. */
-- spin_unlock_irq(&io_request_lock);
--#endif
--
-- // Handle the request
-- switch (current_request->cmd)
-- {
-- size_t retlen;
-+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-
-- case READ:
-- if (MTD_READ(mtd,current_request->sector<<9,
-- current_request->current_nr_sectors << 9,
-- &retlen, current_request->buffer) == 0)
-- res = 1;
-- else
-- res = 0;
-- break;
-+ if (!dev)
-+ return;
-
-- case WRITE:
-+ memset(dev, 0, sizeof(*dev));
-
-- /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
-- current_request->current_nr_sectors);
-- */
-+ dev->mtd = mtd;
-+ dev->devnum = mtd->index;
-+ dev->blksize = 512;
-+ dev->size = mtd->size >> 9;
-+ dev->tr = tr;
-+ if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) !=
-+ (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE))
-+ dev->readonly = 1;
-
-- // Read only device
-- if ((mtd->flags & MTD_CAP_RAM) == 0)
-- {
-- res = 0;
-- break;
-- }
--
-- // Do the write
-- if (MTD_WRITE(mtd,current_request->sector<<9,
-- current_request->current_nr_sectors << 9,
-- &retlen, current_request->buffer) == 0)
-- res = 1;
-- else
-- res = 0;
-- break;
--
-- // Shouldn't happen
-- default:
-- printk("mtd: unknown request\n");
-- break;
-- }
--
-- // Grab the lock and re-thread the item onto the linked list
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- spin_lock_irq(&io_request_lock);
--#endif
-- end_request(res);
-- }
-+ add_mtd_blktrans_dev(dev);
- }
-
--
--
--static int mtdblock_ioctl(struct inode * inode, struct file * file,
-- unsigned int cmd, unsigned long arg)
-+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- struct mtd_info *mtd;
--
-- mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
--
-- if (!mtd) return -EINVAL;
--
-- switch (cmd) {
-- case BLKGETSIZE: /* Return device size */
-- return put_user((mtd->size >> 9), (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)mtd->size, (u64 *)arg);
--#endif
--
-- case BLKFLSBUF:
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-- if(!capable(CAP_SYS_ADMIN)) return -EACCES;
--#endif
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- if (mtd->sync)
-- mtd->sync(mtd);
-- return 0;
--
-- default:
-- return -ENOTTY;
-- }
-+ del_mtd_blktrans_dev(dev);
-+ kfree(dev);
- }
-
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations mtd_fops =
--{
-- open: mtdblock_open,
-- ioctl: mtdblock_ioctl,
-- release: mtdblock_release,
-- read: block_read,
-- write: block_write
--};
--#else
--static struct block_device_operations mtd_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: mtdblock_open,
-- release: mtdblock_release,
-- ioctl: mtdblock_ioctl
-+struct mtd_blktrans_ops mtdblock_tr = {
-+ .name = "mtdblock",
-+ .major = 31,
-+ .part_bits = 0,
-+ .readsect = mtdblock_readsect,
-+ .writesect = mtdblock_writesect,
-+ .add_mtd = mtdblock_add_mtd,
-+ .remove_dev = mtdblock_remove_dev,
-+ .owner = THIS_MODULE,
- };
--#endif
-
--int __init init_mtdblock(void)
-+static int __init mtdblock_init(void)
- {
-- int i;
--
-- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_BLOCK_MAJOR);
-- return -EAGAIN;
-- }
--
-- /* We fill it in at open() time. */
-- for (i=0; i< MAX_MTD_DEVICES; i++) {
-- mtd_sizes[i] = 0;
-- }
--
-- /* Allow the block size to default to BLOCK_SIZE. */
-- blksize_size[MAJOR_NR] = NULL;
-- blk_size[MAJOR_NR] = mtd_sizes;
--
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
-- return 0;
-+ return register_mtd_blktrans(&mtdblock_tr);
- }
-
--static void __exit cleanup_mtdblock(void)
-+static void __exit mtdblock_exit(void)
- {
-- unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-- blk_size[MAJOR_NR] = NULL;
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-+ deregister_mtd_blktrans(&mtdblock_tr);
- }
-
--module_init(init_mtdblock);
--module_exit(cleanup_mtdblock);
--
-+module_init(mtdblock_init);
-+module_exit(mtdblock_exit);
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
- MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdchar.c linux/drivers/mtd/mtdchar.c
---- linux-mips-2.4.27/drivers/mtd/mtdchar.c 2004-08-14 20:38:51.000000000 +0200
-+++ linux/drivers/mtd/mtdchar.c 2004-11-19 10:25:11.647238096 +0100
-@@ -1,8 +1,7 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Character-device access to raw MTD devices.
-- * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
- *
- */
-
-@@ -10,7 +9,11 @@
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-
- #ifdef CONFIG_DEVFS_FS
- #include <linux/devfs_fs_kernel.h>
-@@ -18,8 +21,8 @@
- static void mtd_notify_remove(struct mtd_info* mtd);
-
- static struct mtd_notifier notifier = {
-- add: mtd_notify_add,
-- remove: mtd_notify_remove,
-+ .add = mtd_notify_add,
-+ .remove = mtd_notify_remove,
- };
-
- static devfs_handle_t devfs_dir_handle;
-@@ -60,7 +63,7 @@
-
- static int mtd_open(struct inode *inode, struct file *file)
- {
-- int minor = minor(inode->i_rdev);
-+ int minor = iminor(inode);
- int devnum = minor >> 1;
- struct mtd_info *mtd;
-
-@@ -125,15 +128,11 @@
- int ret=0;
- int len;
- char *kbuf;
-- loff_t pos = *ppos;
-
- DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
-
-- if (pos < 0 || pos > mtd->size)
-- return 0;
--
-- if (count > mtd->size - pos)
-- count = mtd->size - pos;
-+ if (*ppos + count > mtd->size)
-+ count = mtd->size - *ppos;
-
- if (!count)
- return 0;
-@@ -150,9 +149,9 @@
- if (!kbuf)
- return -ENOMEM;
-
-- ret = MTD_READ(mtd, pos, len, &retlen, kbuf);
-+ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
- if (!ret) {
-- pos += retlen;
-+ *ppos += retlen;
- if (copy_to_user(buf, kbuf, retlen)) {
- kfree(kbuf);
- return -EFAULT;
-@@ -171,8 +170,6 @@
- kfree(kbuf);
- }
-
-- *ppos = pos;
--
- return total_retlen;
- } /* mtd_read */
-
-@@ -182,17 +179,16 @@
- char *kbuf;
- size_t retlen;
- size_t total_retlen=0;
-- loff_t pos = *ppos;
- int ret=0;
- int len;
-
- DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
-
-- if (pos < 0 || pos >= mtd->size)
-+ if (*ppos == mtd->size)
- return -ENOSPC;
-
-- if (count > mtd->size - pos)
-- count = mtd->size - pos;
-+ if (*ppos + count > mtd->size)
-+ count = mtd->size - *ppos;
-
- if (!count)
- return 0;
-@@ -214,9 +210,9 @@
- return -EFAULT;
- }
-
-- ret = (*(mtd->write))(mtd, pos, len, &retlen, kbuf);
-+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
- if (!ret) {
-- pos += retlen;
-+ *ppos += retlen;
- total_retlen += retlen;
- count -= retlen;
- buf += retlen;
-@@ -228,7 +224,6 @@
-
- kfree(kbuf);
- }
-- *ppos = pos;
-
- return total_retlen;
- } /* mtd_write */
-@@ -450,81 +445,13 @@
- break;
- }
-
-- case MEMWRITEDATA:
-- {
-- struct mtd_oob_buf buf;
-- void *databuf;
-- ssize_t retlen;
--
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-- return -EFAULT;
--
-- if (buf.length > 0x4096)
-- return -EINVAL;
--
-- if (!mtd->write_ecc)
-- ret = -EOPNOTSUPP;
-- else
-- ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
--
-- if (ret)
-- return ret;
--
-- databuf = kmalloc(buf.length, GFP_KERNEL);
-- if (!databuf)
-- return -ENOMEM;
--
-- if (copy_from_user(databuf, buf.ptr, buf.length)) {
-- kfree(databuf);
-- return -EFAULT;
-- }
--
-- ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
--
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-- ret = -EFAULT;
--
-- kfree(databuf);
-- break;
--
-- }
--
-- case MEMREADDATA:
-+ case MEMSETOOBSEL:
- {
-- struct mtd_oob_buf buf;
-- void *databuf;
-- ssize_t retlen = 0;
--
-- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+ if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo)))
- return -EFAULT;
--
-- if (buf.length > 0x4096)
-- return -EINVAL;
--
-- if (!mtd->read_ecc)
-- ret = -EOPNOTSUPP;
-- else
-- ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
--
-- if (ret)
-- return ret;
--
-- databuf = kmalloc(buf.length, GFP_KERNEL);
-- if (!databuf)
-- return -ENOMEM;
--
-- ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
--
-- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
-- ret = -EFAULT;
-- else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
-- ret = -EFAULT;
--
-- kfree(databuf);
- break;
- }
-
--
- default:
- DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
- ret = -ENOTTY;
-@@ -534,13 +461,13 @@
- } /* memory_ioctl */
-
- static struct file_operations mtd_fops = {
-- owner: THIS_MODULE,
-- llseek: mtd_lseek, /* lseek */
-- read: mtd_read, /* read */
-- write: mtd_write, /* write */
-- ioctl: mtd_ioctl, /* ioctl */
-- open: mtd_open, /* open */
-- release: mtd_close, /* release */
-+ .owner = THIS_MODULE,
-+ .llseek = mtd_lseek,
-+ .read = mtd_read,
-+ .write = mtd_write,
-+ .ioctl = mtd_ioctl,
-+ .open = mtd_open,
-+ .release = mtd_close,
- };
-
-
-@@ -580,26 +507,18 @@
-
- static int __init init_mtdchar(void)
- {
--#ifdef CONFIG_DEVFS_FS
-- if (devfs_register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
-+ if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
- {
- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
- MTD_CHAR_MAJOR);
- return -EAGAIN;
- }
-
-+#ifdef CONFIG_DEVFS_FS
- devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL);
-
- register_mtd_user(&notifier);
--#else
-- if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops))
-- {
-- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-- MTD_CHAR_MAJOR);
-- return -EAGAIN;
-- }
- #endif
--
- return 0;
- }
-
-@@ -608,10 +527,8 @@
- #ifdef CONFIG_DEVFS_FS
- unregister_mtd_user(&notifier);
- devfs_unregister(devfs_dir_handle);
-- devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
--#else
-- unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
- #endif
-+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
- }
-
- module_init(init_mtdchar);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdconcat.c linux/drivers/mtd/mtdconcat.c
---- linux-mips-2.4.27/drivers/mtd/mtdconcat.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/mtdconcat.c 2004-11-19 10:25:11.649237792 +0100
-@@ -3,9 +3,11 @@
- *
- * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
- *
-+ * NAND support by Christian Gan <cgan@iders.ca>
-+ *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
-@@ -35,21 +37,20 @@
- #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
- ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
-
--
- /*
- * Given a pointer to the MTD object in the mtd_concat structure,
- * we can retrieve the pointer to that structure with this macro.
- */
- #define CONCAT(x) ((struct mtd_concat *)(x))
-
--
- /*
- * MTD methods which look up the relevant subdevice, translate the
- * effective address and pass through to the subdevice.
- */
-
--static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf)
-+static int
-+concat_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -57,43 +58,43 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (from >= subdev->size)
-- {
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
- size = 0;
- from -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (from + len > subdev->size)
-+ /* First part goes into this subdev */
- size = subdev->size - from;
- else
-+ /* Entire transaction goes into this subdev */
- size = len;
-
- err = subdev->read(subdev, from, size, &retsize, buf);
-
-- if(err)
-+ if (err)
- break;
-
- *retlen += retsize;
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- buf += size;
- from = 0;
- }
-- }
- return err;
- }
-
--static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf)
-+static int
-+concat_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -104,18 +105,15 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (to >= subdev->size)
-- {
-+ if (to >= subdev->size) {
- size = 0;
- to -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (to + len > subdev->size)
- size = subdev->size - to;
- else
-@@ -126,25 +124,232 @@
- else
- err = subdev->write(subdev, to, size, &retsize, buf);
-
-- if(err)
-+ if (err)
- break;
-
- *retlen += retsize;
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- buf += size;
- to = 0;
- }
-+ return err;
-+}
-+
-+static int
-+concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf, u_char * eccbuf,
-+ struct nand_oobinfo *oobsel)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
-+ from -= subdev->size;
-+ continue;
-+ }
-+
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
-+ else
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-+
-+ if (subdev->read_ecc)
-+ err = subdev->read_ecc(subdev, from, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf) {
-+ eccbuf += subdev->oobsize;
-+ /* in nand.c at least, eccbufs are
-+ tagged with 2 (int)eccstatus'; we
-+ must account for these */
-+ eccbuf += 2 * (sizeof (int));
-+ }
-+ from = 0;
- }
- return err;
- }
-
--static void concat_erase_callback (struct erase_info *instr)
-+static int
-+concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf, u_char * eccbuf,
-+ struct nand_oobinfo *oobsel)
- {
-- wake_up((wait_queue_head_t *)instr->priv);
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ return -EROFS;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
-+ to -= subdev->size;
-+ continue;
-+ }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
-+ else
-+ size = len;
-+
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_ecc)
-+ err = subdev->write_ecc(subdev, to, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf)
-+ eccbuf += subdev->oobsize;
-+ to = 0;
-+ }
-+ return err;
-+}
-+
-+static int
-+concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
-+ from -= subdev->size;
-+ continue;
-+ }
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
-+ else
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-+
-+ if (subdev->read_oob)
-+ err = subdev->read_oob(subdev, from, size,
-+ &retsize, buf);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ from = 0;
-+ }
-+ return err;
-+}
-+
-+static int
-+concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
-+{
-+ struct mtd_concat *concat = CONCAT(mtd);
-+ int err = -EINVAL;
-+ int i;
-+
-+ if (!(mtd->flags & MTD_WRITEABLE))
-+ return -EROFS;
-+
-+ *retlen = 0;
-+
-+ for (i = 0; i < concat->num_subdev; i++) {
-+ struct mtd_info *subdev = concat->subdev[i];
-+ size_t size, retsize;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
-+ to -= subdev->size;
-+ continue;
-+ }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
-+ else
-+ size = len;
-+
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_oob)
-+ err = subdev->write_oob(subdev, to, size, &retsize,
-+ buf);
-+ else
-+ err = -EINVAL;
-+
-+ if (err)
-+ break;
-+
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ to = 0;
-+ }
-+ return err;
-+}
-+
-+static void concat_erase_callback(struct erase_info *instr)
-+{
-+ wake_up((wait_queue_head_t *) instr->priv);
- }
-
- static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
-@@ -160,18 +365,18 @@
-
- erase->mtd = mtd;
- erase->callback = concat_erase_callback;
-- erase->priv = (unsigned long)&waitq;
-+ erase->priv = (unsigned long) &waitq;
-
- /*
- * FIXME: Allow INTERRUPTIBLE. Which means
- * not having the wait_queue head on the stack.
- */
- err = mtd->erase(mtd, erase);
-- if (!err)
-- {
-+ if (!err) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&waitq, &wait);
-- if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
-+ if (erase->state != MTD_ERASE_DONE
-+ && erase->state != MTD_ERASE_FAILED)
- schedule();
- remove_wait_queue(&waitq, &wait);
- set_current_state(TASK_RUNNING);
-@@ -181,7 +386,7 @@
- return err;
- }
-
--static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
-+static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- struct mtd_info *subdev;
-@@ -192,10 +397,10 @@
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-
-- if(instr->addr > concat->mtd.size)
-+ if (instr->addr > concat->mtd.size)
- return -EINVAL;
-
-- if(instr->len + instr->addr > concat->mtd.size)
-+ if (instr->len + instr->addr > concat->mtd.size)
- return -EINVAL;
-
- /*
-@@ -204,23 +409,22 @@
- * region info rather than looking at each particular sub-device
- * in turn.
- */
-- if (!concat->mtd.numeraseregions)
-- { /* the easy case: device has uniform erase block size */
-- if(instr->addr & (concat->mtd.erasesize - 1))
-+ if (!concat->mtd.numeraseregions) {
-+ /* the easy case: device has uniform erase block size */
-+ if (instr->addr & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- if(instr->len & (concat->mtd.erasesize - 1))
-+ if (instr->len & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- }
-- else
-- { /* device has variable erase size */
-- struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
-+ } else {
-+ /* device has variable erase size */
-+ struct mtd_erase_region_info *erase_regions =
-+ concat->mtd.eraseregions;
-
- /*
- * Find the erase region where the to-be-erased area begins:
- */
-- for(i = 0; i < concat->mtd.numeraseregions &&
-- instr->addr >= erase_regions[i].offset; i++)
-- ;
-+ for (i = 0; i < concat->mtd.numeraseregions &&
-+ instr->addr >= erase_regions[i].offset; i++) ;
- --i;
-
- /*
-@@ -228,25 +432,26 @@
- * to-be-erased area begins. Verify that the starting
- * offset is aligned to this region's erase size:
- */
-- if (instr->addr & (erase_regions[i].erasesize-1))
-+ if (instr->addr & (erase_regions[i].erasesize - 1))
- return -EINVAL;
-
- /*
- * now find the erase region where the to-be-erased area ends:
- */
-- for(; i < concat->mtd.numeraseregions &&
-- (instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
-- ;
-+ for (; i < concat->mtd.numeraseregions &&
-+ (instr->addr + instr->len) >= erase_regions[i].offset;
-+ ++i) ;
- --i;
- /*
- * check if the ending offset is aligned to this region's erase size
- */
-- if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
-+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
-+ 1))
- return -EINVAL;
- }
-
- /* make a local copy of instr to avoid modifying the caller's struct */
-- erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
-+ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
-
- if (!erase)
- return -ENOMEM;
-@@ -258,39 +463,40 @@
- * find the subdevice where the to-be-erased area begins, adjust
- * starting offset to be relative to the subdevice start
- */
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- subdev = concat->subdev[i];
-- if(subdev->size <= erase->addr)
-+ if (subdev->size <= erase->addr)
- erase->addr -= subdev->size;
- else
- break;
- }
-- if(i >= concat->num_subdev) /* must never happen since size */
-- BUG(); /* limit has been verified above */
-+
-+ /* must never happen since size limit has been verified above */
-+ if (i >= concat->num_subdev)
-+ BUG();
-
- /* now do the erase: */
- err = 0;
-- for(;length > 0; i++) /* loop for all subevices affected by this request */
-- {
-+ for (; length > 0; i++) {
-+ /* loop for all subdevices affected by this request */
- subdev = concat->subdev[i]; /* get current subdevice */
-
- /* limit length to subdevice's size: */
-- if(erase->addr + length > subdev->size)
-+ if (erase->addr + length > subdev->size)
- erase->len = subdev->size - erase->addr;
- else
- erase->len = length;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- {
-+ if (!(subdev->flags & MTD_WRITEABLE)) {
- err = -EROFS;
- break;
- }
- length -= erase->len;
-- if ((err = concat_dev_erase(subdev, erase)))
-- {
-- if(err == -EINVAL) /* sanity check: must never happen since */
-- BUG(); /* block alignment has been checked above */
-+ if ((err = concat_dev_erase(subdev, erase))) {
-+ /* sanity check: should never happen since
-+ * block alignment has been checked above */
-+ if (err == -EINVAL)
-+ BUG();
- break;
- }
- /*
-@@ -313,7 +519,7 @@
- return 0;
- }
-
--static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = -EINVAL;
-@@ -321,18 +527,15 @@
- if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-+ if (ofs >= subdev->size) {
- size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (ofs + len > subdev->size)
- size = subdev->size - ofs;
- else
-@@ -340,21 +543,21 @@
-
- err = subdev->lock(subdev, ofs, size);
-
-- if(err)
-+ if (err)
- break;
-
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- ofs = 0;
- }
-- }
-+
- return err;
- }
-
--static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = 0;
-@@ -362,18 +565,15 @@
- if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-+ if (ofs >= subdev->size) {
- size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-- else
-- {
- if (ofs + len > subdev->size)
- size = subdev->size - ofs;
- else
-@@ -381,17 +581,17 @@
-
- err = subdev->unlock(subdev, ofs, size);
-
-- if(err)
-+ if (err)
- break;
-
- len -= size;
-- if(len == 0)
-+ if (len == 0)
- break;
-
- err = -EINVAL;
- ofs = 0;
- }
-- }
-+
- return err;
- }
-
-@@ -400,8 +600,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->sync(subdev);
- }
-@@ -412,10 +611,9 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i, rc = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
-- if((rc = subdev->suspend(subdev)) < 0)
-+ if ((rc = subdev->suspend(subdev)) < 0)
- return rc;
- }
- return rc;
-@@ -426,8 +624,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->resume(subdev);
- }
-@@ -439,11 +636,10 @@
- * stored to *new_dev upon success. This function does _not_
- * register any devices: this is the caller's responsibility.
- */
--struct mtd_info *mtd_concat_create(
-- struct mtd_info *subdev[], /* subdevices to concatenate */
-+struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */
- int num_devs, /* number of subdevices */
-- char *name) /* name for the new device */
--{
-+ char *name)
-+{ /* name for the new device */
- int i;
- size_t size;
- struct mtd_concat *concat;
-@@ -451,21 +647,21 @@
- int num_erase_region;
-
- printk(KERN_NOTICE "Concatenating MTD devices:\n");
-- for(i = 0; i < num_devs; i++)
-+ for (i = 0; i < num_devs; i++)
- printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
- printk(KERN_NOTICE "into device \"%s\"\n", name);
-
- /* allocate the device structure */
- size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
-- concat = kmalloc (size, GFP_KERNEL);
-- if(!concat)
-- {
-- printk ("memory allocation error while creating concatenated device \"%s\"\n",
-+ concat = kmalloc(size, GFP_KERNEL);
-+ if (!concat) {
-+ printk
-+ ("memory allocation error while creating concatenated device \"%s\"\n",
- name);
- return NULL;
- }
- memset(concat, 0, size);
-- concat->subdev = (struct mtd_info **)(concat + 1);
-+ concat->subdev = (struct mtd_info **) (concat + 1);
-
- /*
- * Set up the new "super" device's MTD object structure, check for
-@@ -479,39 +675,53 @@
- concat->mtd.oobsize = subdev[0]->oobsize;
- concat->mtd.ecctype = subdev[0]->ecctype;
- concat->mtd.eccsize = subdev[0]->eccsize;
-+ if (subdev[0]->read_ecc)
-+ concat->mtd.read_ecc = concat_read_ecc;
-+ if (subdev[0]->write_ecc)
-+ concat->mtd.write_ecc = concat_write_ecc;
-+ if (subdev[0]->read_oob)
-+ concat->mtd.read_oob = concat_read_oob;
-+ if (subdev[0]->write_oob)
-+ concat->mtd.write_oob = concat_write_oob;
-
- concat->subdev[0] = subdev[0];
-
-- for(i = 1; i < num_devs; i++)
-- {
-- if(concat->mtd.type != subdev[i]->type)
-- {
-+ for (i = 1; i < num_devs; i++) {
-+ if (concat->mtd.type != subdev[i]->type) {
- kfree(concat);
-- printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device type on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
-- if(concat->mtd.flags != subdev[i]->flags)
-- { /*
-- * Expect all flags except MTD_WRITEABLE to be equal on
-- * all subdevices.
-+ if (concat->mtd.flags != subdev[i]->flags) {
-+ /*
-+ * Expect all flags except MTD_WRITEABLE to be
-+ * equal on all subdevices.
- */
-- if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
-- {
-+ if ((concat->mtd.flags ^ subdev[i]->
-+ flags) & ~MTD_WRITEABLE) {
- kfree(concat);
-- printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device flags on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
-- }
-- else /* if writeable attribute differs, make super device writeable */
-- concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
-+ } else
-+ /* if writeable attribute differs,
-+ make super device writeable */
-+ concat->mtd.flags |=
-+ subdev[i]->flags & MTD_WRITEABLE;
- }
- concat->mtd.size += subdev[i]->size;
-- if(concat->mtd.oobblock != subdev[i]->oobblock ||
-+ if (concat->mtd.oobblock != subdev[i]->oobblock ||
- concat->mtd.oobsize != subdev[i]->oobsize ||
- concat->mtd.ecctype != subdev[i]->ecctype ||
-- concat->mtd.eccsize != subdev[i]->eccsize)
-- {
-+ concat->mtd.eccsize != subdev[i]->eccsize ||
-+ !concat->mtd.read_ecc != !subdev[i]->read_ecc ||
-+ !concat->mtd.write_ecc != !subdev[i]->write_ecc ||
-+ !concat->mtd.read_oob != !subdev[i]->read_oob ||
-+ !concat->mtd.write_oob != !subdev[i]->write_oob) {
- kfree(concat);
-- printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible OOB or ECC data on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
- concat->subdev[i] = subdev[i];
-@@ -535,7 +745,6 @@
- concat->mtd.suspend = concat_suspend;
- concat->mtd.resume = concat_resume;
-
--
- /*
- * Combine the erase block size info of the subdevices:
- *
-@@ -544,44 +753,44 @@
- */
- max_erasesize = curr_erasesize = subdev[0]->erasesize;
- num_erase_region = 1;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /* if it differs from the last subdevice's erase size, count it */
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /* if it differs from the last subdevice's erase size, count it */
- ++num_erase_region;
- curr_erasesize = subdev[i]->erasesize;
-- if(curr_erasesize > max_erasesize)
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].erasesize !=
-+ curr_erasesize) {
- ++num_erase_region;
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-- if(curr_erasesize > max_erasesize)
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
- }
- }
- }
-
-- if(num_erase_region == 1)
-- { /*
-+ if (num_erase_region == 1) {
-+ /*
- * All subdevices have the same uniform erase size.
- * This is easy:
- */
- concat->mtd.erasesize = curr_erasesize;
- concat->mtd.numeraseregions = 0;
-- }
-- else
-- { /*
-+ } else {
-+ /*
- * erase block size varies across the subdevices: allocate
- * space to store the data describing the variable erase regions
- */
-@@ -590,12 +799,13 @@
-
- concat->mtd.erasesize = max_erasesize;
- concat->mtd.numeraseregions = num_erase_region;
-- concat->mtd.eraseregions = erase_region_p = kmalloc (
-- num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-- if(!erase_region_p)
-- {
-+ concat->mtd.eraseregions = erase_region_p =
-+ kmalloc(num_erase_region *
-+ sizeof (struct mtd_erase_region_info), GFP_KERNEL);
-+ if (!erase_region_p) {
- kfree(concat);
-- printk ("memory allocation error while creating erase region list"
-+ printk
-+ ("memory allocation error while creating erase region list"
- " for device \"%s\"\n", name);
- return NULL;
- }
-@@ -606,41 +816,48 @@
- */
- curr_erasesize = subdev[0]->erasesize;
- begin = position = 0;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /*
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /*
- * fill in an mtd_erase_region_info structure for the area
- * we have walked so far:
- */
- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position - begin) / curr_erasesize;
- begin = position;
-
- curr_erasesize = subdev[i]->erasesize;
- ++erase_region_p;
- }
- position += subdev[i]->size;
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].
-+ erasesize != curr_erasesize) {
- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position -
-+ begin) / curr_erasesize;
- begin = position;
-
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
- ++erase_region_p;
- }
-- position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
-+ position +=
-+ subdev[i]->eraseregions[j].
-+ numblocks * curr_erasesize;
- }
- }
- }
-@@ -660,16 +877,14 @@
- void mtd_concat_destroy(struct mtd_info *mtd)
- {
- struct mtd_concat *concat = CONCAT(mtd);
-- if(concat->mtd.numeraseregions)
-+ if (concat->mtd.numeraseregions)
- kfree(concat->mtd.eraseregions);
- kfree(concat);
- }
-
--
- EXPORT_SYMBOL(mtd_concat_create);
- EXPORT_SYMBOL(mtd_concat_destroy);
-
--
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
- MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdcore.c linux/drivers/mtd/mtdcore.c
---- linux-mips-2.4.27/drivers/mtd/mtdcore.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/mtdcore.c 2004-11-19 10:25:11.650237640 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Core registration and callback routines for MTD
- * drivers and users.
-@@ -17,6 +17,7 @@
- #include <linux/major.h>
- #include <linux/fs.h>
- #include <linux/ioctl.h>
-+#include <linux/init.h>
- #include <linux/mtd/compatmac.h>
- #ifdef CONFIG_PROC_FS
- #include <linux/proc_fs.h>
-@@ -24,9 +25,15 @@
-
- #include <linux/mtd/mtd.h>
-
--static DECLARE_MUTEX(mtd_table_mutex);
--static struct mtd_info *mtd_table[MAX_MTD_DEVICES];
--static struct mtd_notifier *mtd_notifiers = NULL;
-+/* These are exported solely for the purpose of mtd_blkdevs.c. You
-+ should not use them for _anything_ else */
-+DECLARE_MUTEX(mtd_table_mutex);
-+struct mtd_info *mtd_table[MAX_MTD_DEVICES];
-+
-+EXPORT_SYMBOL_GPL(mtd_table_mutex);
-+EXPORT_SYMBOL_GPL(mtd_table);
-+
-+static LIST_HEAD(mtd_notifiers);
-
- /**
- * add_mtd_device - register an MTD device
-@@ -44,21 +51,28 @@
-
- down(&mtd_table_mutex);
-
-- for (i=0; i< MAX_MTD_DEVICES; i++)
-- if (!mtd_table[i])
-- {
-- struct mtd_notifier *not=mtd_notifiers;
-+ for (i=0; i < MAX_MTD_DEVICES; i++)
-+ if (!mtd_table[i]) {
-+ struct list_head *this;
-
- mtd_table[i] = mtd;
- mtd->index = i;
-+ mtd->usecount = 0;
-+
- DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
-- while (not)
-- {
-- (*(not->add))(mtd);
-- not = not->next;
-+ /* No need to get a refcount on the module containing
-+ the notifier, since we hold the mtd_table_mutex */
-+ list_for_each(this, &mtd_notifiers) {
-+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
-+ not->add(mtd);
- }
-+
- up(&mtd_table_mutex);
-- MOD_INC_USE_COUNT;
-+ /* We _know_ we aren't being removed, because
-+ our caller is still holding us here. So none
-+ of this try_ nonsense, and no bitching about it
-+ either. :) */
-+ __module_get(THIS_MODULE);
- return 0;
- }
-
-@@ -78,29 +92,34 @@
-
- int del_mtd_device (struct mtd_info *mtd)
- {
-- struct mtd_notifier *not=mtd_notifiers;
-- int i;
-+ int ret;
-
- down(&mtd_table_mutex);
-
-- for (i=0; i < MAX_MTD_DEVICES; i++)
-- {
-- if (mtd_table[i] == mtd)
-- {
-- while (not)
-- {
-- (*(not->remove))(mtd);
-- not = not->next;
-- }
-- mtd_table[i] = NULL;
-- up (&mtd_table_mutex);
-- MOD_DEC_USE_COUNT;
-- return 0;
-+ if (mtd_table[mtd->index] != mtd) {
-+ ret = -ENODEV;
-+ } else if (mtd->usecount) {
-+ printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
-+ mtd->index, mtd->name, mtd->usecount);
-+ ret = -EBUSY;
-+ } else {
-+ struct list_head *this;
-+
-+ /* No need to get a refcount on the module containing
-+ the notifier, since we hold the mtd_table_mutex */
-+ list_for_each(this, &mtd_notifiers) {
-+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
-+ not->remove(mtd);
- }
-+
-+ mtd_table[mtd->index] = NULL;
-+
-+ module_put(THIS_MODULE);
-+ ret = 0;
- }
-
- up(&mtd_table_mutex);
-- return 1;
-+ return ret;
- }
-
- /**
-@@ -118,10 +137,9 @@
-
- down(&mtd_table_mutex);
-
-- new->next = mtd_notifiers;
-- mtd_notifiers = new;
-+ list_add(&new->list, &mtd_notifiers);
-
-- MOD_INC_USE_COUNT;
-+ __module_get(THIS_MODULE);
-
- for (i=0; i< MAX_MTD_DEVICES; i++)
- if (mtd_table[i])
-@@ -142,34 +160,24 @@
-
- int unregister_mtd_user (struct mtd_notifier *old)
- {
-- struct mtd_notifier **prev = &mtd_notifiers;
-- struct mtd_notifier *cur;
- int i;
-
- down(&mtd_table_mutex);
-
-- while ((cur = *prev)) {
-- if (cur == old) {
-- *prev = cur->next;
--
-- MOD_DEC_USE_COUNT;
-+ module_put(THIS_MODULE);
-
- for (i=0; i< MAX_MTD_DEVICES; i++)
- if (mtd_table[i])
- old->remove(mtd_table[i]);
-
-+ list_del(&old->list);
- up(&mtd_table_mutex);
- return 0;
-- }
-- prev = &cur->next;
-- }
-- up(&mtd_table_mutex);
-- return 1;
- }
-
-
- /**
-- * __get_mtd_device - obtain a validated handle for an MTD device
-+ * get_mtd_device - obtain a validated handle for an MTD device
- * @mtd: last known address of the required MTD device
- * @num: internal device number of the required MTD device
- *
-@@ -177,11 +185,10 @@
- * table, if any. Given an address and num == -1, search the device table
- * for a device with that address and return if it's still present. Given
- * both, return the num'th driver only if its address matches. Return NULL
-- * if not. get_mtd_device() increases the use count, but
-- * __get_mtd_device() doesn't - you should generally use get_mtd_device().
-+ * if not.
- */
-
--struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num)
-+struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
- {
- struct mtd_info *ret = NULL;
- int i;
-@@ -198,10 +205,27 @@
- ret = NULL;
- }
-
-+ if (ret && !try_module_get(ret->owner))
-+ ret = NULL;
-+
-+ if (ret)
-+ ret->usecount++;
-+
- up(&mtd_table_mutex);
- return ret;
- }
-
-+void put_mtd_device(struct mtd_info *mtd)
-+{
-+ int c;
-+
-+ down(&mtd_table_mutex);
-+ c = --mtd->usecount;
-+ up(&mtd_table_mutex);
-+ BUG_ON(c < 0);
-+
-+ module_put(mtd->owner);
-+}
-
- /* default_mtd_writev - default mtd writev method for MTD devices that
- * dont implement their own
-@@ -265,7 +289,8 @@
-
- EXPORT_SYMBOL(add_mtd_device);
- EXPORT_SYMBOL(del_mtd_device);
--EXPORT_SYMBOL(__get_mtd_device);
-+EXPORT_SYMBOL(get_mtd_device);
-+EXPORT_SYMBOL(put_mtd_device);
- EXPORT_SYMBOL(register_mtd_user);
- EXPORT_SYMBOL(unregister_mtd_user);
- EXPORT_SYMBOL(default_mtd_writev);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdpart.c linux/drivers/mtd/mtdpart.c
---- linux-mips-2.4.27/drivers/mtd/mtdpart.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/mtdpart.c 2004-11-19 10:25:11.652237336 +0100
-@@ -5,7 +5,7 @@
- *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- *
- * 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
- * added support for read_oob, write_oob
-@@ -16,10 +16,11 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/list.h>
--
-+#include <linux/config.h>
-+#include <linux/kmod.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
--
-+#include <linux/mtd/compatmac.h>
-
- /* Our partition linked list */
- static LIST_HEAD(mtd_partitions);
-@@ -54,8 +55,12 @@
- len = 0;
- else if (from + len > mtd->size)
- len = mtd->size - from;
-+ if (part->master->read_ecc == NULL)
- return part->master->read (part->master, from + part->offset,
- len, retlen, buf);
-+ else
-+ return part->master->read_ecc (part->master, from + part->offset,
-+ len, retlen, buf, NULL, &mtd->oobinfo);
- }
-
- static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
-@@ -78,9 +83,11 @@
-
-
- static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
-+ size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- if (from >= mtd->size)
- len = 0;
- else if (from + len > mtd->size)
-@@ -113,7 +120,7 @@
- size_t *retlen, u_char *buf)
- {
- struct mtd_part *part = PART(mtd);
-- return part->master->read_user_prot_reg (part->master, from,
-+ return part->master->read_fact_prot_reg (part->master, from,
- len, retlen, buf);
- }
-
-@@ -127,17 +134,24 @@
- len = 0;
- else if (to + len > mtd->size)
- len = mtd->size - to;
-+ if (part->master->write_ecc == NULL)
- return part->master->write (part->master, to + part->offset,
- len, retlen, buf);
-+ else
-+ return part->master->write_ecc (part->master, to + part->offset,
-+ len, retlen, buf, NULL, &mtd->oobinfo);
-+
- }
-
- static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- if (to >= mtd->size)
- len = 0;
- else if (to + len > mtd->size)
-@@ -174,25 +188,37 @@
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (part->master->writev_ecc == NULL)
- return part->master->writev (part->master, vecs, count,
- to + part->offset, retlen);
-+ else
-+ return part->master->writev_ecc (part->master, vecs, count,
-+ to + part->offset, retlen,
-+ NULL, &mtd->oobinfo);
- }
-
- 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);
-+ if (part->master->readv_ecc == NULL)
- return part->master->readv (part->master, vecs, count,
- from + part->offset, retlen);
-+ else
-+ return part->master->readv_ecc (part->master, vecs, count,
-+ from + part->offset, retlen,
-+ NULL, &mtd->oobinfo);
- }
-
- static int part_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- return part->master->writev_ecc (part->master, vecs, count,
- to + part->offset, retlen,
- eccbuf, oobsel);
-@@ -200,9 +226,11 @@
-
- static int part_readv_ecc (struct mtd_info *mtd, struct iovec *vecs,
- unsigned long count, loff_t from, size_t *retlen,
-- u_char *eccbuf, int oobsel)
-+ u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
- struct mtd_part *part = PART(mtd);
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
- return part->master->readv_ecc (part->master, vecs, count,
- from + part->offset, retlen,
- eccbuf, oobsel);
-@@ -288,7 +316,7 @@
- */
-
- int add_mtd_partitions(struct mtd_info *master,
-- struct mtd_partition *parts,
-+ const struct mtd_partition *parts,
- int nbparts)
- {
- struct mtd_part *slave;
-@@ -321,7 +349,7 @@
-
- slave->mtd.name = parts[i].name;
- slave->mtd.bank_size = master->bank_size;
-- slave->mtd.module = master->module;
-+ slave->mtd.owner = master->owner;
-
- slave->mtd.read = part_read;
- slave->mtd.write = part_write;
-@@ -452,6 +480,75 @@
- EXPORT_SYMBOL(add_mtd_partitions);
- EXPORT_SYMBOL(del_mtd_partitions);
-
-+static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED;
-+static LIST_HEAD(part_parsers);
-+
-+struct mtd_part_parser *get_partition_parser(const char *name)
-+{
-+ struct list_head *this;
-+ void *ret = NULL;
-+ spin_lock(&part_parser_lock);
-+
-+ list_for_each(this, &part_parsers) {
-+ struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list);
-+
-+ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
-+ ret = p;
-+ break;
-+ }
-+ }
-+ spin_unlock(&part_parser_lock);
-+
-+ return ret;
-+}
-+
-+int register_mtd_parser(struct mtd_part_parser *p)
-+{
-+ spin_lock(&part_parser_lock);
-+ list_add(&p->list, &part_parsers);
-+ spin_unlock(&part_parser_lock);
-+
-+ return 0;
-+}
-+
-+int deregister_mtd_parser(struct mtd_part_parser *p)
-+{
-+ spin_lock(&part_parser_lock);
-+ list_del(&p->list);
-+ spin_unlock(&part_parser_lock);
-+ return 0;
-+}
-+
-+int parse_mtd_partitions(struct mtd_info *master, const char **types,
-+ struct mtd_partition **pparts, unsigned long origin)
-+{
-+ struct mtd_part_parser *parser;
-+ int ret = 0;
-+
-+ for ( ; ret <= 0 && *types; types++) {
-+ parser = get_partition_parser(*types);
-+#ifdef CONFIG_KMOD
-+ if (!parser && !request_module("%s", *types))
-+ parser = get_partition_parser(*types);
-+#endif
-+ if (!parser) {
-+ printk(KERN_NOTICE "%s partition parsing not available\n",
-+ *types);
-+ continue;
-+ }
-+ ret = (*parser->parse_fn)(master, pparts, origin);
-+ if (ret > 0) {
-+ printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
-+ ret, parser->name, master->name);
-+ }
-+ put_partition_parser(parser);
-+ }
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL_GPL(parse_mtd_partitions);
-+EXPORT_SYMBOL_GPL(register_mtd_parser);
-+EXPORT_SYMBOL_GPL(deregister_mtd_parser);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/Config.in linux/drivers/mtd/nand/Config.in
---- linux-mips-2.4.27/drivers/mtd/nand/Config.in 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/Config.in 2004-11-19 10:25:11.987186416 +0100
-@@ -1,6 +1,6 @@
- # drivers/mtd/nand/Config.in
-
--# $Id$
-+# $Id$
-
- mainmenu_option next_comment
-
-@@ -11,26 +11,27 @@
- bool ' Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
- fi
-
--if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
-- dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
-+if [ "$CONFIG_ARM" = "y" ]; then
-+ dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND $CONFIG_ARCH_P720T
-+ dep_tristate ' NAND Flash device on TOTO board' CONFIG_MTD_NAND_TOTO $CONFIG_MTD_NAND $CONFIG_ARCH_OMAP
-+ dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND $CONFIG_ARCH_AUTCPU12
-+ dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND $CONFIG_ARCH_EDB7312
- fi
-
--if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then
-- dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND
--fi
--
--if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then
-- dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND
--fi
--
--if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
-+if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
- define_bool CONFIG_MTD_NAND_IDS y
-+else
-+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
-+ define_bool CONFIG_MTD_NAND_IDS m
-+ fi
- fi
-
--if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then
--if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
-- define_bool CONFIG_MTD_NAND_IDS m
-+if [ "$CONFIG_TOSHIBA_RBTX4925" = "y" ]; then
-+ dep_tristate ' SmartMedia Card on Toshiba RBTX4925 reference board' CONFIG_MTD_NAND_TX4925NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4925_MPLEX_NAND
- fi
-+
-+if [ "$CONFIG_TOSHIBA_RBTX4938" = "y" ]; then
-+ dep_tristate ' NAND Flash device on Toshiba RBTX4938 reference board' CONFIG_MTD_NAND_TX4938NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND
- fi
-
- endmenu
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/Makefile linux/drivers/mtd/nand/Makefile
---- linux-mips-2.4.27/drivers/mtd/nand/Makefile 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/Makefile 2004-11-19 10:25:11.989186112 +0100
-@@ -1,16 +1,20 @@
- #
- # linux/drivers/nand/Makefile
- #
--# $Id$
-+# $Id$
-
-+ifeq ($(PATCHLEVEL),4)
- O_TARGET := nandlink.o
--
- export-objs := nand.o nand_ecc.o nand_ids.o
-+endif
-
- obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
- obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
-+obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
- obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
- obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
-+obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o
-+obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o
- obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
-
--include $(TOPDIR)/Rules.make
-+-include $(TOPDIR)/Rules.make
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/autcpu12.c linux/drivers/mtd/nand/autcpu12.c
---- linux-mips-2.4.27/drivers/mtd/nand/autcpu12.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/autcpu12.c 2004-11-19 10:25:11.990185960 +0100
-@@ -4,9 +4,9 @@
- * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
- *
- * Derived from drivers/mtd/spia.c
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -25,10 +25,10 @@
- * added page_cache
- *
- * 10-06-2002 TG 128K card support added
-- *
- */
-
- #include <linux/slab.h>
-+#include <linux/init.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
-@@ -70,6 +70,7 @@
- /*
- * Define partitions for flash devices
- */
-+extern struct nand_oobinfo jffs2_oobinfo;
-
- static struct mtd_partition partition_info16k[] = {
- { name: "AUTCPU12 flash partition 1",
-@@ -95,7 +96,7 @@
- size: 16 * SZ_1M },
- { name: "AUTCPU12 flash partition 2",
- offset: 16 * SZ_1M,
-- size: 48 * SZ_1M},
-+ size: 48 * SZ_1M },
- };
-
- static struct mtd_partition partition_info128k[] = {
-@@ -104,7 +105,7 @@
- size: 16 * SZ_1M },
- { name: "AUTCPU12 flash partition 2",
- offset: 16 * SZ_1M,
-- size: 112 * SZ_1M},
-+ size: 112 * SZ_1M },
- };
-
- #define NUM_PARTITIONS16K 2
-@@ -114,7 +115,7 @@
- /*
- * hardware specific access to control-lines
- */
--void autcpu12_hwcontrol(int cmd)
-+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
- {
-
- switch(cmd){
-@@ -133,7 +134,7 @@
- /*
- * read device ready pin
- */
--int autcpu12_device_ready(void)
-+int autcpu12_device_ready(struct mtd_info *mtd)
- {
-
- return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
-@@ -184,7 +185,7 @@
- this->eccmode = NAND_ECC_SOFT;
-
- /* Scan to find existance of the device */
-- if (nand_scan (autcpu12_mtd)) {
-+ if (nand_scan (autcpu12_mtd, 1)) {
- err = -ENXIO;
- goto out_ior;
- }
-@@ -197,15 +198,6 @@
- goto out_ior;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk ("Unable to allocate NAND data cache for AUTCPU12.\n");
-- err = -ENOMEM;
-- goto out_buf;
-- }
-- this->cache_page = -1;
--
- /* Register the partitions */
- switch(autcpu12_mtd->size){
- case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
-@@ -215,13 +207,11 @@
- default: {
- printk ("Unsupported SmartMedia device\n");
- err = -ENXIO;
-- goto out_cac;
-+ goto out_buf;
- }
- }
- goto out;
-
--out_cac:
-- kfree (this->data_cache);
- out_buf:
- kfree (this->data_buf);
- out_ior:
-@@ -250,7 +240,6 @@
-
- /* Free internal data buffers */
- kfree (this->data_buf);
-- kfree (this->data_cache);
-
- /* unmap physical adress */
- iounmap((void *)autcpu12_fio_base);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/diskonchip.c linux/drivers/mtd/nand/diskonchip.c
---- linux-mips-2.4.27/drivers/mtd/nand/diskonchip.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/nand/diskonchip.c 2004-11-19 10:25:11.992185656 +0100
-@@ -0,0 +1,534 @@
-+/*
-+ * drivers/mtd/nand/diskonchip.c
-+ *
-+ * (C) 2003 Red Hat, Inc.
-+ *
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to generic NAND code for M-Systems DiskOnChip devices
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/doc2000.h>
-+#include <linux/mtd/compatmac.h>
-+
-+struct doc_priv {
-+ unsigned long virtadr;
-+ unsigned long physadr;
-+ u_char ChipID;
-+ u_char CDSNControl;
-+ int chips_per_floor; /* The number of chips detected on each floor */
-+ int curfloor;
-+ int curchip;
-+};
-+
-+#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
-+#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-+
-+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
-+static void doc200x_select_chip(struct mtd_info *mtd, int chip);
-+
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+
-+static int try_dword=1;
-+MODULE_PARM(try_dword, "i");
-+
-+static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
-+{
-+ volatile char dummy;
-+ int i;
-+
-+ for (i = 0; i < cycles; i++) {
-+ if (DoC_is_Millennium(doc))
-+ dummy = ReadDOC(doc->virtadr, NOP);
-+ else
-+ dummy = ReadDOC(doc->virtadr, DOCStatus);
-+ }
-+
-+}
-+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
-+static int _DoC_WaitReady(struct doc_priv *doc)
-+{
-+ unsigned long docptr = doc->virtadr;
-+ unsigned long timeo = jiffies + (HZ * 10);
-+
-+ if(debug) printk("_DoC_WaitReady...\n");
-+ /* Out-of-line routine to wait for chip response */
-+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+ if (time_after(jiffies, timeo)) {
-+ printk("_DoC_WaitReady timed out.\n");
-+ return -EIO;
-+ }
-+ udelay(1);
-+ cond_resched();
-+ }
-+
-+ return 0;
-+}
-+
-+static inline int DoC_WaitReady(struct doc_priv *doc)
-+{
-+ unsigned long docptr = doc->virtadr;
-+ int ret = 0;
-+
-+ DoC_Delay(doc, 4);
-+
-+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-+ /* Call the out-of-line routine to wait */
-+ ret = _DoC_WaitReady(doc);
-+
-+ DoC_Delay(doc, 2);
-+ if(debug) printk("DoC_WaitReady OK\n");
-+ return ret;
-+}
-+
-+static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ if(debug)printk("write_byte %02x\n", datum);
-+ WriteDOC(datum, docptr, CDSNSlowIO);
-+ WriteDOC(datum, docptr, 2k_CDSN_IO);
-+}
-+
-+static u_char doc2000_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ ReadDOC(docptr, CDSNSlowIO);
-+ u_char ret = ReadDOC(docptr, 2k_CDSN_IO);
-+ if (debug) printk("read_byte returns %02x\n", ret);
-+ return ret;
-+}
-+static void doc2000_writebuf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+ if (debug)printk("writebuf of %d bytes: ", len);
-+ for (i=0; i < len; i++) {
-+ WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
-+ if (debug && i < 16)
-+ printk("%02x ", buf[i]);
-+ }
-+ if (debug) printk("\n");
-+}
-+
-+static void doc2000_readbuf(struct mtd_info *mtd,
-+ u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ if (debug)printk("readbuf of %d bytes: ", len);
-+
-+ for (i=0; i < len; i++) {
-+ buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
-+ }
-+}
-+
-+static void doc2000_readbuf_dword(struct mtd_info *mtd,
-+ u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ if (debug) printk("readbuf_dword of %d bytes: ", len);
-+
-+ if (unlikely((((unsigned long)buf)|len) & 3)) {
-+ for (i=0; i < len; i++) {
-+ *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
-+ }
-+ } else {
-+ for (i=0; i < len; i+=4) {
-+ *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
-+ }
-+ }
-+}
-+
-+static int doc2000_verifybuf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ for (i=0; i < len; i++)
-+ if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))
-+ return i;
-+ return 0;
-+}
-+
-+static uint16_t doc200x_ident_chip(struct mtd_info *mtd, int nr)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ uint16_t ret;
-+
-+ doc200x_select_chip(mtd, nr);
-+ doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
-+ this->write_byte(mtd, NAND_CMD_READID);
-+ doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
-+ doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
-+ this->write_byte(mtd, 0);
-+ doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-+
-+ ret = this->read_byte(mtd) << 8;
-+ ret |= this->read_byte(mtd);
-+
-+ if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
-+ /* First chip probe. See if we get same results by 32-bit access */
-+ union {
-+ uint32_t dword;
-+ uint8_t byte[4];
-+ } ident;
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
-+ doc2000_write_byte(mtd, NAND_CMD_READID);
-+ doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
-+ doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
-+ doc2000_write_byte(mtd, 0);
-+ doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-+
-+ ident.dword = readl(docptr + DoC_2k_CDSN_IO);
-+ if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
-+ printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
-+ this->read_buf = &doc2000_readbuf_dword;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static void doc2000_count_chips(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ uint16_t mfrid;
-+ int i;
-+
-+ /* Max 4 chips per floor on DiskOnChip 2000 */
-+ doc->chips_per_floor = 4;
-+
-+ /* Find out what the first chip is */
-+ mfrid = doc200x_ident_chip(mtd, 0);
-+
-+ /* Find how many chips in each floor. */
-+ for (i = 1; i < 4; i++) {
-+ if (doc200x_ident_chip(mtd, i) != mfrid)
-+ break;
-+ }
-+ doc->chips_per_floor = i;
-+}
-+
-+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
-+{
-+ struct doc_priv *doc = (void *)this->priv;
-+
-+ int status;
-+
-+ DoC_WaitReady(doc);
-+ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-+ DoC_WaitReady(doc);
-+ status = (int)this->read_byte(mtd);
-+
-+ return status;
-+}
-+
-+static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ WriteDOC(datum, docptr, CDSNSlowIO);
-+ WriteDOC(datum, docptr, Mil_CDSN_IO);
-+ WriteDOC(datum, docptr, WritePipeTerm);
-+}
-+
-+static u_char doc2001_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ ReadDOC(docptr, CDSNSlowIO);
-+ /* 11.4.5 -- delay twice to allow extended length cycle */
-+ DoC_Delay(doc, 2);
-+ ReadDOC(docptr, ReadPipeInit);
-+ return ReadDOC(docptr, Mil_CDSN_IO);
-+}
-+
-+static void doc2001_writebuf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ for (i=0; i < len; i++)
-+ WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
-+ /* Terminate write pipeline */
-+ WriteDOC(0x00, docptr, WritePipeTerm);
-+}
-+
-+static void doc2001_readbuf(struct mtd_info *mtd,
-+ u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ /* Start read pipeline */
-+ ReadDOC(docptr, ReadPipeInit);
-+
-+ for (i=0; i < len-1; i++)
-+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
-+
-+ /* Terminate read pipeline */
-+ buf[i] = ReadDOC(docptr, LastDataRead);
-+}
-+static int doc2001_verifybuf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int i;
-+
-+ /* Start read pipeline */
-+ ReadDOC(docptr, ReadPipeInit);
-+
-+ for (i=0; i < len-1; i++)
-+ if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
-+ ReadDOC(docptr, LastDataRead);
-+ return i;
-+ }
-+ if (buf[i] != ReadDOC(docptr, LastDataRead))
-+ return i;
-+ return 0;
-+}
-+
-+static void doc200x_select_chip(struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+ int floor = 0;
-+
-+ /* 11.4.4 -- deassert CE before changing chip */
-+ doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
-+
-+ if(debug)printk("select chip (%d)\n", chip);
-+
-+ if (chip == -1)
-+ return;
-+
-+ floor = chip / doc->chips_per_floor;
-+ chip -= (floor * doc->chips_per_floor);
-+
-+ WriteDOC(floor, docptr, FloorSelect);
-+ WriteDOC(chip, docptr, CDSNDeviceSelect);
-+
-+ doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
-+
-+ doc->curchip = chip;
-+ doc->curfloor = floor;
-+}
-+
-+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ switch(cmd) {
-+ case NAND_CTL_SETNCE:
-+ doc->CDSNControl |= CDSN_CTRL_CE;
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ doc->CDSNControl &= ~CDSN_CTRL_CE;
-+ break;
-+ case NAND_CTL_SETCLE:
-+ doc->CDSNControl |= CDSN_CTRL_CLE;
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ doc->CDSNControl &= ~CDSN_CTRL_CLE;
-+ break;
-+ case NAND_CTL_SETALE:
-+ doc->CDSNControl |= CDSN_CTRL_ALE;
-+ break;
-+ case NAND_CTL_CLRALE:
-+ doc->CDSNControl &= ~CDSN_CTRL_ALE;
-+ break;
-+ case NAND_CTL_SETWP:
-+ doc->CDSNControl |= CDSN_CTRL_WP;
-+ break;
-+ case NAND_CTL_CLRWP:
-+ doc->CDSNControl &= ~CDSN_CTRL_WP;
-+ break;
-+ }
-+ if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
-+ WriteDOC(doc->CDSNControl, docptr, CDSNControl);
-+ /* 11.4.3 -- 4 NOPs after CSDNControl write */
-+ DoC_Delay(doc, 4);
-+}
-+
-+static int doc200x_dev_ready(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ struct doc_priv *doc = (void *)this->priv;
-+ unsigned long docptr = doc->virtadr;
-+
-+ /* 11.4.2 -- must NOP four times before checking FR/B# */
-+ DoC_Delay(doc, 4);
-+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+ if(debug)
-+ printk("not ready\n");
-+ return 0;
-+ }
-+ /* 11.4.2 -- Must NOP twice if it's ready */
-+ DoC_Delay(doc, 2);
-+ if (debug)printk("was ready\n");
-+ return 1;
-+}
-+
-+static int doc200x_block_bad(struct mtd_info *mtd, unsigned long block)
-+{
-+ /* FIXME: Look it up in the BBT */
-+ return 0;
-+}
-+
-+struct doc_priv mydoc = {
-+ .physadr = 0xd4000,
-+ .curfloor = -1,
-+ .curchip = -1,
-+};
-+
-+u_char mydatabuf[528];
-+
-+struct nand_chip mynand = {
-+ .priv = (void *)&mydoc,
-+ .select_chip = doc200x_select_chip,
-+ .hwcontrol = doc200x_hwcontrol,
-+ .dev_ready = doc200x_dev_ready,
-+ .waitfunc = doc200x_wait,
-+ .block_bad = doc200x_block_bad,
-+ .eccmode = NAND_ECC_SOFT,
-+ .data_buf = mydatabuf,
-+};
-+
-+struct mtd_info mymtd = {
-+ .priv = (void *)&mynand,
-+ .owner = THIS_MODULE,
-+};
-+
-+int __init init_nanddoc(void)
-+{
-+ mydoc.virtadr = (unsigned long)ioremap(mydoc.physadr, DOC_IOREMAP_LEN);
-+ int nrchips = 1;
-+ char *name;
-+
-+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
-+ mydoc.virtadr, DOCControl);
-+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
-+ mydoc.virtadr, DOCControl);
-+
-+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
-+ mydoc.virtadr, DOCControl);
-+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
-+ mydoc.virtadr, DOCControl);
-+
-+ mydoc.ChipID = ReadDOC(mydoc.virtadr, ChipID);
-+
-+ switch(mydoc.ChipID) {
-+ case DOC_ChipID_DocMil:
-+ mynand.write_byte = doc2001_write_byte;
-+ mynand.read_byte = doc2001_read_byte;
-+ mynand.write_buf = doc2001_writebuf;
-+ mynand.read_buf = doc2001_readbuf;
-+ mynand.verify_buf = doc2001_verifybuf;
-+
-+ ReadDOC(mydoc.virtadr, ChipID);
-+ ReadDOC(mydoc.virtadr, ChipID);
-+ if (ReadDOC(mydoc.virtadr, ChipID) != DOC_ChipID_DocMil) {
-+ /* It's not a Millennium; it's one of the newer
-+ DiskOnChip 2000 units with a similar ASIC.
-+ Treat it like a Millennium, except that it
-+ can have multiple chips. */
-+ doc2000_count_chips(&mymtd);
-+ nrchips = 4 * mydoc.chips_per_floor;
-+ name = "DiskOnChip 2000 (INFTL Model)";
-+ } else {
-+ /* Bog-standard Millennium */
-+ mydoc.chips_per_floor = 1;
-+ nrchips = 1;
-+ name = "DiskOnChip Millennium";
-+ }
-+ break;
-+
-+ case DOC_ChipID_Doc2k:
-+ mynand.write_byte = doc2000_write_byte;
-+ mynand.read_byte = doc2000_read_byte;
-+ mynand.write_buf = doc2000_writebuf;
-+ mynand.read_buf = doc2000_readbuf;
-+ mynand.verify_buf = doc2000_verifybuf;
-+
-+ doc2000_count_chips(&mymtd);
-+ nrchips = 4 * mydoc.chips_per_floor;
-+ name = "DiskOnChip 2000 (NFTL Model)";
-+ mydoc.CDSNControl |= CDSN_CTRL_FLASH_IO;
-+
-+ break;
-+
-+ default:
-+ return -EIO;
-+ }
-+ if (nand_scan(&mymtd, nrchips)) {
-+ iounmap((void *)mydoc.virtadr);
-+ return -EIO;
-+ }
-+ mymtd.name = name;
-+ add_mtd_device(&mymtd);
-+
-+ return 0;
-+}
-+
-+void __exit cleanup_nanddoc(void)
-+{
-+ del_mtd_device(&mymtd);
-+ iounmap((void *)mydoc.virtadr);
-+}
-+
-+module_init(init_nanddoc);
-+module_exit(cleanup_nanddoc);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000 and Millennium device driver\n");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/edb7312.c linux/drivers/mtd/nand/edb7312.c
---- linux-mips-2.4.27/drivers/mtd/nand/edb7312.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/edb7312.c 2004-11-19 10:25:11.997184896 +0100
-@@ -6,7 +6,7 @@
- * Derived from drivers/mtd/nand/autcpu12.c
- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -20,6 +20,7 @@
-
- #include <linux/slab.h>
- #include <linux/module.h>
-+#include <linux/init.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/partitions.h>
-@@ -77,16 +78,13 @@
- };
- #define NUM_PARTITIONS 1
-
--extern int parse_cmdline_partitions(struct mtd_info *master,
-- struct mtd_partition **pparts,
-- const char *mtd_id);
- #endif
-
-
- /*
- * hardware specific access to control-lines
- */
--static void ep7312_hwcontrol(int cmd)
-+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
- {
- switch(cmd) {
-
-@@ -116,10 +114,13 @@
- /*
- * read device ready pin
- */
--static int ep7312_device_ready(void)
-+static int ep7312_device_ready(struct mtd_info *mtd)
- {
- return 1;
- }
-+#ifdef CONFIG_MTD_PARTITIONS
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+#endif
-
- /*
- * Main initialization routine
-@@ -174,7 +175,7 @@
- this->chip_delay = 15;
-
- /* Scan to find existence of the device */
-- if (nand_scan (ep7312_mtd)) {
-+ if (nand_scan (ep7312_mtd, 1)) {
- iounmap((void *)ep7312_fio_base);
- kfree (ep7312_mtd);
- return -ENXIO;
-@@ -189,27 +190,16 @@
- return -ENOMEM;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk("Unable to allocate NAND data cache for EDB7312.\n");
-- kfree (this->data_buf);
-- iounmap((void *)ep7312_fio_base);
-- kfree (ep7312_mtd);
-- return -ENOMEM;
-- }
-- this->cache_page = -1;
--
--#ifdef CONFIG_MTD_CMDLINE_PARTS
-- mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts,
-- "edb7312-nand");
-+#ifdef CONFIG_PARTITIONS
-+ ep7312_mtd->name = "edb7312-nand";
-+ mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
-+ &mtd_parts, 0);
- if (mtd_parts_nb > 0)
- part_type = "command line";
- else
- mtd_parts_nb = 0;
- #endif
-- if (mtd_parts_nb == 0)
-- {
-+ if (mtd_parts_nb == 0) {
- mtd_parts = partition_info;
- mtd_parts_nb = NUM_PARTITIONS;
- part_type = "static";
-@@ -236,7 +226,6 @@
-
- /* Free internal data buffer */
- kfree (this->data_buf);
-- kfree (this->data_cache);
-
- /* Free the MTD device structure */
- kfree (ep7312_mtd);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand.c linux/drivers/mtd/nand/nand.c
---- linux-mips-2.4.27/drivers/mtd/nand/nand.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/nand.c 2004-11-19 10:25:12.010182920 +0100
-@@ -8,7 +8,7 @@
- * Additional technical information is available on
- * http://www.linux-mtd.infradead.org/tech/nand.html
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- * 10-29-2001 Thomas Gleixner (tglx@linutronix.de)
-@@ -112,10 +112,27 @@
- * for mtd->read_ecc / mtd->write_ecc
- * some minor cleanups
- *
-- * 12-05-2000 tglx: Dave Ellis (DGE@sixnetio) provided the fix for
-+ * 12-05-2002 tglx: Dave Ellis (DGE@sixnetio) provided the fix for
- * WRITE_VERIFY long time ago. Thanks for remembering me.
- *
-- * $Id$
-+ * 02-14-2003 tglx: Reject non page aligned writes
-+ * Fixed ecc select in nand_write_page to match semantics.
-+ *
-+ * 02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector
-+ *
-+ * 02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to
-+ + a structure, which will be supplied by a filesystem driver
-+ * If NULL is given, then the defaults (none or defaults
-+ * supplied by ioctl (MEMSETOOBSEL) are used.
-+ * For partitions the partition defaults are used (mtdpart.c)
-+ *
-+ * 06-04-2003 tglx: fix compile errors and fix write verify problem for
-+ * some chips, which need either a delay between the readback
-+ * and the next write command or have the CE removed. The
-+ * CE disable/enable is much faster than a 20us delay and
-+ * it should work on all available chips.
-+ *
-+ * $Id$
- *
- * 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
-@@ -130,102 +147,151 @@
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nand_ecc.h>
-+#include <linux/mtd/compatmac.h>
- #include <linux/interrupt.h>
- #include <asm/io.h>
-
- /*
-- * Macros for low-level register control
-- */
--#define nand_select() this->hwcontrol(NAND_CTL_SETNCE);
--
--#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
--
--/*
-- * out of band configuration for different filesystems
-- */
--static int oobconfigs[][6] = {
-- { 0,0,0,0,0,0},
--
-- { NAND_JFFS2_OOB_ECCPOS0, NAND_JFFS2_OOB_ECCPOS1, NAND_JFFS2_OOB_ECCPOS2,
-- NAND_JFFS2_OOB_ECCPOS3, NAND_JFFS2_OOB_ECCPOS4, NAND_JFFS2_OOB_ECCPOS5 },
--
-- { NAND_YAFFS_OOB_ECCPOS0, NAND_YAFFS_OOB_ECCPOS1, NAND_YAFFS_OOB_ECCPOS2,
-- NAND_YAFFS_OOB_ECCPOS3, NAND_YAFFS_OOB_ECCPOS4, NAND_YAFFS_OOB_ECCPOS5 }
--};
--
--/*
- * NAND low-level MTD interface functions
- */
-+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
-+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
-+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
-+
- 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 * eccbuf, int oobsel);
-+ size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
- 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 * eccbuf, int oobsel);
-+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
- 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_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
-- unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel);
-+ unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
- static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
- static void nand_sync (struct mtd_info *mtd);
--static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col,
-- int last, u_char *oob_buf, int oobsel);
-+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel);
-+
-+static u_char nand_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ return readb(this->IO_ADDR_R);
-+}
-+
-+static void nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ writeb(byte, this->IO_ADDR_W);
-+}
-+
-+static void nand_select_chip(struct mtd_info *mtd, int chip)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ switch(chip) {
-+ case -1:
-+ this->hwcontrol(mtd, NAND_CTL_CLRNCE);
-+ break;
-+ case 0:
-+ this->hwcontrol(mtd, NAND_CTL_SETNCE);
-+ break;
-+
-+ default:
-+ BUG();
-+ }
-+}
-+
-+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ writeb(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ buf[i] = readb(this->IO_ADDR_R);
-+}
-+
-+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ if (buf[i] != readb(this->IO_ADDR_R))
-+ return i;
-+
-+ return 0;
-+}
-+
-+/* Appropriate chip should already be selected */
-+static int nand_block_bad(struct mtd_info *mtd, unsigned long page)
-+{
-+ struct nand_chip *this = mtd->priv;
-+
-+ this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
-+ if (this->read_byte(mtd) != 0xff)
-+ return 1;
-+
-+ return 0;
-+}
-+
- /*
- * Send command to NAND device
- */
- static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
- {
- register struct nand_chip *this = mtd->priv;
-- register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
-
- /* Begin command latch cycle */
-- this->hwcontrol (NAND_CTL_SETCLE);
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
- /*
- * Write out the command to the device.
- */
-- if (command != NAND_CMD_SEQIN)
-- writeb (command, NAND_IO_ADDR);
-- else {
-- if (mtd->oobblock == 256 && column >= 256) {
-- column -= 256;
-- writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
-- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-- } else if (mtd->oobblock == 512 && column >= 256) {
-- if (column < 512) {
-- column -= 256;
-- writeb (NAND_CMD_READ1, NAND_IO_ADDR);
-- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-- } else {
-- column -= 512;
-- writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
-- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-- }
-+ if (command == NAND_CMD_SEQIN) {
-+ int readcmd;
-+
-+ if (column >= mtd->oobblock) {
-+ /* OOB area */
-+ column -= mtd->oobblock;
-+ readcmd = NAND_CMD_READOOB;
-+ } else if (column < 256) {
-+ /* First 256 bytes --> READ0 */
-+ readcmd = NAND_CMD_READ0;
- } else {
-- writeb (NAND_CMD_READ0, NAND_IO_ADDR);
-- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-+ column -= 256;
-+ readcmd = NAND_CMD_READ1;
- }
-+ this->write_byte(mtd, readcmd);
- }
-+ this->write_byte(mtd, command);
-
- /* Set ALE and clear CLE to start address cycle */
-- this->hwcontrol (NAND_CTL_CLRCLE);
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-
- if (column != -1 || page_addr != -1) {
-- this->hwcontrol (NAND_CTL_SETALE);
-+ this->hwcontrol(mtd, NAND_CTL_SETALE);
-
- /* Serially input address */
- if (column != -1)
-- writeb (column, NAND_IO_ADDR);
-+ this->write_byte(mtd, column);
- if (page_addr != -1) {
-- writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
-- writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
-+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
- /* One more address cycle for higher density devices */
- if (mtd->size & 0x0c000000)
-- writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
- }
- /* Latch in address */
-- this->hwcontrol (NAND_CTL_CLRALE);
-+ this->hwcontrol(mtd, NAND_CTL_CLRALE);
- }
-
- /*
-@@ -244,10 +310,11 @@
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
-- this->hwcontrol (NAND_CTL_SETCLE);
-- writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
-- this->hwcontrol (NAND_CTL_CLRCLE);
-- while ( !(readb (this->IO_ADDR_R) & 0x40));
-+ udelay(this->chip_delay);
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+ this->write_byte(mtd, NAND_CMD_STATUS);
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+ while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
-@@ -263,7 +330,7 @@
- }
-
- /* wait until command is processed */
-- while (!this->dev_ready());
-+ while (!this->dev_ready(mtd));
- }
-
- /*
-@@ -288,17 +355,17 @@
- spin_unlock_bh (&this->chip_lock);
- return;
- }
--
-+#if 0 /* This was broken. And of dubious utility */
- if (this->state == FL_ERASING) {
- if (new_state != FL_ERASING) {
- this->state = new_state;
- spin_unlock_bh (&this->chip_lock);
-- nand_select (); /* select in any case */
-+ this->select_chip(mtd, 0); /* select in any case */
- this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
- return;
- }
- }
--
-+#endif
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
-@@ -334,17 +401,17 @@
- return 0;
- }
- if (this->dev_ready) {
-- if (this->dev_ready ())
-+ if (this->dev_ready(mtd))
- break;
- }
-- if (readb (this->IO_ADDR_R) & 0x40)
-+ if (this->read_byte(mtd) & 0x40)
- break;
-
- spin_unlock_bh (&this->chip_lock);
- yield ();
- spin_lock_bh (&this->chip_lock);
- }
-- status = (int) readb (this->IO_ADDR_R);
-+ status = (int) this->read_byte(mtd);
- spin_unlock_bh (&this->chip_lock);
-
- return status;
-@@ -352,14 +419,15 @@
-
- /*
- * Nand_page_program function is used for write and writev !
-+ * This function will always program a full page of data
-+ * If you call it with a non page aligned buffer, you're lost :)
- */
--static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this,
-- int page, int col, int last, u_char *oob_buf, int oobsel)
-+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel)
- {
- int i, status;
- u_char ecc_code[6], *oob_data;
-- int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
-- int *oob_config = oobconfigs[oobsel];
-+ int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-+ int *oob_config = oobsel->eccpos;
-
- /* pad oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf) {
-@@ -369,66 +437,42 @@
- } else
- oob_data = oob_buf;
-
-- /* software ecc 3 Bytes ECC / 256 Byte Data ? */
-- if (eccmode == NAND_ECC_SOFT) {
-- /* Read back previous written data, if col > 0 */
-- if (col) {
-- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
-- for (i = 0; i < col; i++)
-- this->data_poi[i] = readb (this->IO_ADDR_R);
-- }
-- if ((col < this->eccsize) && (last >= this->eccsize)) {
-- this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
-- for (i = 0; i < 3; i++)
-- oob_data[oob_config[i]] = ecc_code[i];
-- }
-- /* Calculate and write the second ECC if we have enough data */
-- if ((mtd->oobblock == 512) && (last == 512)) {
-- this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
-- for (i = 3; i < 6; i++)
-- oob_data[oob_config[i]] = ecc_code[i];
-- }
-- } else {
-- /* For hardware ECC skip ECC, if we have no full page write */
-- if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock))
-- eccmode = NAND_ECC_NONE;
-- }
--
-- /* Prepad for partial page programming !!! */
-- for (i = 0; i < col; i++)
-- this->data_poi[i] = 0xff;
--
-- /* Postpad for partial page programming !!! oob is already padded */
-- for (i = last; i < mtd->oobblock; i++)
-- this->data_poi[i] = 0xff;
--
- /* Send command to begin auto page programming */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
-
- /* Write out complete page of data, take care of eccmode */
-- switch (this->eccmode) {
-+ switch (eccmode) {
- /* No ecc and software ecc 3/256, write all */
- case NAND_ECC_NONE:
-+ printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
-+ this->write_buf(mtd, this->data_poi, mtd->oobblock);
-+ break;
- case NAND_ECC_SOFT:
-- for (i = 0; i < mtd->oobblock; i++)
-- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-+ this->calculate_ecc(mtd, &this->data_poi[0], &(ecc_code[0]));
-+ for (i = 0; i < 3; i++)
-+ oob_data[oob_config[i]] = ecc_code[i];
-+ /* Calculate and write the second ECC for 512 Byte page size */
-+ if (mtd->oobblock == 512) {
-+ this->calculate_ecc(mtd, &this->data_poi[256], &(ecc_code[3]));
-+ for (i = 3; i < 6; i++)
-+ oob_data[oob_config[i]] = ecc_code[i];
-+ }
-+ this->write_buf(mtd, this->data_poi, mtd->oobblock);
- break;
-
- /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */
- case NAND_ECC_HW3_256:
-- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write */
-- for (i = 0; i < mtd->eccsize; i++)
-- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */
-+ this->write_buf(mtd, this->data_poi, mtd->eccsize);
-
-- this->calculate_ecc (NULL, &(ecc_code[0]));
-+ this->calculate_ecc(mtd, NULL, &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
-
- if (mtd->oobblock == 512) {
-- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write*/
-- for (i = mtd->eccsize; i < mtd->oobblock; i++)
-- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-- this->calculate_ecc (NULL, &(ecc_code[3]));
-+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write*/
-+ this->write_buf(mtd, &this->data_poi[mtd->eccsize], mtd->oobblock - mtd->eccsize);
-+ this->calculate_ecc(mtd, NULL, &(ecc_code[3]));
- for (i = 3; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- }
-@@ -436,20 +480,18 @@
-
- /* Hardware ecc 3 byte / 512 byte data, write full page */
- case NAND_ECC_HW3_512:
-- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */
-- for (i = 0; i < mtd->oobblock; i++)
-- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-- this->calculate_ecc (NULL, &(ecc_code[0]));
-+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */
-+ this->write_buf(mtd, this->data_poi, mtd->oobblock);
-+ this->calculate_ecc(mtd, NULL, &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- break;
-
- /* Hardware ecc 6 byte / 512 byte data, write full page */
- case NAND_ECC_HW6_512:
-- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */
-- for (i = 0; i < mtd->oobblock; i++)
-- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-- this->calculate_ecc (NULL, &(ecc_code[0]));
-+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */
-+ this->write_buf(mtd, this->data_poi, mtd->oobblock);
-+ this->calculate_ecc(mtd, NULL, &(ecc_code[0]));
- for (i = 0; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- break;
-@@ -460,8 +502,7 @@
- }
-
- /* Write out OOB data */
-- for (i = 0; i < mtd->oobsize; i++)
-- writeb ( oob_data[i] , this->IO_ADDR_W);
-+ this->write_buf(mtd, oob_data, mtd->oobsize);
-
- /* Send command to actually program the data */
- this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-@@ -490,25 +531,21 @@
- */
-
- /* Send command to read back the page */
-- this->cmdfunc (mtd, NAND_CMD_READ0, col, page);
-+ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
- /* Loop through and verify the data */
-- for (i = col; i < last; i++) {
-- if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
-+ if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- return -EIO;
- }
-- }
-
- /* check, if we have a fs-supplied oob-buffer */
- if (oob_buf) {
-- for (i = 0; i < mtd->oobsize; i++) {
-- if (oob_data[i] != readb (this->IO_ADDR_R)) {
-+ if (this->verify_buf(mtd, oob_data, mtd->oobsize)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- return -EIO;
- }
-- }
- } else {
-- if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) {
-+ if (eccmode != NAND_ECC_NONE) {
- int ecc_bytes = 0;
-
- switch (this->eccmode) {
-@@ -518,8 +555,7 @@
- case NAND_ECC_HW6_512: ecc_bytes = 6; break;
- }
-
-- for (i = 0; i < mtd->oobsize; i++)
-- oob_data[i] = readb (this->IO_ADDR_R);
-+ this->read_buf(mtd, oob_data, mtd->oobsize);
-
- for (i = 0; i < ecc_bytes; i++) {
- if (oob_data[oob_config[i]] != ecc_code[i]) {
-@@ -531,6 +567,13 @@
- }
- }
- }
-+ /*
-+ * Terminate the read command. This is faster than sending a reset command or
-+ * applying a 20us delay before issuing the next programm sequence.
-+ * This is not a problem for all chips, but I have found a bunch of them.
-+ */
-+ this->select_chip(mtd, -1);
-+ this->select_chip(mtd, 0);
- #endif
- return 0;
- }
-@@ -540,7 +583,7 @@
- */
- 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, 0));
-+ return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
- }
-
-
-@@ -548,7 +591,7 @@
- * 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 * oob_buf, int oobsel)
-+ size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
- {
- int j, col, page, end, ecc;
- int erase_state = 0;
-@@ -557,9 +600,15 @@
- u_char *data_poi, *oob_data = oob_buf;
- u_char ecc_calc[6];
- u_char ecc_code[6];
-- int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
-+ int eccmode;
-+ int *oob_config;
-+
-+ // use chip default if zero
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
-
-- int *oob_config = oobconfigs[oobsel];
-+ eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-+ oob_config = oobsel->eccpos;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
-
-@@ -574,7 +623,7 @@
- nand_get_chip (this, mtd ,FL_READING, &erase_state);
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* First we calculate the starting page */
- page = from >> this->page_shift;
-@@ -596,7 +645,7 @@
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
-- while (!this->dev_ready());
-+ while (!this->dev_ready(mtd));
- }
-
- /*
-@@ -616,39 +665,40 @@
-
- j = 0;
- switch (eccmode) {
-- case NAND_ECC_NONE: /* No ECC, Read in a page */
-- while (j < end)
-- data_poi[j++] = readb (this->IO_ADDR_R);
-+ case NAND_ECC_NONE: { /* No ECC, Read in a page */
-+ static unsigned long lastwhinge = 0;
-+ if ((lastwhinge / HZ) != (jiffies / HZ)) {
-+ printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
-+ lastwhinge = jiffies;
-+ }
-+ this->read_buf(mtd, data_poi, end);
- break;
-+ }
-
- case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
-- while (j < end)
-- data_poi[j++] = readb (this->IO_ADDR_R);
-- this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
-+ this->read_buf(mtd, data_poi, end);
-+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]);
- if (mtd->oobblock == 512)
-- this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
-+ this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]);
- break;
-
- case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
-- this->enable_hwecc (NAND_ECC_READ);
-- while (j < ecc)
-- data_poi[j++] = readb (this->IO_ADDR_R);
-- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */
-+ this->enable_hwecc(mtd, NAND_ECC_READ);
-+ this->read_buf(mtd, data_poi, ecc);
-+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */
-
- if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
-- this->enable_hwecc (NAND_ECC_READ);
-- while (j < end)
-- data_poi[j++] = readb (this->IO_ADDR_R);
-- this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
-+ this->enable_hwecc(mtd, NAND_ECC_READ);
-+ this->read_buf(mtd, &data_poi[ecc], end-ecc);
-+ this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); /* read from hardware */
- }
- break;
-
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */
-- this->enable_hwecc (NAND_ECC_READ);
-- while (j < end)
-- data_poi[j++] = readb (this->IO_ADDR_R);
-- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */
-+ this->enable_hwecc(mtd, NAND_ECC_READ);
-+ this->read_buf(mtd, data_poi, end);
-+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */
- break;
-
- default:
-@@ -658,7 +708,7 @@
-
- /* read oobdata */
- for (j = 0; j < mtd->oobsize; j++)
-- oob_data[oob + j] = readb (this->IO_ADDR_R);
-+ oob_data[oob + j] = this->read_byte(mtd);
-
- /* Skip ECC, if not active */
- if (eccmode == NAND_ECC_NONE)
-@@ -669,7 +719,7 @@
- ecc_code[j] = oob_data[oob + oob_config[j]];
-
- /* correct data, if neccecary */
-- ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
-+ ecc_status = this->correct_data(mtd, &data_poi[0], &ecc_code[0], &ecc_calc[0]);
- /* check, if we have a fs supplied oob-buffer */
- if (oob_buf) {
- oob += mtd->oobsize;
-@@ -682,7 +732,7 @@
- }
-
- if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
-- ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
-+ ecc_status = this->correct_data(mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]);
- if (oob_buf) {
- *((int *)&oob_data[oob]) = ecc_status;
- oob += sizeof(int);
-@@ -705,7 +755,7 @@
- }
-
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
-@@ -753,7 +803,7 @@
- nand_get_chip (this, mtd , FL_READING, &erase_state);
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* Send the read command */
- this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
-@@ -761,13 +811,20 @@
- * Read the data, if we read more than one page
- * oob data, let the device transfer the data !
- */
-- for (i = 0; i < len; i++) {
-- buf[i] = readb (this->IO_ADDR_R);
-- if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
-+ i = 0;
-+ while (i < len) {
-+ int thislen = (mtd->oobsize - col) & (mtd->oobsize - 1);
-+ if (!thislen)
-+ thislen = mtd->oobsize;
-+ thislen = min_t(int, thislen, len);
-+ this->read_buf(mtd, &buf[i], thislen);
-+ i += thislen;
-+ col += thislen;
-+ /* Delay between pages */
- udelay (this->chip_delay);
- }
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
-@@ -780,45 +837,54 @@
- return 0;
- }
-
-+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
-+
- /*
- * Use NAND write ECC
- */
- 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, 0));
-+ return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 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 * eccbuf, int oobsel)
-+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
- {
-- int i, page, col, cnt, ret = 0, oob = 0, written = 0;
-+ int page, ret = 0, oob = 0, written = 0;
- struct nand_chip *this = mtd->priv;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
- /* Do not allow write past end of device */
- if ((to + len) > mtd->size) {
-- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
-+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
-+ return -EINVAL;
-+ }
-+
-+ /* reject writes, which are not page aligned */
-+ if (NOTALIGNED (to) || NOTALIGNED(len)) {
-+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
- return -EINVAL;
- }
-
-+ // if oobsel is NULL, use chip defaults
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
-+
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
-
-- /* Get the starting column */
-- col = to & (mtd->oobblock - 1);
--
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-- if (!(readb (this->IO_ADDR_R) & 0x80)) {
-+ if (!(this->read_byte(mtd) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
-@@ -826,42 +892,27 @@
-
- /* Loop until all data is written */
- while (written < len) {
-- /*
-- * Check, if we have a full page write, then we can
-- * use the given buffer, else we have to copy
-- */
-- if (!col && (len - written) >= mtd->oobblock) {
-+ int cnt = mtd->oobblock;
- this->data_poi = (u_char*) &buf[written];
-- cnt = mtd->oobblock;
-- } else {
-- cnt = 0;
-- for (i = col; i < len && i < mtd->oobblock; i++) {
-- this->data_buf[i] = buf[written + i];
-- cnt++;
-- }
-- this->data_poi = this->data_buf;
-- }
-- /* We use the same function for write and writev !) */
-+ /* We use the same function for write and writev */
- if (eccbuf) {
-- ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel);
-+ ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
- oob += mtd->oobsize;
- } else
-- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
-+ ret = nand_write_page (mtd, this, page, NULL, oobsel);
-
- if (ret)
- goto out;
-
- /* Update written bytes count */
- written += cnt;
-- /* Next write is aligned */
-- col = 0;
- /* Increment page address */
- page++;
- }
-
- out:
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
-@@ -873,13 +924,21 @@
- return ret;
- }
-
-+static u_char ffchars[] = {
-+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-+};
-+
- /*
- * 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 i, column, page, status, ret = 0;
-+ int column, page, status, ret = 0;
- struct nand_chip *this = mtd->priv;
-+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-+ int i;
-+#endif
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
-@@ -902,27 +961,31 @@
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-+
-+ /* Reset the chip. Some chips (like the Toshiba TC5832DC found
-+ in one of my DiskOnChip 2000 test units) will clear the whole
-+ data page too if we don't do this. I have no clue why, but
-+ I seem to have 'fixed' it in the doc2000 driver in
-+ August 1999. dwmw2. */
-+ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-- if (!(readb (this->IO_ADDR_R) & 0x80)) {
-+ if (!(this->read_byte(mtd) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
- }
--
- /* Write out desired data */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
-+
- /* prepad 0xff for partial programming */
-- for (i = 0; i < column; i++)
-- writeb (0xff, this->IO_ADDR_W);
-+ this->write_buf(mtd, ffchars, column);
- /* write data */
-- for (i = 0; i < len; i++)
-- writeb (buf[i], this->IO_ADDR_W);
-+ this->write_buf(mtd, buf, len);
- /* postpad 0xff for partial programming */
-- for (i = len + column; i < mtd->oobsize; i++)
-- writeb (0xff, this->IO_ADDR_W);
-+ this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
-
- /* Send command to program the OOB data */
- this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-@@ -944,7 +1007,7 @@
-
- /* Loop through and verify the data */
- for (i = 0; i < len; i++) {
-- if (buf[i] != readb (this->IO_ADDR_R)) {
-+ if (buf[i] != this->read_byte(mtd)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
- ret = -EIO;
- goto out;
-@@ -954,7 +1017,7 @@
-
- out:
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
-@@ -976,9 +1039,9 @@
- }
-
- static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count,
-- loff_t to, size_t * retlen, u_char *eccbuf, int oobsel)
-+ loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
- {
-- int i, page, col, cnt, len, total_len, ret = 0, written = 0;
-+ int i, page, len, total_len, ret = 0, written = 0;
- struct nand_chip *this = mtd->priv;
-
- /* Calculate total length of data */
-@@ -995,39 +1058,42 @@
- return -EINVAL;
- }
-
-+ /* reject writes, which are not page aligned */
-+ if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
-+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
-+ return -EINVAL;
-+ }
-+
-+ // if oobsel is NULL, use chip defaults
-+ if (oobsel == NULL)
-+ oobsel = &mtd->oobinfo;
-+
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
-
-- /* Get the starting column */
-- col = to & (mtd->oobblock - 1);
--
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-- if (!(readb (this->IO_ADDR_R) & 0x80)) {
-+ if (!(this->read_byte(mtd) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
- }
-
- /* Loop until all iovecs' data has been written */
-- cnt = col;
- len = 0;
--
- while (count) {
- /*
-- * Check, if we write from offset 0 and if the tuple
-- * gives us not enough data for a full page write. Then we
-- * can use the iov direct, else we have to copy into
-- * data_buf.
-+ * Check, if the tuple gives us not enough data for a
-+ * full page write. Then we can use the iov direct,
-+ * else we have to copy into data_buf.
- */
-- if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) {
-- cnt = mtd->oobblock;
-+ if ((vecs->iov_len - len) >= mtd->oobblock) {
- this->data_poi = (u_char *) vecs->iov_base;
- this->data_poi += len;
- len += mtd->oobblock;
-@@ -1042,6 +1108,7 @@
- * Read data out of each tuple until we have a full page
- * to write or we've read all the tuples.
- */
-+ int cnt = 0;
- while ((cnt < mtd->oobblock) && count) {
- if (vecs->iov_base != NULL && vecs->iov_len) {
- this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
-@@ -1057,15 +1124,12 @@
- }
-
- /* We use the same function for write and writev !) */
-- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
-+ ret = nand_write_page (mtd, this, page, NULL, oobsel);
- if (ret)
- goto out;
-
- /* Update written bytes count */
-- written += (cnt - col);
--
-- /* Reset written byte counter and column */
-- col = cnt = 0;
-+ written += mtd->oobblock;;
-
- /* Increment page address */
- page++;
-@@ -1073,7 +1137,7 @@
-
- out:
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
-@@ -1125,11 +1189,11 @@
- pages_per_block = mtd->erasesize / mtd->oobblock;
-
- /* Select the NAND device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-- if (!(readb (this->IO_ADDR_R) & 0x80)) {
-+ if (!(this->read_byte(mtd) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
-@@ -1142,8 +1206,7 @@
-
- while (len) {
- /* Check if we have a bad block, we do not erase bad blocks ! */
-- this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
-- if (readb (this->IO_ADDR_R) != 0xff) {
-+ if (this->block_bad(mtd, page)) {
- printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
-@@ -1179,7 +1242,7 @@
- if (this->state == FL_ERASING || this->state == FL_READY) {
- /* Select the NAND device again, if we were interrupted */
- this->state = FL_ERASING;
-- nand_select ();
-+ this->select_chip(mtd, 0);
- continue;
- } else {
- set_current_state (TASK_UNINTERRUPTIBLE);
-@@ -1194,7 +1257,7 @@
-
- erase_exit:
- /* De-select the NAND device */
-- nand_deselect ();
-+ this->select_chip(mtd, -1);
- spin_unlock_bh (&this->chip_lock);
-
- ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
-@@ -1205,6 +1268,7 @@
- /* The device is ready */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
-+ wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- /* Return more or less happy */
-@@ -1259,7 +1323,7 @@
- /*
- * Scan for the NAND device
- */
--int nand_scan (struct mtd_info *mtd)
-+int nand_scan (struct mtd_info *mtd, int maxchips)
- {
- int i, nand_maf_id, nand_dev_id;
- struct nand_chip *this = mtd->priv;
-@@ -1276,23 +1340,38 @@
- if (this->waitfunc == NULL)
- this->waitfunc = nand_wait;
-
-+ if (!this->block_bad)
-+ this->block_bad = nand_block_bad;
-+ if (!this->select_chip)
-+ this->select_chip = nand_select_chip;
-+ if (!this->write_byte)
-+ this->write_byte = nand_write_byte;
-+ if (!this->read_byte)
-+ this->read_byte = nand_read_byte;
-+ if (!this->write_buf)
-+ this->write_buf = nand_write_buf;
-+ if (!this->read_buf)
-+ this->read_buf = nand_read_buf;
-+ if (!this->verify_buf)
-+ this->verify_buf = nand_verify_buf;
-+
- /* Select the device */
-- nand_select ();
-+ this->select_chip(mtd, 0);
-
- /* Send the command for reading device ID */
- this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-
- /* Read manufacturer and device IDs */
-- nand_maf_id = readb (this->IO_ADDR_R);
-- nand_dev_id = readb (this->IO_ADDR_R);
-+ nand_maf_id = this->read_byte(mtd);
-+ nand_dev_id = this->read_byte(mtd);
-
- /* Print and store flash device information */
- for (i = 0; nand_flash_ids[i].name != NULL; i++) {
- if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
- mtd->name = nand_flash_ids[i].name;
- mtd->erasesize = nand_flash_ids[i].erasesize;
-- mtd->size = (1 << nand_flash_ids[i].chipshift);
- mtd->eccsize = 256;
-+ this->chipshift = nand_flash_ids[i].chipshift;
- if (nand_flash_ids[i].page256) {
- mtd->oobblock = 256;
- mtd->oobsize = 8;
-@@ -1307,13 +1386,34 @@
- if (nand_manuf_ids[i].id == nand_maf_id)
- break;
- }
-- printk (KERN_INFO "NAND device: Manufacture ID:"
-+ printk (KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[i].name , mtd->name);
- break;
- }
- }
-
-+ if (!mtd->name) {
-+ printk (KERN_WARNING "No NAND device found!!!\n");
-+ return 1;
-+ }
-+
-+ for (i=1; i < maxchips; i++) {
-+ this->select_chip(mtd, i);
-+
-+ /* Send the command for reading device ID */
-+ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-+
-+ /* Read manufacturer and device IDs */
-+ if (nand_maf_id != this->read_byte(mtd) ||
-+ nand_dev_id != this->read_byte(mtd))
-+ break;
-+ }
-+ if (i > 1)
-+ printk(KERN_INFO "%d NAND chips detected\n", i);
-+
-+ mtd->size = (1 << this->chipshift) /* * i when we fix the rest of the code */;
-+
- /*
- * check ECC mode, default to software
- * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
-@@ -1324,6 +1424,7 @@
- switch (this->eccmode) {
-
- case NAND_ECC_HW3_512:
-+ case NAND_ECC_HW6_512:
- if (mtd->oobblock == 256) {
- printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
- this->eccmode = NAND_ECC_SOFT;
-@@ -1340,6 +1441,7 @@
- BUG();
-
- case NAND_ECC_NONE:
-+ printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
- this->eccmode = NAND_ECC_NONE;
- break;
-
-@@ -1359,18 +1461,11 @@
- spin_lock_init (&this->chip_lock);
-
- /* De-select the device */
-- nand_deselect ();
--
-- /* Print warning message for no device */
-- if (!mtd->size) {
-- printk (KERN_WARNING "No NAND device found!!!\n");
-- return 1;
-- }
-+ this->select_chip(mtd, -1);
-
- /* Fill in remaining MTD driver data */
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
-- mtd->module = THIS_MODULE;
- mtd->ecctype = MTD_ECC_SW;
- mtd->erase = nand_erase;
- mtd->point = NULL;
-@@ -1389,6 +1484,7 @@
- mtd->unlock = NULL;
- mtd->suspend = NULL;
- mtd->resume = NULL;
-+ mtd->owner = THIS_MODULE;
-
- /* Return happy */
- return 0;
-@@ -1397,5 +1493,5 @@
- EXPORT_SYMBOL (nand_scan);
-
- MODULE_LICENSE ("GPL");
--MODULE_AUTHOR ("Steven J. Hill <sjhill@cotw.com>, Thomas Gleixner <tglx@linutronix.de>");
-+MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
- MODULE_DESCRIPTION ("Generic NAND flash driver code");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand_ecc.c linux/drivers/mtd/nand/nand_ecc.c
---- linux-mips-2.4.27/drivers/mtd/nand/nand_ecc.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/nand_ecc.c 2004-11-19 10:25:12.011182768 +0100
-@@ -1,10 +1,10 @@
- /*
- * drivers/mtd/nand_ecc.c
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * Toshiba America Electronics Components, Inc.
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
-@@ -17,6 +17,7 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
-+#include <linux/mtd/nand_ecc.h>
-
- /*
- * Pre-calculated 256-way 1 byte column parity
-@@ -84,7 +85,7 @@
- /*
- * Calculate 3 byte ECC code for 256 byte block
- */
--void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
-+void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
- {
- u_char idx, reg1, reg2, reg3;
- int j;
-@@ -119,7 +120,7 @@
- /*
- * Detect and correct a 1 bit error for 256 byte block
- */
--int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
-+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
- {
- u_char a, b, c, d1, d2, d3, add, bit, i;
-
-@@ -209,5 +210,5 @@
- EXPORT_SYMBOL(nand_correct_data);
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
-+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
- MODULE_DESCRIPTION("Generic NAND ECC support");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand_ids.c linux/drivers/mtd/nand/nand_ids.c
---- linux-mips-2.4.27/drivers/mtd/nand/nand_ids.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/nand_ids.c 2004-11-19 10:25:12.013182464 +0100
-@@ -4,7 +4,7 @@
- * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -18,21 +18,21 @@
- * Chip ID list
- */
- struct nand_flash_dev nand_flash_ids[] = {
-- {"NAND 1MB 5V", 0x6e, 20, 0x1000, 1}, // 1Mb 5V
-- {"NAND 2MB 5V", 0x64, 21, 0x1000, 1}, // 2Mb 5V
-- {"NAND 4MB 5V", 0x6b, 22, 0x2000, 0}, // 4Mb 5V
-- {"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1}, // 1Mb 3.3V
-- {"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1}, // 1Mb 3.3V
-- {"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1}, // 2Mb 3.3V
-- {"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0}, // 4Mb 3.3V
-- {"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0}, // 8Mb 3.3V
-- {"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0}, // 8Mb 3.3V
-- {"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V
-- {"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V
-- {"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V
-- {"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V
-+ {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1},
-+ {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1},
-+ {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0},
-+ {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1},
-+ {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1},
-+ {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1},
-+ {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0},
-+ {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0},
-+ {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0},
-+ {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0},
-+ {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0},
-+ {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0},
-+ {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0},
-+ {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0},
-+ {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0},
- {NULL,}
- };
-
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/spia.c linux/drivers/mtd/nand/spia.c
---- linux-mips-2.4.27/drivers/mtd/nand/spia.c 2003-02-26 01:53:50.000000000 +0100
-+++ linux/drivers/mtd/nand/spia.c 2004-11-19 10:25:12.014182312 +0100
-@@ -1,14 +1,14 @@
- /*
- * drivers/mtd/nand/spia.c
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
- *
- * 10-29-2001 TG change to support hardwarespecific access
- * to controllines (due to change in nand.c)
- * page_cache added
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -20,6 +20,8 @@
- * a 64Mibit (8MiB x 8 bits) NAND flash device.
- */
-
-+#include <linux/kernel.h>
-+#include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
-@@ -35,14 +37,14 @@
- /*
- * Values specific to the SPIA board (used with EP7212 processor)
- */
--#define SPIA_IO_ADDR = 0xd0000000 /* Start of EP7212 IO address space */
--#define SPIA_FIO_ADDR = 0xf0000000 /* Address where flash is mapped */
--#define SPIA_PEDR = 0x0080 /*
-+#define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */
-+#define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */
-+#define SPIA_PEDR 0x0080 /*
- * IO offset to Port E data register
- * where the CLE, ALE and NCE pins
- * are wired to.
- */
--#define SPIA_PEDDR = 0x00c0 /*
-+#define SPIA_PEDDR 0x00c0 /*
- * IO offset to Port E data direction
- * register so we can control the IO
- * lines.
-@@ -62,21 +64,20 @@
- MODULE_PARM(spia_pedr, "i");
- MODULE_PARM(spia_peddr, "i");
-
--__setup("spia_io_base=",spia_io_base);
--__setup("spia_fio_base=",spia_fio_base);
--__setup("spia_pedr=",spia_pedr);
--__setup("spia_peddr=",spia_peddr);
--
- /*
- * Define partitions for flash device
- */
- const static struct mtd_partition partition_info[] = {
-- { name: "SPIA flash partition 1",
-- offset: 0,
-- size: 2*1024*1024 },
-- { name: "SPIA flash partition 2",
-- offset: 2*1024*1024,
-- size: 6*1024*1024 }
-+ {
-+ .name = "SPIA flash partition 1",
-+ .offset = 0,
-+ .size = 2*1024*1024
-+ },
-+ {
-+ .name = "SPIA flash partition 2",
-+ .offset = 2*1024*1024,
-+ .size = 6*1024*1024
-+ }
- };
- #define NUM_PARTITIONS 2
-
-@@ -84,7 +85,7 @@
- /*
- * hardware specific access to control-lines
- */
--void spia_hwcontrol(int cmd){
-+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
-
- switch(cmd){
-
-@@ -139,7 +140,7 @@
- this->chip_delay = 15;
-
- /* Scan to find existence of the device */
-- if (nand_scan (spia_mtd)) {
-+ if (nand_scan (spia_mtd, 1)) {
- kfree (spia_mtd);
- return -ENXIO;
- }
-@@ -152,16 +153,6 @@
- return -ENOMEM;
- }
-
-- /* Allocate memory for internal data buffer */
-- this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
-- if (!this->data_cache) {
-- printk ("Unable to allocate NAND data cache for SPIA.\n");
-- kfree (this->data_buf);
-- kfree (spia_mtd);
-- return = -ENOMEM;
-- }
-- this->cache_page = -1;
--
- /* Register the partitions */
- add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
-
-@@ -183,7 +174,6 @@
-
- /* Free internal data buffer */
- kfree (this->data_buf);
-- kfree (this->page_cache);
-
- /* Free the MTD device structure */
- kfree (spia_mtd);
-@@ -192,5 +182,5 @@
- #endif
-
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
-+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com");
- MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on SPIA board");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/toto.c linux/drivers/mtd/nand/toto.c
---- linux-mips-2.4.27/drivers/mtd/nand/toto.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/nand/toto.c 2004-11-19 10:25:12.016182008 +0100
-@@ -0,0 +1,221 @@
-+/*
-+ * drivers/mtd/nand/toto.c
-+ *
-+ * Copyright (c) 2003 Texas Instruments
-+ *
-+ * Derived from drivers/mtd/autcpu12.c
-+ *
-+ * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
-+ *
-+ * 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.
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device found on the
-+ * TI fido board. It supports 32MiB and 64MiB cards
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/arch/hardware.h>
-+#include <asm/sizes.h>
-+#include <asm/arch/toto.h>
-+#include <asm/arch-omap1510/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+/*
-+ * MTD structure for TOTO board
-+ */
-+static struct mtd_info *toto_mtd = NULL;
-+
-+static int toto_io_base = OMAP_FLASH_1_BASE;
-+
-+#define CONFIG_NAND_WORKAROUND 1
-+
-+#define NAND_NCE 0x4000
-+#define NAND_CLE 0x1000
-+#define NAND_ALE 0x0002
-+#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE)
-+
-+#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0)
-+#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE)
-+#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */
-+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2)
-+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0)
-+#else
-+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0)
-+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE)
-+#endif
-+#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
-+#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
-+
-+/*
-+ * Define partitions for flash devices
-+ */
-+
-+static struct mtd_partition partition_info64M[] = {
-+ { .name = "toto kernel partition 1",
-+ .offset = 0,
-+ .size = 2 * SZ_1M },
-+ { .name = "toto file sys partition 2",
-+ .offset = 2 * SZ_1M,
-+ .size = 14 * SZ_1M },
-+ { .name = "toto user partition 3",
-+ .offset = 16 * SZ_1M,
-+ .size = 16 * SZ_1M },
-+ { .name = "toto devboard extra partition 4",
-+ .offset = 32 * SZ_1M,
-+ .size = 32 * SZ_1M },
-+};
-+
-+static struct mtd_partition partition_info32M[] = {
-+ { .name = "toto kernel partition 1",
-+ .offset = 0,
-+ .size = 2 * SZ_1M },
-+ { .name = "toto file sys partition 2",
-+ .offset = 2 * SZ_1M,
-+ .size = 14 * SZ_1M },
-+ { .name = "toto user partition 3",
-+ .offset = 16 * SZ_1M,
-+ .size = 16 * SZ_1M },
-+};
-+
-+#define NUM_PARTITIONS32M 3
-+#define NUM_PARTITIONS64M 4
-+/*
-+ * hardware specific access to control-lines
-+*/
-+
-+static void toto_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+
-+ udelay(1); /* hopefully enough time for tc make proceding write to clear */
-+ switch(cmd){
-+
-+ case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
-+ case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
-+
-+ case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
-+ case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
-+
-+ case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
-+ case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
-+ }
-+ udelay(1); /* allow time to ensure gpio state to over take memory write */
-+}
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init toto_init (void)
-+{
-+ struct nand_chip *this;
-+ int err = 0;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ toto_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!toto_mtd) {
-+ printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&toto_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) toto_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ toto_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = toto_io_base;
-+ this->IO_ADDR_W = toto_io_base;
-+ this->hwcontrol = toto_hwcontrol;
-+ this->dev_ready = NULL;
-+ /* 25 us command delay time */
-+ this->chip_delay = 30;
-+ this->eccmode = NAND_ECC_SOFT;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (toto_mtd, 1)) {
-+ err = -ENXIO;
-+ goto out_mtd;
-+ }
-+
-+ /* Allocate memory for internal data buffer */
-+ this->data_buf = kmalloc (sizeof(u_char) * (toto_mtd->oobblock + toto_mtd->oobsize), GFP_KERNEL);
-+ if (!this->data_buf) {
-+ printk (KERN_WARNING "Unable to allocate NAND data buffer for toto.\n");
-+ err = -ENOMEM;
-+ goto out_mtd;
-+ }
-+
-+ /* Register the partitions */
-+ switch(toto_mtd->size){
-+ case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
-+ case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
-+ default: {
-+ printk (KERN_WARNING "Unsupported Nand device\n");
-+ err = -ENXIO;
-+ goto out_buf;
-+ }
-+ }
-+
-+ gpioreserve(NAND_MASK); /* claim our gpios */
-+ archflashwp(0,0); /* open up flash for writing */
-+
-+ goto out;
-+
-+out_buf:
-+ kfree (this->data_buf);
-+out_mtd:
-+ kfree (toto_mtd);
-+out:
-+ return err;
-+}
-+
-+module_init(toto_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit toto_cleanup (void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) &toto_mtd[1];
-+
-+ /* Unregister partitions */
-+ del_mtd_partitions(toto_mtd);
-+
-+ /* Unregister the device */
-+ del_mtd_device (toto_mtd);
-+
-+ /* Free internal data buffers */
-+ kfree (this->data_buf);
-+
-+ /* Free the MTD device structure */
-+ kfree (toto_mtd);
-+
-+ /* stop flash writes */
-+ archflashwp(0,1);
-+
-+ /* release gpios to system */
-+ gpiorelease(NAND_MASK);
-+}
-+module_exit(toto_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>");
-+MODULE_DESCRIPTION("Glue layer for NAND flash on toto board");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/tx4925ndfmc.c linux/drivers/mtd/nand/tx4925ndfmc.c
---- linux-mips-2.4.27/drivers/mtd/nand/tx4925ndfmc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/nand/tx4925ndfmc.c 2004-11-19 10:25:12.017181856 +0100
-@@ -0,0 +1,442 @@
-+/*
-+ * drivers/mtd/tx4925ndfmc.c
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device found on the
-+ * Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports
-+ * 16MiB, 32MiB and 64MiB cards.
-+ *
-+ * Author: MontaVista Software, Inc. source@mvista.com
-+ *
-+ * Derived from drivers/mtd/autcpu12.c
-+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
-+ *
-+ * $Id$
-+ *
-+ * Copyright (C) 2001 Toshiba Corporation
-+ *
-+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
-+ * the terms of the GNU General Public License version 2. This program
-+ * is licensed "as is" without any warranty of any kind, whether express
-+ * or implied.
-+ *
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+#include <asm/tx4925/tx4925_nand.h>
-+
-+extern struct nand_oobinfo jffs2_oobinfo;
-+
-+/*
-+ * MTD structure for RBTX4925 board
-+ */
-+static struct mtd_info *tx4925ndfmc_mtd = NULL;
-+
-+/*
-+ * Module stuff
-+ */
-+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-+#define tx4925ndfmc_init init_module
-+#define tx4925ndfmc_cleanup cleanup_module
-+#endif
-+
-+/*
-+ * Define partitions for flash devices
-+ */
-+
-+static struct mtd_partition partition_info16k[] = {
-+ { .name = "RBTX4925 flash partition 1",
-+ .offset = 0,
-+ .size = 8 * 0x00100000 },
-+ { .name = "RBTX4925 flash partition 2",
-+ .offset = 8 * 0x00100000,
-+ .size = 8 * 0x00100000 },
-+};
-+
-+static struct mtd_partition partition_info32k[] = {
-+ { .name = "RBTX4925 flash partition 1",
-+ .offset = 0,
-+ .size = 8 * 0x00100000 },
-+ { .name = "RBTX4925 flash partition 2",
-+ .offset = 8 * 0x00100000,
-+ .size = 24 * 0x00100000 },
-+};
-+
-+static struct mtd_partition partition_info64k[] = {
-+ { .name = "User FS",
-+ .offset = 0,
-+ .size = 16 * 0x00100000 },
-+ { .name = "RBTX4925 flash partition 2",
-+ .offset = 16 * 0x00100000,
-+ .size = 48 * 0x00100000},
-+};
-+
-+static struct mtd_partition partition_info128k[] = {
-+ { .name = "Skip bad section",
-+ .offset = 0,
-+ .size = 16 * 0x00100000 },
-+ { .name = "User FS",
-+ .offset = 16 * 0x00100000,
-+ .size = 112 * 0x00100000 },
-+};
-+#define NUM_PARTITIONS16K 2
-+#define NUM_PARTITIONS32K 2
-+#define NUM_PARTITIONS64K 2
-+#define NUM_PARTITIONS128K 2
-+
-+/*
-+ * hardware specific access to control-lines
-+*/
-+static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+
-+ switch(cmd){
-+
-+ case NAND_CTL_SETCLE:
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_SETALE:
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE;
-+ break;
-+ case NAND_CTL_CLRALE:
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE;
-+ break;
-+ case NAND_CTL_SETNCE:
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_SETWP:
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE;
-+ break;
-+ case NAND_CTL_CLRWP:
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE;
-+ break;
-+ }
-+}
-+
-+/*
-+* read device ready pin
-+*/
-+static int tx4925ndfmc_device_ready(struct mtd_info *mtd)
-+{
-+ int ready;
-+ ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1;
-+ return ready;
-+}
-+void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+ /* reset first */
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK;
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB;
-+}
-+static void tx4925ndfmc_disable_ecc(void)
-+{
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+}
-+static void tx4925ndfmc_enable_read_ecc(void)
-+{
-+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ;
-+}
-+void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){
-+ int i;
-+ u_char *ecc = ecc_code;
-+ tx4925ndfmc_enable_read_ecc();
-+ for (i = 0;i < 6;i++,ecc++)
-+ *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr));
-+ tx4925ndfmc_disable_ecc();
-+}
-+void tx4925ndfmc_device_setup(void)
-+{
-+
-+ *(unsigned char *)0xbb005000 &= ~0x08;
-+
-+ /* reset NDFMC */
-+ tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST;
-+ while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST);
-+
-+ /* setup BusSeparete, Hold Time, Strobe Pulse Width */
-+ tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0;
-+ tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW;
-+}
-+static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ return tx4925_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ tx4925_write_nfmc(byte, this->IO_ADDR_W);
-+}
-+
-+static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ tx4925_write_nfmc(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ buf[i] = tx4925_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R))
-+ return i;
-+
-+ return 0;
-+}
-+
-+/*
-+ * Send command to NAND device
-+ */
-+static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+ register struct nand_chip *this = mtd->priv;
-+
-+ /* Begin command latch cycle */
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+ /*
-+ * Write out the command to the device.
-+ */
-+ if (command == NAND_CMD_SEQIN) {
-+ int readcmd;
-+
-+ if (column >= mtd->oobblock) {
-+ /* OOB area */
-+ column -= mtd->oobblock;
-+ readcmd = NAND_CMD_READOOB;
-+ } else if (column < 256) {
-+ /* First 256 bytes --> READ0 */
-+ readcmd = NAND_CMD_READ0;
-+ } else {
-+ column -= 256;
-+ readcmd = NAND_CMD_READ1;
-+ }
-+ this->write_byte(mtd, readcmd);
-+ }
-+ this->write_byte(mtd, command);
-+
-+ /* Set ALE and clear CLE to start address cycle */
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+ if (column != -1 || page_addr != -1) {
-+ this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+ /* Serially input address */
-+ if (column != -1)
-+ this->write_byte(mtd, column);
-+ if (page_addr != -1) {
-+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+ /* One more address cycle for higher density devices */
-+ if (mtd->size & 0x0c000000)
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
-+ }
-+ /* Latch in address */
-+ this->hwcontrol(mtd, NAND_CTL_CLRALE);
-+ }
-+
-+ /*
-+ * program and erase have their own busy handlers
-+ * status and sequential in needs no delay
-+ */
-+ switch (command) {
-+
-+ case NAND_CMD_PAGEPROG:
-+ /* Turn off WE */
-+ this->hwcontrol (mtd, NAND_CTL_CLRWP);
-+ return;
-+
-+ case NAND_CMD_SEQIN:
-+ /* Turn on WE */
-+ this->hwcontrol (mtd, NAND_CTL_SETWP);
-+ return;
-+
-+ case NAND_CMD_ERASE1:
-+ case NAND_CMD_ERASE2:
-+ case NAND_CMD_STATUS:
-+ return;
-+
-+ case NAND_CMD_RESET:
-+ if (this->dev_ready)
-+ break;
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+ this->write_byte(mtd, NAND_CMD_STATUS);
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+ while ( !(this->read_byte(mtd) & 0x40));
-+ return;
-+
-+ /* This applies to read commands */
-+ default:
-+ /*
-+ * If we don't have access to the busy pin, we apply the given
-+ * command delay
-+ */
-+ if (!this->dev_ready) {
-+ udelay (this->chip_delay);
-+ return;
-+ }
-+ }
-+
-+ /* wait until command is processed */
-+ while (!this->dev_ready(mtd));
-+}
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio
-+n **pparts, char *);
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+int __init tx4925ndfmc_init (void)
-+{
-+ struct nand_chip *this;
-+ int err = 0;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!tx4925ndfmc_mtd) {
-+ printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n");
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ tx4925ndfmc_device_setup();
-+
-+ /* io is indirect via a register so don't need to ioremap address */
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ tx4925ndfmc_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = (unsigned long)&(tx4925_ndfmcptr->dtr);
-+ this->IO_ADDR_W = (unsigned long)&(tx4925_ndfmcptr->dtr);
-+ this->hwcontrol = tx4925ndfmc_hwcontrol;
-+ this->enable_hwecc = tx4925ndfmc_enable_hwecc;
-+ this->calculate_ecc = tx4925ndfmc_readecc;
-+ this->correct_data = nand_correct_data;
-+ this->eccmode = NAND_ECC_HW6_512;
-+ this->dev_ready = tx4925ndfmc_device_ready;
-+ /* 20 us command delay time */
-+ this->chip_delay = 20;
-+ this->read_byte = tx4925ndfmc_nand_read_byte;
-+ this->write_byte = tx4925ndfmc_nand_write_byte;
-+ this->cmdfunc = tx4925ndfmc_nand_command;
-+ this->write_buf = tx4925ndfmc_nand_write_buf;
-+ this->read_buf = tx4925ndfmc_nand_read_buf;
-+ this->verify_buf = tx4925ndfmc_nand_verify_buf;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (tx4925ndfmc_mtd, 1)) {
-+ err = -ENXIO;
-+ goto out_ior;
-+ }
-+
-+ /* Allocate memory for internal data buffer */
-+ this->data_buf = kmalloc (sizeof(u_char) * (tx4925ndfmc_mtd->oobblock + tx4925ndfmc_mtd->oobsize), GFP_KERNEL);
-+ if (!this->data_buf) {
-+ printk ("Unable to allocate NAND data buffer for RBTX4925.\n");
-+ err = -ENOMEM;
-+ goto out_ior;
-+ }
-+
-+ /* Register the partitions */
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ {
-+ int mtd_parts_nb = 0;
-+ struct mtd_partition *mtd_parts = 0;
-+ mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc");
-+ if (mtd_parts_nb > 0)
-+ add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb);
-+ else
-+ add_mtd_device(tx4925ndfmc_mtd);
-+ }
-+#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */
-+ switch(tx4925ndfmc_mtd->size){
-+ case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break;
-+ case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break;
-+ case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break;
-+ case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break;
-+ default: {
-+ printk ("Unsupported SmartMedia device\n");
-+ err = -ENXIO;
-+ goto out_buf;
-+ }
-+ }
-+#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
-+ goto out;
-+
-+out_buf:
-+ kfree (this->data_buf);
-+out_ior:
-+out:
-+ return err;
-+}
-+
-+module_init(tx4925ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit tx4925ndfmc_cleanup (void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) &tx4925ndfmc_mtd[1];
-+
-+ /* Unregister partitions */
-+ del_mtd_partitions(tx4925ndfmc_mtd);
-+
-+ /* Unregister the device */
-+ del_mtd_device (tx4925ndfmc_mtd);
-+
-+ /* Free internal data buffers */
-+ kfree (this->data_buf);
-+
-+ /* Free the MTD device structure */
-+ kfree (tx4925ndfmc_mtd);
-+}
-+module_exit(tx4925ndfmc_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/tx4938ndfmc.c linux/drivers/mtd/nand/tx4938ndfmc.c
---- linux-mips-2.4.27/drivers/mtd/nand/tx4938ndfmc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/mtd/nand/tx4938ndfmc.c 2004-11-19 10:25:12.019181552 +0100
-@@ -0,0 +1,422 @@
-+/*
-+ * drivers/mtd/nand/tx4938ndfmc.c
-+ *
-+ * Overview:
-+ * This is a device driver for the NAND flash device connected to
-+ * TX4938 internal NAND Memory Controller.
-+ * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit.
-+ *
-+ * Author: source@mvista.com
-+ *
-+ * Based on spia.c by Steven J. Hill
-+ *
-+ * $Id$
-+ *
-+ * Copyright (C) 2000-2001 Toshiba Corporation
-+ *
-+ * 2003 (c) MontaVista Software, Inc. This file is licensed under the
-+ * terms of the GNU General Public License version 2. This program is
-+ * licensed "as is" without any warranty of any kind, whether express
-+ * or implied.
-+ */
-+#include <linux/config.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/bootinfo.h>
-+#include <linux/delay.h>
-+#include <asm/tx4938/rbtx4938.h>
-+
-+extern struct nand_oobinfo jffs2_oobinfo;
-+
-+/*
-+ * MTD structure for TX4938 NDFMC
-+ */
-+static struct mtd_info *tx4938ndfmc_mtd;
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+#define flush_wb() (void)tx4938_ndfmcptr->mcr;
-+
-+#define NUM_PARTITIONS 3
-+#define NUMBER_OF_CIS_BLOCKS 24
-+#define SIZE_OF_BLOCK 0x00004000
-+#define NUMBER_OF_BLOCK_PER_ZONE 1024
-+#define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK)
-+#ifndef CONFIG_MTD_CMDLINE_PARTS
-+/*
-+ * You can use the following sample of MTD partitions
-+ * on the NAND Flash Memory 32MB or more.
-+ *
-+ * The following figure shows the image of the sample partition on
-+ * the 32MB NAND Flash Memory.
-+ *
-+ * Block No.
-+ * 0 +-----------------------------+ ------
-+ * | CIS | ^
-+ * 24 +-----------------------------+ |
-+ * | kernel image | | Zone 0
-+ * | | |
-+ * +-----------------------------+ |
-+ * 1023 | unused area | v
-+ * +-----------------------------+ ------
-+ * 1024 | JFFS2 | ^
-+ * | | |
-+ * | | | Zone 1
-+ * | | |
-+ * | | |
-+ * | | v
-+ * 2047 +-----------------------------+ ------
-+ *
-+ */
-+static struct mtd_partition partition_info[NUM_PARTITIONS] = {
-+ {
-+ .name = "RBTX4938 CIS Area",
-+ .offset = 0,
-+ .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK),
-+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
-+ },
-+ {
-+ .name = "RBTX4938 kernel image",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */
-+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
-+ },
-+ {
-+ .name = "Root FS (JFFS2)",
-+ .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */
-+ .size = MTDPART_SIZ_FULL
-+ },
-+};
-+#endif
-+
-+static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+ switch (cmd) {
-+ case NAND_CTL_SETCLE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_CLRCLE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE;
-+ break;
-+ case NAND_CTL_SETALE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE;
-+ break;
-+ case NAND_CTL_CLRALE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE;
-+ break;
-+ /* TX4938_NDFMCR_CE bit is 0:high 1:low */
-+ case NAND_CTL_SETNCE:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_CLRNCE:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE;
-+ break;
-+ case NAND_CTL_SETWP:
-+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE;
-+ break;
-+ case NAND_CTL_CLRWP:
-+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE;
-+ break;
-+ }
-+}
-+static int tx4938ndfmc_dev_ready(struct mtd_info *mtd)
-+{
-+ flush_wb();
-+ return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY);
-+}
-+static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-+{
-+ u32 mcr = tx4938_ndfmcptr->mcr;
-+ mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ;
-+ ecc_code[1] = tx4938_ndfmcptr->dtr;
-+ ecc_code[0] = tx4938_ndfmcptr->dtr;
-+ ecc_code[2] = tx4938_ndfmcptr->dtr;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+}
-+static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+ u32 mcr = tx4938_ndfmcptr->mcr;
-+ mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON;
-+}
-+
-+static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ return tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+ struct nand_chip *this = mtd->priv;
-+ tx4938_write_nfmc(byte, this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ tx4938_write_nfmc(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ buf[i] = tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+ int i;
-+ struct nand_chip *this = mtd->priv;
-+
-+ for (i=0; i<len; i++)
-+ if (buf[i] != tx4938_read_nfmc(this->IO_ADDR_R))
-+ return i;
-+
-+ return 0;
-+}
-+
-+/*
-+ * Send command to NAND device
-+ */
-+static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+ register struct nand_chip *this = mtd->priv;
-+
-+ /* Begin command latch cycle */
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+ /*
-+ * Write out the command to the device.
-+ */
-+ if (command == NAND_CMD_SEQIN) {
-+ int readcmd;
-+
-+ if (column >= mtd->oobblock) {
-+ /* OOB area */
-+ column -= mtd->oobblock;
-+ readcmd = NAND_CMD_READOOB;
-+ } else if (column < 256) {
-+ /* First 256 bytes --> READ0 */
-+ readcmd = NAND_CMD_READ0;
-+ } else {
-+ column -= 256;
-+ readcmd = NAND_CMD_READ1;
-+ }
-+ this->write_byte(mtd, readcmd);
-+ }
-+ this->write_byte(mtd, command);
-+
-+ /* Set ALE and clear CLE to start address cycle */
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+ if (column != -1 || page_addr != -1) {
-+ this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+ /* Serially input address */
-+ if (column != -1)
-+ this->write_byte(mtd, column);
-+ if (page_addr != -1) {
-+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+ /* One more address cycle for higher density devices */
-+ if (mtd->size & 0x0c000000)
-+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
-+ }
-+ /* Latch in address */
-+ this->hwcontrol(mtd, NAND_CTL_CLRALE);
-+ }
-+
-+ /*
-+ * program and erase have their own busy handlers
-+ * status and sequential in needs no delay
-+ */
-+ switch (command) {
-+
-+ case NAND_CMD_PAGEPROG:
-+ /* Turn off WE */
-+ this->hwcontrol (mtd, NAND_CTL_CLRWP);
-+ return;
-+
-+ case NAND_CMD_SEQIN:
-+ /* Turn on WE */
-+ this->hwcontrol (mtd, NAND_CTL_SETWP);
-+ return;
-+
-+ case NAND_CMD_ERASE1:
-+ case NAND_CMD_ERASE2:
-+ case NAND_CMD_STATUS:
-+ return;
-+
-+ case NAND_CMD_RESET:
-+ if (this->dev_ready)
-+ break;
-+ this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+ this->write_byte(mtd, NAND_CMD_STATUS);
-+ this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+ while ( !(this->read_byte(mtd) & 0x40));
-+ return;
-+
-+ /* This applies to read commands */
-+ default:
-+ /*
-+ * If we don't have access to the busy pin, we apply the given
-+ * command delay
-+ */
-+ if (!this->dev_ready) {
-+ udelay (this->chip_delay);
-+ return;
-+ }
-+ }
-+
-+ /* wait until command is processed */
-+ while (!this->dev_ready(mtd));
-+}
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
-+#endif
-+/*
-+ * Main initialization routine
-+ */
-+int __init tx4938ndfmc_init (void)
-+{
-+ struct nand_chip *this;
-+ int bsprt = 0, hold = 0xf, spw = 0xf;
-+ int protected = 0;
-+
-+ if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) {
-+ printk("TX4938 NDFMC: disabled by IOC PIOSEL\n");
-+ return -ENODEV;
-+ }
-+ bsprt = 1;
-+ hold = 2;
-+ spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */
-+
-+ if ((tx4938_ccfgptr->pcfg &
-+ (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL))
-+ != TX4938_PCFG_NDF_SEL) {
-+ printk("TX4938 NDFMC: disabled by PCFG.\n");
-+ return -ENODEV;
-+ }
-+
-+ /* reset NDFMC */
-+ tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST;
-+ while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST)
-+ ;
-+ /* setup BusSeparete, Hold Time, Strobe Pulse Width */
-+ tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0;
-+ tx4938_ndfmcptr->spr = hold << 4 | spw;
-+
-+ /* Allocate memory for MTD device structure and private data */
-+ tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+ GFP_KERNEL);
-+ if (!tx4938ndfmc_mtd) {
-+ printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Get pointer to private data */
-+ this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]);
-+
-+ /* Initialize structures */
-+ memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info));
-+ memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+ /* Link the private data with the MTD structure */
-+ tx4938ndfmc_mtd->priv = this;
-+
-+ /* Set address of NAND IO lines */
-+ this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr;
-+ this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr;
-+ this->hwcontrol = tx4938ndfmc_hwcontrol;
-+ this->dev_ready = tx4938ndfmc_dev_ready;
-+ this->calculate_ecc = tx4938ndfmc_calculate_ecc;
-+ this->correct_data = nand_correct_data;
-+ this->enable_hwecc = tx4938ndfmc_enable_hwecc;
-+ this->eccmode = NAND_ECC_HW3_256;
-+ this->chip_delay = 100;
-+ this->read_byte = tx4938ndfmc_nand_read_byte;
-+ this->write_byte = tx4938ndfmc_nand_write_byte;
-+ this->cmdfunc = tx4938ndfmc_nand_command;
-+ this->write_buf = tx4938ndfmc_nand_write_buf;
-+ this->read_buf = tx4938ndfmc_nand_read_buf;
-+ this->verify_buf = tx4938ndfmc_nand_verify_buf;
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan (tx4938ndfmc_mtd, 1)) {
-+ kfree (tx4938ndfmc_mtd);
-+ return -ENXIO;
-+ }
-+
-+ /* Allocate memory for internal data buffer */
-+ this->data_buf = kmalloc (sizeof(u_char) * (tx4938ndfmc_mtd->oobblock + tx4938ndfmc_mtd->oobsize), GFP_KERNEL);
-+ if (!this->data_buf) {
-+ printk ("Unable to allocate NAND data buffer for TX4938.\n");
-+ kfree (tx4938ndfmc_mtd);
-+ return -ENOMEM;
-+ }
-+
-+ if (protected) {
-+ printk(KERN_INFO "TX4938 NDFMC: write protected.\n");
-+ tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
-+ }
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ {
-+ int mtd_parts_nb = 0;
-+ struct mtd_partition *mtd_parts = 0;
-+ mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc");
-+ if (mtd_parts_nb > 0)
-+ add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb);
-+ else
-+ add_mtd_device(tx4938ndfmc_mtd);
-+ }
-+#else
-+ add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS );
-+#endif
-+
-+ return 0;
-+}
-+module_init(tx4938ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit tx4938ndfmc_cleanup (void)
-+{
-+ struct nand_chip *this = (struct nand_chip *) tx4938ndfmc_mtd->priv;
-+
-+ /* Unregister the device */
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ del_mtd_partitions(tx4938ndfmc_mtd);
-+#endif
-+ del_mtd_device (tx4938ndfmc_mtd);
-+
-+ /* Free the MTD device structure */
-+ kfree (tx4938ndfmc_mtd);
-+
-+ /* Free internal data buffer */
-+ kfree (this->data_buf);
-+}
-+module_exit(tx4938ndfmc_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC");
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c
---- linux-mips-2.4.27/drivers/mtd/nftlcore.c 2003-02-26 01:53:49.000000000 +0100
-+++ linux/drivers/mtd/nftlcore.c 2004-11-19 10:25:11.653237184 +0100
-@@ -1,7 +1,7 @@
- /* Linux driver for NAND Flash Translation Layer */
- /* (c) 1999 Machine Vision Holdings, Inc. */
- /* Author: David Woodhouse <dwmw2@infradead.org> */
--/* $Id$ */
-+/* $Id$ */
-
- /*
- The contents of this file are distributed under the GNU General
-@@ -23,15 +23,13 @@
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/init.h>
--#include <linux/blkpg.h>
-+#include <linux/hdreg.h>
-
--#ifdef CONFIG_KMOD
- #include <linux/kmod.h>
--#endif
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nftl.h>
--#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/blktrans.h>
-
- /* maximum number of loops while examining next block, to have a
- chance to detect consistency problems (they should never happen
-@@ -39,187 +37,95 @@
-
- #define MAX_LOOPS 10000
-
--/* NFTL block device stuff */
--#define MAJOR_NR NFTL_MAJOR
--#define DEVICE_REQUEST nftl_request
--#define DEVICE_OFF(device)
--
--
--#include <linux/blk.h>
--#include <linux/hdreg.h>
--
--/* Linux-specific block device functions */
--
--/* I _HATE_ the Linux block device setup more than anything else I've ever
-- * encountered, except ...
-- */
--
--static int nftl_sizes[256];
--static int nftl_blocksizes[256];
--
--/* .. for the Linux partition table handling. */
--struct hd_struct part_table[256];
--
--#if LINUX_VERSION_CODE < 0x20328
--static void dummy_init (struct gendisk *crap)
--{}
--#endif
--
--static struct gendisk nftl_gendisk = {
-- major: MAJOR_NR,
-- major_name: "nftl",
-- minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */
-- max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
--#if LINUX_VERSION_CODE < 0x20328
-- max_nr: MAX_NFTLS, /* maximum number of real */
-- init: dummy_init, /* init function */
--#endif
-- part: part_table, /* hd struct */
-- sizes: nftl_sizes, /* block sizes */
--};
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
--struct NFTLrecord *NFTLs[MAX_NFTLS];
-
--static void NFTL_setup(struct mtd_info *mtd)
-+static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
- {
-- int i;
- struct NFTLrecord *nftl;
- unsigned long temp;
-- int firstfree = -1;
--
-- DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
-
-- for (i = 0; i < MAX_NFTLS; i++) {
-- if (!NFTLs[i] && firstfree == -1)
-- firstfree = i;
-- else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
-- /* This is a Spare Media Header for an NFTL we've already found */
-- DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
-+ if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
- return;
-- }
-- }
-- if (firstfree == -1) {
-- printk(KERN_WARNING "No more NFTL slot available\n");
-- return;
-- }
-+
-+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
-
- nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-+
- if (!nftl) {
-- printk(KERN_WARNING "Out of memory for NFTL data structures\n");
-+ printk(KERN_WARNING "NFTL: out of memory for data structures\n");
- return;
- }
-+ memset(nftl, 0, sizeof(*nftl));
-
-- init_MUTEX(&nftl->mutex);
--
-- nftl->mtd = mtd;
-+ nftl->mbd.mtd = mtd;
-+ nftl->mbd.devnum = -1;
-+ nftl->mbd.blksize = 512;
-+ nftl->mbd.tr = tr;
-
- if (NFTL_mount(nftl) < 0) {
-- printk(KERN_WARNING "Could not mount NFTL device\n");
-+ printk(KERN_WARNING "NFTL: could not mount device\n");
- kfree(nftl);
- return;
- }
-
- /* OK, it's a new one. Set up all the data structures. */
--#ifdef PSYCHO_DEBUG
-- printk("Found new NFTL nftl%c\n", firstfree + 'a');
--#endif
-
-- /* linux stuff */
-- nftl->usecount = 0;
-+ /* Calculate geometry */
- nftl->cylinders = 1024;
- nftl->heads = 16;
-
- temp = nftl->cylinders * nftl->heads;
-- nftl->sectors = nftl->nr_sects / temp;
-- if (nftl->nr_sects % temp) {
-+ nftl->sectors = nftl->mbd.size / temp;
-+ if (nftl->mbd.size % temp) {
- nftl->sectors++;
- temp = nftl->cylinders * nftl->sectors;
-- nftl->heads = nftl->nr_sects / temp;
-+ nftl->heads = nftl->mbd.size / temp;
-
-- if (nftl->nr_sects % temp) {
-+ if (nftl->mbd.size % temp) {
- nftl->heads++;
- temp = nftl->heads * nftl->sectors;
-- nftl->cylinders = nftl->nr_sects / temp;
-+ nftl->cylinders = nftl->mbd.size / temp;
- }
- }
-
-- if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
-- printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-- "match size of 0x%x.\n", nftl->nr_sects);
-- printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n",
-+ if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
-+ /*
-+ Oh no we don't have
-+ mbd.size == heads * cylinders * sectors
-+ */
-+ printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
-+ "match size of 0x%lx.\n", nftl->mbd.size);
-+ printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
-+ "(== 0x%lx sects)\n",
- nftl->cylinders, nftl->heads , nftl->sectors,
-- (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
--
-- /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
-+ (long)nftl->cylinders * (long)nftl->heads *
-+ (long)nftl->sectors );
- }
-- NFTLs[firstfree] = nftl;
-- /* Finally, set up the block device sizes */
-- nftl_sizes[firstfree * 16] = nftl->nr_sects;
-- //nftl_blocksizes[firstfree*16] = 512;
-- part_table[firstfree * 16].nr_sects = nftl->nr_sects;
--
-- nftl_gendisk.nr_real++;
--
-- /* partition check ... */
--#if LINUX_VERSION_CODE < 0x20328
-- resetup_one_dev(&nftl_gendisk, firstfree);
--#else
-- grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
--#endif
--}
--
--static void NFTL_unsetup(int i)
--{
-- struct NFTLrecord *nftl = NFTLs[i];
--
-- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
--
-- NFTLs[i] = NULL;
-
-+ if (add_mtd_blktrans_dev(&nftl->mbd)) {
- if (nftl->ReplUnitTable)
- kfree(nftl->ReplUnitTable);
- if (nftl->EUNtable)
- kfree(nftl->EUNtable);
--
-- nftl_gendisk.nr_real--;
- kfree(nftl);
--}
--
--/* Search the MTD device for NFTL partitions */
--static void NFTL_notify_add(struct mtd_info *mtd)
--{
-- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
--
-- if (mtd) {
-- if (!mtd->read_oob) {
-- /* If this MTD doesn't have out-of-band data,
-- then there's no point continuing */
-- DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
- return;
- }
-- DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n",
-- mtd->read, mtd->size, mtd->erasesize);
--
-- NFTL_setup(mtd);
-- }
-+#ifdef PSYCHO_DEBUG
-+ printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
-+#endif
- }
-
--static void NFTL_notify_remove(struct mtd_info *mtd)
-+static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
- {
-- int i;
-+ struct NFTLrecord *nftl = (void *)dev;
-
-- for (i = 0; i < MAX_NFTLS; i++) {
-- if (NFTLs[i] && NFTLs[i]->mtd == mtd)
-- NFTL_unsetup(i);
-- }
-+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
-+
-+ del_mtd_blktrans_dev(dev);
-+ if (nftl->ReplUnitTable)
-+ kfree(nftl->ReplUnitTable);
-+ if (nftl->EUNtable)
-+ kfree(nftl->EUNtable);
-+ kfree(nftl);
- }
-
- #ifdef CONFIG_NFTL_RW
-@@ -303,7 +209,7 @@
-
- targetEUN = thisEUN;
- for (block = 0; block < nftl->EraseSize / 512; block ++) {
-- MTD_READOOB(nftl->mtd,
-+ MTD_READOOB(nftl->mbd.mtd,
- (thisEUN * nftl->EraseSize) + (block * 512),
- 16 , &retlen, (char *)&oob);
- if (block == 2) {
-@@ -420,7 +326,7 @@
- chain by selecting the longer one */
- oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
- oob.u.c.unused = 0xffffffff;
-- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
- 8, &retlen, (char *)&oob.u);
- }
-
-@@ -444,16 +350,16 @@
- if (BlockMap[block] == BLOCK_NIL)
- continue;
-
-- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-+ ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
- if (ret < 0) {
-- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-+ ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
- + (block * 512), 512, &retlen,
- movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
- if (ret != -EIO)
- printk("Error went away on retry.\n");
- }
-- MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-+ MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
- }
-
-@@ -462,7 +368,7 @@
- = cpu_to_le16(thisVUC);
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-
-- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
- 8, &retlen, (char *)&oob.u);
-
- /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
-@@ -582,7 +488,7 @@
-
- lastEUN = writeEUN;
-
-- MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-+ MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci);
-
- DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
-@@ -670,12 +576,12 @@
- nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
-
- /* ... and on the flash itself */
-- MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
-+ MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
-
- oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
-
-- MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
-
- /* we link the new block to the chain only after the
-@@ -685,13 +591,13 @@
- /* Both in our cache... */
- nftl->ReplUnitTable[lastEUN] = writeEUN;
- /* ... and on the flash itself */
-- MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
-+ MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
-
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
- = cpu_to_le16(writeEUN);
-
-- MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
-+ MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
- }
-
-@@ -704,8 +610,10 @@
- return 0xffff;
- }
-
--static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-+static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
- {
-+ struct NFTLrecord *nftl = (void *)mbd;
- u16 writeEUN;
- unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
- size_t retlen;
-@@ -720,7 +628,7 @@
- return 1;
- }
-
-- MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-+ MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
- /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
-
-@@ -728,8 +636,10 @@
- }
- #endif /* CONFIG_NFTL_RW */
-
--static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
-+static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
-+ char *buffer)
- {
-+ struct NFTLrecord *nftl = (void *)mbd;
- u16 lastgoodEUN;
- u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
- unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
-@@ -742,7 +652,7 @@
-
- if (thisEUN != BLOCK_NIL) {
- while (thisEUN < nftl->nb_blocks) {
-- if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
-+ if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci) < 0)
- status = SECTOR_IGNORE;
- else
-@@ -761,13 +671,13 @@
- case SECTOR_IGNORE:
- break;
- default:
-- printk("Unknown status for block %d in EUN %d: %x\n",
-+ printk("Unknown status for block %ld in EUN %d: %x\n",
- block, thisEUN, status);
- break;
- }
-
- if (!silly--) {
-- printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
-+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
- block / (nftl->EraseSize / 512));
- return 1;
- }
-@@ -783,264 +693,22 @@
- loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
- size_t retlen;
- u_char eccbuf[6];
-- if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
-+ if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
- return -EIO;
- }
- return 0;
- }
-
--static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
--{
-- struct NFTLrecord *nftl;
-- int p;
--
-- nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
--
-- if (!nftl) return -EINVAL;
--
-- switch (cmd) {
-- case HDIO_GETGEO: {
-- struct hd_geometry g;
--
-- g.heads = nftl->heads;
-- g.sectors = nftl->sectors;
-- g.cylinders = nftl->cylinders;
-- g.start = part_table[MINOR(inode->i_rdev)].start_sect;
-- return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
-- }
-- case BLKGETSIZE: /* Return device size */
-- return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
-- (unsigned long *) arg);
--
--#ifdef BLKGETSIZE64
-- case BLKGETSIZE64:
-- return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
-- (u64 *)arg);
--#endif
--
-- case BLKFLSBUF:
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-- fsync_dev(inode->i_rdev);
-- invalidate_buffers(inode->i_rdev);
-- if (nftl->mtd->sync)
-- nftl->mtd->sync(nftl->mtd);
-- return 0;
--
-- case BLKRRPART:
-- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-- if (nftl->usecount > 1) return -EBUSY;
-- /*
-- * We have to flush all buffers and invalidate caches,
-- * or we won't be able to re-use the partitions,
-- * if there was a change and we don't want to reboot
-- */
-- p = (1<<NFTL_PARTN_BITS) - 1;
-- while (p-- > 0) {
-- kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
-- if (part_table[p].nr_sects > 0)
-- invalidate_device (devp, 1);
--
-- part_table[MINOR(inode->i_dev)+p].start_sect = 0;
-- part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
-- }
--
--#if LINUX_VERSION_CODE < 0x20328
-- resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
--#else
-- grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
-- 1<<NFTL_PARTN_BITS, nftl->nr_sects);
--#endif
-- return 0;
--
--#if (LINUX_VERSION_CODE < 0x20303)
-- RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
--#else
-- case BLKROSET:
-- case BLKROGET:
-- case BLKSSZGET:
-- return blk_ioctl(inode->i_rdev, cmd, arg);
--#endif
--
-- default:
-- return -EINVAL;
-- }
--}
--
--void nftl_request(RQFUNC_ARG)
--{
-- unsigned int dev, block, nsect;
-- struct NFTLrecord *nftl;
-- char *buffer;
-- struct request *req;
-- int res;
--
-- while (1) {
-- INIT_REQUEST; /* blk.h */
-- req = CURRENT;
--
-- /* We can do this because the generic code knows not to
-- touch the request at the head of the queue */
-- spin_unlock_irq(&io_request_lock);
--
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
-- DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
-- (req->cmd == READ) ? "Read " : "Write",
-- req->sector, req->current_nr_sectors);
--
-- dev = MINOR(req->rq_dev);
-- block = req->sector;
-- nsect = req->current_nr_sectors;
-- buffer = req->buffer;
-- res = 1; /* succeed */
--
-- if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
-- /* there is no such partition */
-- printk("nftl: bad minor number: device = %s\n",
-- kdevname(req->rq_dev));
-- res = 0; /* fail */
-- goto repeat;
-- }
--
-- nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
-- DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
-- down(&nftl->mutex);
-- DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
--
-- if (block + nsect > part_table[dev].nr_sects) {
-- /* access past the end of device */
-- printk("nftl%c%d: bad access: block = %d, count = %d\n",
-- (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
-- up(&nftl->mutex);
-- res = 0; /* fail */
-- goto repeat;
-- }
--
-- block += part_table[dev].start_sect;
--
-- if (req->cmd == READ) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
-- "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
--
-- for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-- /* Read a single sector to req->buffer + (512 * i) */
-- if (NFTL_readblock(nftl, block, buffer)) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- }
--
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
-- up(&nftl->mutex);
-- goto repeat;
-- } else if (req->cmd == WRITE) {
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
-- "(req->nr_sectors == %lx)\n", nsect, block,
-- req->nr_sectors);
--#ifdef CONFIG_NFTL_RW
-- for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-- /* Read a single sector to req->buffer + (512 * i) */
-- if (NFTL_writeblock(nftl, block, buffer)) {
-- DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- }
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
--#else
-- res = 0; /* Writes always fail */
--#endif /* CONFIG_NFTL_RW */
-- up(&nftl->mutex);
-- goto repeat;
-- } else {
-- DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
-- up(&nftl->mutex);
-- res = 0;
-- goto repeat;
-- }
-- repeat:
-- DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
-- spin_lock_irq(&io_request_lock);
-- end_request(res);
-- }
--}
--
--static int nftl_open(struct inode *ip, struct file *fp)
--{
-- int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
-- struct NFTLrecord *thisNFTL;
-- thisNFTL = NFTLs[nftlnum];
--
-- DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
--
--#ifdef CONFIG_KMOD
-- if (!thisNFTL && nftlnum == 0) {
-- request_module("docprobe");
-- thisNFTL = NFTLs[nftlnum];
-- }
--#endif
-- if (!thisNFTL) {
-- DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
-- nftlnum, ip->i_rdev, ip, fp);
-- return -ENODEV;
-- }
--
--#ifndef CONFIG_NFTL_RW
-- if (fp->f_mode & FMODE_WRITE)
-- return -EROFS;
--#endif /* !CONFIG_NFTL_RW */
--
-- thisNFTL->usecount++;
-- BLK_INC_USE_COUNT;
-- if (!get_mtd_device(thisNFTL->mtd, -1)) {
-- BLK_DEC_USE_COUNT;
-- return -ENXIO;
-- }
--
-- return 0;
--}
--
--static int nftl_release(struct inode *inode, struct file *fp)
-+static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
- {
-- struct NFTLrecord *thisNFTL;
--
-- thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
--
-- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
--
-- if (thisNFTL->mtd->sync)
-- thisNFTL->mtd->sync(thisNFTL->mtd);
-- thisNFTL->usecount--;
-- BLK_DEC_USE_COUNT;
-+ struct NFTLrecord *nftl = (void *)dev;
-
-- put_mtd_device(thisNFTL->mtd);
-+ geo->heads = nftl->heads;
-+ geo->sectors = nftl->sectors;
-+ geo->cylinders = nftl->cylinders;
-
- return 0;
- }
--#if LINUX_VERSION_CODE < 0x20326
--static struct file_operations nftl_fops = {
-- read: block_read,
-- write: block_write,
-- ioctl: nftl_ioctl,
-- open: nftl_open,
-- release: nftl_release,
-- fsync: block_fsync,
--};
--#else
--static struct block_device_operations nftl_fops =
--{
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
-- owner: THIS_MODULE,
--#endif
-- open: nftl_open,
-- release: nftl_release,
-- ioctl: nftl_ioctl
--};
--#endif
--
--
-
- /****************************************************************************
- *
-@@ -1048,49 +716,33 @@
- *
- ****************************************************************************/
-
--static struct mtd_notifier nftl_notifier = {
-- add: NFTL_notify_add,
-- remove: NFTL_notify_remove
-+
-+struct mtd_blktrans_ops nftl_tr = {
-+ .name = "nftl",
-+ .major = NFTL_MAJOR,
-+ .part_bits = NFTL_PARTN_BITS,
-+ .getgeo = nftl_getgeo,
-+ .readsect = nftl_readblock,
-+#ifdef CONFIG_NFTL_RW
-+ .writesect = nftl_writeblock,
-+#endif
-+ .add_mtd = nftl_add_mtd,
-+ .remove_dev = nftl_remove_dev,
-+ .owner = THIS_MODULE,
- };
-
- extern char nftlmountrev[];
-
- int __init init_nftl(void)
- {
-- int i;
--
--#ifdef PRERELEASE
-- printk(KERN_INFO "NFTL driver: nftlcore.c $Revision$, nftlmount.c %s\n", nftlmountrev);
--#endif
--
-- if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
-- printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
-- return -EBUSY;
-- } else {
-- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
-+ printk(KERN_INFO "NFTL driver: nftlcore.c $Revision$, nftlmount.c %s\n", nftlmountrev);
-
-- /* set block size to 1kB each */
-- for (i = 0; i < 256; i++) {
-- nftl_blocksizes[i] = 1024;
-- }
-- blksize_size[MAJOR_NR] = nftl_blocksizes;
--
-- add_gendisk(&nftl_gendisk);
-- }
--
-- register_mtd_user(&nftl_notifier);
--
-- return 0;
-+ return register_mtd_blktrans(&nftl_tr);
- }
-
- static void __exit cleanup_nftl(void)
- {
-- unregister_mtd_user(&nftl_notifier);
-- unregister_blkdev(MAJOR_NR, "nftl");
--
-- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
--
-- del_gendisk(&nftl_gendisk);
-+ deregister_mtd_blktrans(&nftl_tr);
- }
-
- module_init(init_nftl);
-diff -Nurb linux-mips-2.4.27/drivers/mtd/nftlmount.c linux/drivers/mtd/nftlmount.c
---- linux-mips-2.4.27/drivers/mtd/nftlmount.c 2003-07-05 05:23:38.000000000 +0200
-+++ linux/drivers/mtd/nftlmount.c 2004-11-19 10:25:11.655236880 +0100
-@@ -4,7 +4,7 @@
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
- * Copyright (C) 2000 Netgem S.A.
- *
-- * $Id$
-+ * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
-@@ -21,26 +21,17 @@
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
--#define __NO_VERSION__
- #include <linux/kernel.h>
--#include <linux/module.h>
- #include <asm/errno.h>
--#include <asm/io.h>
--#include <asm/uaccess.h>
--#include <linux/miscdevice.h>
--#include <linux/pci.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
--#include <linux/sched.h>
--#include <linux/init.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nftl.h>
--#include <linux/mtd/compatmac.h>
-
- #define SECTORSIZE 512
-
--char nftlmountrev[]="$Revision$";
-+char nftlmountrev[]="$Revision$";
-
- /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
- * various device information of the NFTL partition and Bad Unit Table. Update
-@@ -59,8 +50,8 @@
-
- /* Assume logical EraseSize == physical erasesize for starting the scan.
- We'll sort it out later if we find a MediaHeader which says otherwise */
-- nftl->EraseSize = nftl->mtd->erasesize;
-- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
-+ nftl->EraseSize = nftl->mbd.mtd->erasesize;
-+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
-
- nftl->MediaUnit = BLOCK_NIL;
- nftl->SpareMediaUnit = BLOCK_NIL;
-@@ -71,12 +62,12 @@
-
- /* Check for ANAND header first. Then can whinge if it's found but later
- checks fail */
-- if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
-+ if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
- static int warncount = 5;
-
- if (warncount) {
- printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- if (!--warncount)
- printk(KERN_WARNING "Further failures for this block will not be printed\n");
- }
-@@ -87,16 +78,16 @@
- /* ANAND\0 not found. Continue */
- #if 0
- printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
-- block * nftl->EraseSize, nftl->mtd->index);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index);
- #endif
- continue;
- }
-
- /* To be safer with BIOS, also use erase mark as discriminant */
-- if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-- 8, &retlen, (char *)&h1)) < 0) {
-+ if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-+ 8, &retlen, (char *)&h1) < 0)) {
- printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- continue;
- }
-
-@@ -106,23 +97,23 @@
- */
- if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
-- block * nftl->EraseSize, nftl->mtd->index,
-+ block * nftl->EraseSize, nftl->mbd.mtd->index,
- le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
- continue;
- }
-
- /* Finally reread to check ECC */
-- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
-- &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
-+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
-+ &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
-- block * nftl->EraseSize, nftl->mtd->index, ret);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
- continue;
- }
-
- /* Paranoia. Check the ANAND header is still there after the ECC read */
- if (memcmp(buf, "ANAND", 6)) {
- printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
-- block * nftl->EraseSize, nftl->mtd->index);
-+ block * nftl->EraseSize, nftl->mbd.mtd->index);
- printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
- continue;
-@@ -137,8 +128,12 @@
- printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
- nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
- /* if (debug) Print both side by side */
-+ if (boot_record_count < 2) {
-+ /* We haven't yet seen two real ones */
- return -1;
- }
-+ continue;
-+ }
- if (boot_record_count == 1)
- nftl->SpareMediaUnit = block;
-
-@@ -163,8 +158,8 @@
- } else if (mh->UnitSizeFactor != 0xff) {
- printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
- mh->UnitSizeFactor);
-- nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor);
-- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
-+ nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
-+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
- }
- nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
- if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
-@@ -182,7 +177,7 @@
- return -1;
- }
-
-- nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-+ nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-
- /* If we're not using the last sectors in the device for some reason,
- reduce nb_blocks accordingly so we forget they're there */
-@@ -220,7 +215,7 @@
- for (i = 0; i < nftl->nb_blocks; i++) {
- if ((i & (SECTORSIZE - 1)) == 0) {
- /* read one sector for every SECTORSIZE of blocks */
-- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize +
-+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
- i + SECTORSIZE, SECTORSIZE, &retlen, buf,
- (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
- printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
-@@ -263,16 +258,16 @@
- for (i = 0; i < len; i += SECTORSIZE) {
- /* we want to read the sector without ECC check here since a free
- sector does not have ECC syndrome on it yet */
-- if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)
-+ if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
- return -1;
- if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
- return -1;
-
- if (check_oob) {
-- if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,
-+ if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
- &retlen, buf) < 0)
- return -1;
-- if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)
-+ if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
- return -1;
- }
- address += SECTORSIZE;
-@@ -297,7 +292,7 @@
- struct erase_info *instr = &nftl->instr;
-
- /* Read the Unit Control Information #1 for Wear-Leveling */
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
- goto default_uci1;
-
-@@ -314,7 +309,7 @@
- /* XXX: use async erase interface, XXX: test return code */
- instr->addr = block * nftl->EraseSize;
- instr->len = nftl->EraseSize;
-- MTD_ERASE(nftl->mtd, instr);
-+ MTD_ERASE(nftl->mbd.mtd, instr);
-
- if (instr->state == MTD_ERASE_FAILED) {
- /* could not format, FixMe: We should update the BadUnitTable
-@@ -337,7 +332,7 @@
- return -1;
-
- uci.WearInfo = le32_to_cpu(nb_erases);
-- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&uci) < 0)
- return -1;
- return 0;
-@@ -363,7 +358,7 @@
- block = first_block;
- for (;;) {
- for (i = 0; i < sectors_per_block; i++) {
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci) < 0)
- status = SECTOR_IGNORE;
- else
-@@ -383,7 +378,7 @@
- /* sector not free actually : mark it as SECTOR_IGNORE */
- bci.Status = SECTOR_IGNORE;
- bci.Status1 = SECTOR_IGNORE;
-- MTD_WRITEOOB(nftl->mtd,
-+ MTD_WRITEOOB(nftl->mbd.mtd,
- block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci);
- }
-@@ -476,7 +471,7 @@
- size_t retlen;
-
- /* check erase mark. */
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
- return -1;
-
-@@ -491,7 +486,7 @@
- h1.EraseMark = cpu_to_le16(ERASE_MARK);
- h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
- h1.WearInfo = cpu_to_le32(0);
-- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
-+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
- return -1;
- } else {
-@@ -503,7 +498,7 @@
- SECTORSIZE, 0) != 0)
- return -1;
-
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i,
- 16, &retlen, buf) < 0)
- return -1;
- if (i == SECTORSIZE) {
-@@ -533,7 +528,7 @@
- struct nftl_uci2 uci;
- size_t retlen;
-
-- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
-+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
- return 0;
-
-@@ -572,9 +567,9 @@
-
- for (;;) {
- /* read the block header. If error, we format the chain */
-- if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8,
-+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
- &retlen, (char *)&h0) < 0 ||
-- MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
-+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0) {
- s->ReplUnitTable[block] = BLOCK_NIL;
- do_format_chain = 1;
-diff -Nurb linux-mips-2.4.27/drivers/mtd/redboot.c linux/drivers/mtd/redboot.c
---- linux-mips-2.4.27/drivers/mtd/redboot.c 2001-12-02 12:34:42.000000000 +0100
-+++ linux/drivers/mtd/redboot.c 2004-11-19 10:25:11.656236728 +0100
-@@ -1,5 +1,5 @@
- /*
-- * $Id$
-+ * $Id$
- *
- * Parse RedBoot-style Flash Image System (FIS) tables and
- * produce a Linux partition array to match.
-@@ -7,6 +7,7 @@
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
-+#include <linux/init.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -34,7 +35,9 @@
- return 1;
- }
-
--int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-+static int parse_redboot_partitions(struct mtd_info *master,
-+ struct mtd_partition **pparts,
-+ unsigned long fis_origin)
- {
- int nrparts = 0;
- struct fis_image_desc *buf;
-@@ -43,7 +46,9 @@
- int ret, i;
- size_t retlen;
- char *names;
-+ char *nullname;
- int namelen = 0;
-+ static char nullstring[] = "unallocated";
-
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-
-@@ -90,7 +95,11 @@
- goto out;
- }
- new_fl->img = &buf[i];
-+ if (fis_origin) {
-+ buf[i].flash_base -= fis_origin;
-+ } else {
- buf[i].flash_base &= master->size-1;
-+ }
-
- /* I'm sure the JFFS2 code has done me permanent damage.
- * I now think the following is _normal_
-@@ -110,18 +119,24 @@
- if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
- nrparts++;
- }
-- parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL);
-+ parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL);
-
- if (!parts) {
- ret = -ENOMEM;
- goto out;
- }
-- names = (char *)&parts[nrparts];
-+
- memset(parts, 0, sizeof(*parts)*nrparts + namelen);
-+
-+ /* FIXME: Include nullname only if it's used */
-+ nullname = (char *)&parts[nrparts];
-+ sprintf(nullname, nullstring);
-+ names = nullname + sizeof(nullstring);
-+
- i=0;
-
- if (fl->img->flash_base) {
-- parts[0].name = "unallocated space";
-+ parts[0].name = nullname;
- parts[0].size = fl->img->flash_base;
- parts[0].offset = 0;
- }
-@@ -133,11 +148,11 @@
- strcpy(names, fl->img->name);
- names += strlen(names)+1;
-
-- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
-+ if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
-- parts[i].name = "unallocated space";
-+ parts[i].name = nullname;
- }
- tmp_fl = fl;
- fl = fl->next;
-@@ -155,7 +170,24 @@
- return ret;
- }
-
--EXPORT_SYMBOL(parse_redboot_partitions);
-+static struct mtd_part_parser redboot_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_redboot_partitions,
-+ .name = "RedBoot",
-+};
-+
-+static int __init redboot_parser_init(void)
-+{
-+ return register_mtd_parser(&redboot_parser);
-+}
-+
-+static void __exit redboot_parser_exit(void)
-+{
-+ deregister_mtd_parser(&redboot_parser);
-+}
-+
-+module_init(redboot_parser_init);
-+module_exit(redboot_parser_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
-diff -Nurb linux-mips-2.4.27/fs/Config.in linux/fs/Config.in
---- linux-mips-2.4.27/fs/Config.in 2004-02-20 02:22:19.000000000 +0100
-+++ linux/fs/Config.in 2004-11-19 10:25:12.229149632 +0100
-@@ -49,6 +49,7 @@
- dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD
- if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
- int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
-+ bool 'JFFS2 support for NAND chips' CONFIG_JFFS2_FS_NAND
- fi
- tristate 'Compressed ROM file system support' CONFIG_CRAMFS
- bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
-diff -Nurb linux-mips-2.4.27/fs/jffs2/Makefile linux/fs/jffs2/Makefile
---- linux-mips-2.4.27/fs/jffs2/Makefile 2003-08-13 19:19:25.000000000 +0200
-+++ linux/fs/jffs2/Makefile 2004-11-19 10:25:12.071173648 +0100
-@@ -1,7 +1,7 @@
- #
- # Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
- #
--# $Id$
-+# $Id$
- #
- # Note! Dependencies are done automagically by 'make dep', which also
- # removes any old dependencies. DON'T put your own dependencies here
-@@ -10,16 +10,31 @@
- # Note 2! The CFLAGS definitions are now in the main makefile...
-
-
--COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
-- compr_zlib.o
-+obj-$(CONFIG_JFFS2_FS) := jffs2.o
-+
-+COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o compr_zlib.o
- JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
-- read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
-- symlink.o build.o erase.o background.o
-+ read.o nodemgmt.o readinode.o write.o scan.o gc.o \
-+ symlink.o build.o erase.o background.o fs.o writev.o
-
--O_TARGET := jffs2.o
-+BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
-+
-+ifeq ($(BELOW25),y)
-+LINUX_OBJS := super-v24.o crc32.o rbtree.o
-+else
-+LINUX_OBJS := super.o
-+endif
-
--obj-y := $(COMPR_OBJS) $(JFFS2_OBJS)
--obj-m := $(O_TARGET)
-+NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o
-
-+jffs2-objs := $(COMPR_OBJS) $(JFFS2_OBJS) $(VERS_OBJS) $(NAND_OBJS-y) \
-+ $(LINUX_OBJS)
-+
-+
-+# 2.4 build compatibility
-+ifeq ($(BELOW25),y)
-+obj-y := $(jffs2-objs)
-+O_TARGET := jffs2.o
- include $(TOPDIR)/Rules.make
-+endif
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/background.c linux/fs/jffs2/background.c
---- linux-mips-2.4.27/fs/jffs2/background.c 2001-11-06 08:56:10.000000000 +0100
-+++ linux/fs/jffs2/background.c 2004-11-19 10:25:12.072173496 +0100
-@@ -1,61 +1,36 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #define __KERNEL_SYSCALLS__
-
- #include <linux/kernel.h>
--#include <linux/sched.h>
--#include <linux/unistd.h>
- #include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
- #include <linux/completion.h>
-+#include <linux/sched.h>
-+#include <linux/unistd.h>
-+#include <linux/suspend.h>
- #include "nodelist.h"
-
-
- static int jffs2_garbage_collect_thread(void *);
--static int thread_should_wake(struct jffs2_sb_info *c);
-
- void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
- {
-- spin_lock_bh(&c->erase_completion_lock);
-- if (c->gc_task && thread_should_wake(c))
-+ spin_lock(&c->erase_completion_lock);
-+ if (c->gc_task && jffs2_thread_should_wake(c))
- send_sig(SIGHUP, c->gc_task, 1);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- }
-
- /* This must only ever be called when no GC thread is currently running */
-@@ -86,12 +61,12 @@
-
- void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
- {
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- if (c->gc_task) {
- D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
- send_sig(SIGKILL, c->gc_task, 1);
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- wait_for_completion(&c->gc_thread_exit);
- }
-
-@@ -99,34 +74,37 @@
- {
- struct jffs2_sb_info *c = _c;
-
-- daemonize();
-- current->tty = NULL;
-+ daemonize("jffs2_gcd_mtd%d", c->mtd->index);
-+ allow_signal(SIGKILL);
-+ allow_signal(SIGSTOP);
-+ allow_signal(SIGCONT);
-+
- c->gc_task = current;
- up(&c->gc_thread_start);
-
-- sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index);
--
-- /* FIXME in the 2.2 backport */
-- current->nice = 10;
-+ set_user_nice(current, 10);
-
- for (;;) {
-- spin_lock_irq(&current->sigmask_lock);
-- siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ allow_signal(SIGHUP);
-
-- if (!thread_should_wake(c)) {
-+ if (!jffs2_thread_should_wake(c)) {
- set_current_state (TASK_INTERRUPTIBLE);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
-- /* Yes, there's a race here; we checked thread_should_wake() before
-- setting current->state to TASK_INTERRUPTIBLE. But it doesn't
-+ /* Yes, there's a race here; we checked jffs2_thread_should_wake()
-+ before setting current->state to TASK_INTERRUPTIBLE. But it doesn't
- matter - We don't care if we miss a wakeup, because the GC thread
- is only an optimisation anyway. */
- schedule();
- }
-
-- if (current->need_resched)
-- schedule();
-+ if (current->flags & PF_FREEZE) {
-+ refrigerator(0);
-+ /* refrigerator() should recalc sigpending for us
-+ but doesn't. No matter - allow_signal() will. */
-+ continue;
-+ }
-+
-+ cond_resched();
-
- /* Put_super will send a SIGKILL and then wait on the sem.
- */
-@@ -134,9 +112,7 @@
- siginfo_t info;
- unsigned long signr;
-
-- spin_lock_irq(&current->sigmask_lock);
-- signr = dequeue_signal(&current->blocked, &info);
-- spin_unlock_irq(&current->sigmask_lock);
-+ signr = dequeue_signal_lock(current, &current->blocked, &info);
-
- switch(signr) {
- case SIGSTOP:
-@@ -147,9 +123,10 @@
-
- case SIGKILL:
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
-- spin_lock_bh(&c->erase_completion_lock);
-+ die:
-+ spin_lock(&c->erase_completion_lock);
- c->gc_task = NULL;
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- complete_and_exit(&c->gc_thread_exit, 0);
-
- case SIGHUP:
-@@ -157,27 +134,15 @@
- break;
- default:
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr));
--
- }
- }
- /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
-- spin_lock_irq(&current->sigmask_lock);
-- siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-- recalc_sigpending(current);
-- spin_unlock_irq(&current->sigmask_lock);
-+ disallow_signal(SIGHUP);
-
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
-- jffs2_garbage_collect_pass(c);
-+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
-+ printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
-+ goto die;
-+ }
- }
--}
--
--static int thread_should_wake(struct jffs2_sb_info *c)
--{
-- D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n",
-- c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size));
-- if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER &&
-- c->dirty_size > c->sector_size)
-- return 1;
-- else
-- return 0;
- }
-diff -Nurb linux-mips-2.4.27/fs/jffs2/build.c linux/fs/jffs2/build.c
---- linux-mips-2.4.27/fs/jffs2/build.c 2003-07-05 05:23:44.000000000 +0200
-+++ linux/fs/jffs2/build.c 2004-11-19 10:25:12.073173344 +0100
-@@ -1,47 +1,22 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
--#include <linux/jffs2.h>
-+#include <linux/sched.h>
- #include <linux/slab.h>
- #include "nodelist.h"
-
--int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
--int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
-+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
-
- static inline struct jffs2_inode_cache *
- first_inode_chain(int *i, struct jffs2_sb_info *c)
-@@ -68,16 +43,52 @@
- ic; \
- ic = next_inode(&i, ic, (c)))
-
-+
-+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+{
-+ struct jffs2_full_dirent *fd;
-+
-+ D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
-+
-+ /* For each child, increase nlink */
-+ for(fd = ic->scan_dents; fd; fd = fd->next) {
-+ struct jffs2_inode_cache *child_ic;
-+ if (!fd->ino)
-+ continue;
-+
-+ /* XXX: Can get high latency here with huge directories */
-+
-+ child_ic = jffs2_get_ino_cache(c, fd->ino);
-+ if (!child_ic) {
-+ printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
-+ fd->name, fd->ino, ic->ino);
-+ continue;
-+ }
-+
-+ if (child_ic->nlink++ && fd->type == DT_DIR) {
-+ printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-+ if (fd->ino == 1 && ic->ino == 1) {
-+ printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-+ printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-+ }
-+ /* What do we do about it? */
-+ }
-+ D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-+ /* Can't free them. We might need them in pass 2 */
-+ }
-+}
-+
- /* Scan plan:
- - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
- - Scan directory tree from top down, setting nlink in inocaches
- - Scan inocaches for inodes with nlink==0
- */
--int jffs2_build_filesystem(struct jffs2_sb_info *c)
-+static int jffs2_build_filesystem(struct jffs2_sb_info *c)
- {
- int ret;
- int i;
- struct jffs2_inode_cache *ic;
-+ struct jffs2_full_dirent *dead_fds = NULL;
-
- /* First, scan the medium and build all the inode caches with
- lists of physical nodes */
-@@ -90,14 +101,17 @@
- return ret;
-
- D1(printk(KERN_DEBUG "Scanned flash completely\n"));
-- /* Now build the data map for each inode, marking obsoleted nodes
-- as such, and also increase nlink of any children. */
-+ D1(jffs2_dump_block_lists(c));
-+
-+ /* Now scan the directory tree, increasing nlink according to every dirent found. */
- for_each_inode(i, c, ic) {
- D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
-- ret = jffs2_build_inode_pass1(c, ic);
-- if (ret) {
-- D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
-- return ret;
-+
-+ D1(BUG_ON(ic->ino > c->highest_ino));
-+
-+ if (ic->scan_dents) {
-+ jffs2_build_inode_pass1(c, ic);
-+ cond_resched();
- }
- }
- D1(printk(KERN_DEBUG "Pass 1 complete\n"));
-@@ -107,181 +121,226 @@
- children too, and repeat the scan. As that's going to be
- a fairly uncommon occurrence, it's not so evil to do it this
- way. Recursion bad. */
-- do {
-- D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
-- ret = 0;
-+ D1(printk(KERN_DEBUG "Pass 2 starting\n"));
-+
- for_each_inode(i, c, ic) {
- D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
- if (ic->nlink)
- continue;
-
-- ret = jffs2_build_remove_unlinked_inode(c, ic);
-- if (ret)
-- break;
-- /* -EAGAIN means the inode's nlink was zero, so we deleted it,
-- and furthermore that it had children and their nlink has now
-- gone to zero too. So we have to restart the scan. */
-+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
-+ cond_resched();
-+ }
-+
-+ D1(printk(KERN_DEBUG "Pass 2a starting\n"));
-+
-+ while (dead_fds) {
-+ struct jffs2_inode_cache *ic;
-+ struct jffs2_full_dirent *fd = dead_fds;
-+
-+ dead_fds = fd->next;
-+
-+ ic = jffs2_get_ino_cache(c, fd->ino);
-+ D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));
-+
-+ if (ic)
-+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
-+ jffs2_free_full_dirent(fd);
- }
-- } while(ret == -EAGAIN);
-
- D1(printk(KERN_DEBUG "Pass 2 complete\n"));
-
-- /* Finally, we can scan again and free the dirent nodes and scan_info structs */
-+ /* Finally, we can scan again and free the dirent structs */
- for_each_inode(i, c, ic) {
-- struct jffs2_scan_info *scan = ic->scan;
- struct jffs2_full_dirent *fd;
- D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
-- if (!scan) {
-- if (ic->nlink) {
-- D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink));
-- }
-- continue;
-- }
-- ic->scan = NULL;
-- while(scan->dents) {
-- fd = scan->dents;
-- scan->dents = fd->next;
-+
-+ while(ic->scan_dents) {
-+ fd = ic->scan_dents;
-+ ic->scan_dents = fd->next;
- jffs2_free_full_dirent(fd);
- }
-- kfree(scan);
-+ ic->scan_dents = NULL;
-+ cond_resched();
- }
- D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-+ D1(jffs2_dump_block_lists(c));
-+
-+ /* Rotate the lists by some number to ensure wear levelling */
-+ jffs2_rotate_lists(c);
-
- return ret;
- }
-
--int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
- {
-- struct jffs2_tmp_dnode_info *tn;
-+ struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
-- struct jffs2_node_frag *fraglist = NULL;
-- struct jffs2_tmp_dnode_info *metadata = NULL;
--
-- D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
-- if (ic->ino > c->highest_ino)
-- c->highest_ino = ic->ino;
-
-- if (!ic->scan->tmpnodes && ic->ino != 1) {
-- D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino));
-- }
-- /* Build the list to make sure any obsolete nodes are marked as such */
-- while(ic->scan->tmpnodes) {
-- tn = ic->scan->tmpnodes;
-- ic->scan->tmpnodes = tn->next;
--
-- if (metadata && tn->version > metadata->version) {
-- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
-- metadata->fn->raw->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
-
-- jffs2_free_full_dnode(metadata->fn);
-- jffs2_free_tmp_dnode_info(metadata);
-- metadata = NULL;
-+ for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
-+ D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
-+ jffs2_mark_node_obsolete(c, raw);
- }
-
-- if (tn->fn->size) {
-- jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
-- jffs2_free_tmp_dnode_info(tn);
-- } else {
-- if (!metadata) {
-- metadata = tn;
-- } else {
-- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
-- tn->fn->raw->flash_offset &~3));
--
-- jffs2_free_full_dnode(tn->fn);
-- jffs2_free_tmp_dnode_info(tn);
-- }
-- }
-- }
-+ if (ic->scan_dents) {
-+ int whinged = 0;
-+ D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
-
-- /* OK. Now clear up */
-- if (metadata) {
-- jffs2_free_full_dnode(metadata->fn);
-- jffs2_free_tmp_dnode_info(metadata);
-- }
-- metadata = NULL;
-+ while(ic->scan_dents) {
-+ struct jffs2_inode_cache *child_ic;
-
-- while (fraglist) {
-- struct jffs2_node_frag *frag;
-- frag = fraglist;
-- fraglist = fraglist->next;
-+ fd = ic->scan_dents;
-+ ic->scan_dents = fd->next;
-
-- if (frag->node && !(--frag->node->frags)) {
-- jffs2_free_full_dnode(frag->node);
-+ if (!fd->ino) {
-+ /* It's a deletion dirent. Ignore it */
-+ D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
-+ jffs2_free_full_dirent(fd);
-+ continue;
- }
-- jffs2_free_node_frag(frag);
-+ if (!whinged) {
-+ whinged = 1;
-+ printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
- }
-
-- /* Now for each child, increase nlink */
-- for(fd=ic->scan->dents; fd; fd = fd->next) {
-- struct jffs2_inode_cache *child_ic;
-- if (!fd->ino)
-- continue;
-+ D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
-+ fd->name, fd->ino));
-
- child_ic = jffs2_get_ino_cache(c, fd->ino);
- if (!child_ic) {
-- printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
-- fd->name, fd->ino, ic->ino);
-+ printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
-+ jffs2_free_full_dirent(fd);
- continue;
- }
-
-- if (child_ic->nlink++ && fd->type == DT_DIR) {
-- printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-- if (fd->ino == 1 && ic->ino == 1) {
-- printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-- printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-+ /* Reduce nlink of the child. If it's now zero, stick it on the
-+ dead_fds list to be cleaned up later. Else just free the fd */
-+
-+ child_ic->nlink--;
-+
-+ if (!child_ic->nlink) {
-+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
-+ fd->ino, fd->name));
-+ fd->next = *dead_fds;
-+ *dead_fds = fd;
-+ } else {
-+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
-+ fd->ino, fd->name, child_ic->nlink));
-+ jffs2_free_full_dirent(fd);
- }
-- /* What do we do about it? */
- }
-- D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-- /* Can't free them. We might need them in pass 2 */
- }
-- return 0;
-+
-+ /*
-+ We don't delete the inocache from the hash list and free it yet.
-+ The erase code will do that, when all the nodes are completely gone.
-+ */
- }
-
--int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
- {
-- struct jffs2_raw_node_ref *raw;
-- struct jffs2_full_dirent *fd;
-- int ret = 0;
-+ uint32_t size;
-
-- if(!ic->scan) {
-- D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
-- return 0;
-- }
-+ /* Deletion should almost _always_ be allowed. We're fairly
-+ buggered once we stop allowing people to delete stuff
-+ because there's not enough free space... */
-+ c->resv_blocks_deletion = 2;
-+
-+ /* Be conservative about how much space we need before we allow writes.
-+ On top of that which is required for deletia, require an extra 2%
-+ of the medium to be available, for overhead caused by nodes being
-+ split across blocks, etc. */
-+
-+ size = c->flash_size / 50; /* 2% of flash size */
-+ size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
-+ size += c->sector_size - 1; /* ... and round up */
-+
-+ c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
-+
-+ /* When do we let the GC thread run in the background */
-+
-+ c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
-+
-+ /* When do we allow garbage collection to merge nodes to make
-+ long-term progress at the expense of short-term space exhaustion? */
-+ c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
-+
-+ /* When do we allow garbage collection to eat from bad blocks rather
-+ than actually making progress? */
-+ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
-+
-+ /* If there's less than this amount of dirty space, don't bother
-+ trying to GC to make more space. It'll be a fruitless task */
-+ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
-+
-+ D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
-+ c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
-+ D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n",
-+ c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n",
-+ c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
-+ c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n",
-+ c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n",
-+ c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
-+ D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
-+ c->nospc_dirty_size));
-+}
-
-- D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
-+int jffs2_do_mount_fs(struct jffs2_sb_info *c)
-+{
-+ int i;
-
-- for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
-- D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3));
-- jffs2_mark_node_obsolete(c, raw);
-+ c->free_size = c->flash_size;
-+ c->nr_blocks = c->flash_size / c->sector_size;
-+ c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
-+ if (!c->blocks)
-+ return -ENOMEM;
-+ for (i=0; i<c->nr_blocks; i++) {
-+ INIT_LIST_HEAD(&c->blocks[i].list);
-+ c->blocks[i].offset = i * c->sector_size;
-+ c->blocks[i].free_size = c->sector_size;
-+ c->blocks[i].dirty_size = 0;
-+ c->blocks[i].wasted_size = 0;
-+ c->blocks[i].unchecked_size = 0;
-+ c->blocks[i].used_size = 0;
-+ c->blocks[i].first_node = NULL;
-+ c->blocks[i].last_node = NULL;
-+ }
-+
-+ init_MUTEX(&c->alloc_sem);
-+ init_MUTEX(&c->erase_free_sem);
-+ init_waitqueue_head(&c->erase_wait);
-+ init_waitqueue_head(&c->inocache_wq);
-+ spin_lock_init(&c->erase_completion_lock);
-+ spin_lock_init(&c->inocache_lock);
-+
-+ INIT_LIST_HEAD(&c->clean_list);
-+ INIT_LIST_HEAD(&c->very_dirty_list);
-+ INIT_LIST_HEAD(&c->dirty_list);
-+ INIT_LIST_HEAD(&c->erasable_list);
-+ INIT_LIST_HEAD(&c->erasing_list);
-+ INIT_LIST_HEAD(&c->erase_pending_list);
-+ INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
-+ INIT_LIST_HEAD(&c->erase_complete_list);
-+ INIT_LIST_HEAD(&c->free_list);
-+ INIT_LIST_HEAD(&c->bad_list);
-+ INIT_LIST_HEAD(&c->bad_used_list);
-+ c->highest_ino = 1;
-+
-+ if (jffs2_build_filesystem(c)) {
-+ D1(printk(KERN_DEBUG "build_fs failed\n"));
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ kfree(c->blocks);
-+ return -EIO;
- }
-
-- if (ic->scan->dents) {
-- printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
--
-- while(ic->scan->dents) {
-- struct jffs2_inode_cache *child_ic;
-+ jffs2_calc_trigger_levels(c);
-
-- fd = ic->scan->dents;
-- ic->scan->dents = fd->next;
--
-- D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
-- fd->name, fd->ino));
--
-- child_ic = jffs2_get_ino_cache(c, fd->ino);
-- if (!child_ic) {
-- printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
-- continue;
-- }
-- jffs2_free_full_dirent(fd);
-- child_ic->nlink--;
-- }
-- ret = -EAGAIN;
-- }
-- kfree(ic->scan);
-- ic->scan = NULL;
-- // jffs2_del_ino_cache(c, ic);
-- // jffs2_free_inode_cache(ic);
-- return ret;
-+ return 0;
- }
-diff -Nurb linux-mips-2.4.27/fs/jffs2/compr.c linux/fs/jffs2/compr.c
---- linux-mips-2.4.27/fs/jffs2/compr.c 2001-11-05 21:16:18.000000000 +0100
-+++ linux/fs/jffs2/compr.c 2004-11-19 10:25:12.085171520 +0100
-@@ -1,59 +1,37 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/string.h>
--#include <linux/types.h>
- #include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
- #include <linux/jffs2.h>
-+#include "nodelist.h"
-
--int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
--int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
--void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
-+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-+void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-+int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-+void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-+void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-+int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-+void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-
-
- /* jffs2_compress:
- * @data: Pointer to uncompressed data
-- * @cdata: Pointer to buffer for compressed data
-+ * @cdata: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- * On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
-@@ -68,47 +46,59 @@
- * jffs2_compress should compress as much as will fit, and should set
- * *datalen accordingly to show the amount of data which were compressed.
- */
--unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *datalen, __u32 *cdatalen)
-+unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
-+ uint32_t *datalen, uint32_t *cdatalen)
- {
-+#ifdef JFFS2_COMPRESSION
- int ret;
-
-- ret = zlib_compress(data_in, cpage_out, datalen, cdatalen);
-+ *cpage_out = kmalloc(*cdatalen, GFP_KERNEL);
-+ if (!*cpage_out) {
-+ printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n");
-+ goto out;
-+ }
-+
-+#ifdef JFFS2_USE_ZLIB
-+ ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_ZLIB;
- }
--#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
-- ret = dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
-+#endif
-+#ifdef JFFS2_USE_DYNRUBIN
-+ ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_DYNRUBIN;
- }
- #endif
--#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */
-- ret = rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
-+#ifdef JFFS2_USE_RUBINMIPS
-+ ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_RUBINMIPS;
- }
- #endif
-+#ifdef JFFS2_USE_RTIME
- /* rtime does manage to recompress already-compressed data */
-- ret = rtime_compress(data_in, cpage_out, datalen, cdatalen);
-+ ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_RTIME;
- }
--#if 0
-- /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */
-- /* If we get here, no compression is going to work */
-- /* But we might want to use the fragmentation part -- Arjan */
-- memcpy(cpage_out,data_in,min(*datalen,*cdatalen));
-- if (*datalen > *cdatalen)
-- *datalen = *cdatalen;
- #endif
-+ kfree(*cpage_out);
-+#endif /* Compression */
-+ out:
-+ *cpage_out = data_in;
-+ *datalen = *cdatalen;
- return JFFS2_COMPR_NONE; /* We failed to compress */
--
- }
-
-+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
-+{
-+ if (orig != comprbuf)
-+ kfree(comprbuf);
-+}
-
- int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-- unsigned char *data_out, __u32 cdatalen, __u32 datalen)
-+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
- {
- switch (comprtype) {
- case JFFS2_COMPR_NONE:
-@@ -119,30 +109,27 @@
- case JFFS2_COMPR_ZERO:
- memset(data_out, 0, datalen);
- break;
--
-+#ifdef JFFS2_USE_ZLIB
- case JFFS2_COMPR_ZLIB:
-- zlib_decompress(cdata_in, data_out, cdatalen, datalen);
-+ jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen);
- break;
--
-+#endif
-+#ifdef JFFS2_USE_RTIME
- case JFFS2_COMPR_RTIME:
-- rtime_decompress(cdata_in, data_out, cdatalen, datalen);
-+ jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
- break;
--
-- case JFFS2_COMPR_RUBINMIPS:
--#if 0 /* Disabled 23/9/1 */
-- rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
--#else
-- printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n");
- #endif
-+#ifdef JFFS2_USE_RUBINMIPS
-+ case JFFS2_COMPR_RUBINMIPS:
-+ jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
- break;
-- case JFFS2_COMPR_DYNRUBIN:
--#if 1 /* Phase this one out */
-- dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
--#else
-- printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n");
- #endif
-- break;
-+#ifdef JFFS2_USE_DYNRUBIN
-+ case JFFS2_COMPR_DYNRUBIN:
-
-+ jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
-+ break;
-+#endif
- default:
- printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
- return -EIO;
-diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rtime.c linux/fs/jffs2/compr_rtime.c
---- linux-mips-2.4.27/fs/jffs2/compr_rtime.c 2001-10-19 03:24:56.000000000 +0200
-+++ linux/fs/jffs2/compr_rtime.c 2004-11-19 10:25:12.087171216 +0100
-@@ -1,43 +1,19 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- *
- * Very simple lz77-ish encoder.
- *
- * Theory of operation: Both encoder and decoder have a list of "last
-- * occurances" for every possible source-value; after sending the
-+ * occurrences" for every possible source-value; after sending the
- * first source-byte, the second byte indicated the "run" length of
- * matches
- *
-@@ -51,10 +27,10 @@
- #include <linux/string.h>
-
- /* _compress returns the compressed size, -1 if bigger */
--int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen)
- {
-- int positions[256];
-+ short positions[256];
- int outpos = 0;
- int pos=0;
-
-@@ -91,10 +67,10 @@
- }
-
-
--void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 srclen, __u32 destlen)
-+void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t srclen, uint32_t destlen)
- {
-- int positions[256];
-+ short positions[256];
- int outpos = 0;
- int pos=0;
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rubin.c linux/fs/jffs2/compr_rubin.c
---- linux-mips-2.4.27/fs/jffs2/compr_rubin.c 2001-11-05 21:16:18.000000000 +0100
-+++ linux/fs/jffs2/compr_rubin.c 2004-11-19 10:25:12.088171064 +0100
-@@ -1,37 +1,13 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-@@ -43,7 +19,7 @@
-
-
-
--void init_rubin(struct rubin_state *rs, int div, int *bits)
-+static void init_rubin(struct rubin_state *rs, int div, int *bits)
- {
- int c;
-
-@@ -56,7 +32,7 @@
- }
-
-
--int encode(struct rubin_state *rs, long A, long B, int symbol)
-+static int encode(struct rubin_state *rs, long A, long B, int symbol)
- {
-
- long i0, i1;
-@@ -91,7 +67,7 @@
- }
-
-
--void end_rubin(struct rubin_state *rs)
-+static void end_rubin(struct rubin_state *rs)
- {
-
- int i;
-@@ -104,7 +80,7 @@
- }
-
-
--void init_decode(struct rubin_state *rs, int div, int *bits)
-+static void init_decode(struct rubin_state *rs, int div, int *bits)
- {
- init_rubin(rs, div, bits);
-
-@@ -151,7 +127,7 @@
- rs->rec_q = rec_q;
- }
-
--int decode(struct rubin_state *rs, long A, long B)
-+static int decode(struct rubin_state *rs, long A, long B)
- {
- unsigned long p = rs->p, q = rs->q;
- long i0, threshold;
-@@ -212,8 +188,8 @@
-
-
-
--int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
-- unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen)
-+static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
-+ unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen)
- {
- int outpos = 0;
- int pos=0;
-@@ -246,20 +222,20 @@
- }
- #if 0
- /* _compress returns the compressed size, -1 if bigger */
--int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen)
- {
- return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
- }
- #endif
--int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen)
- {
- int bits[8];
- unsigned char histo[256];
- int i;
- int ret;
-- __u32 mysrclen, mydstlen;
-+ uint32_t mysrclen, mydstlen;
-
- mysrclen = *sourcelen;
- mydstlen = *dstlen - 8;
-@@ -315,8 +291,8 @@
- return 0;
- }
-
--void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
-- unsigned char *page_out, __u32 srclen, __u32 destlen)
-+static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
-+ unsigned char *page_out, uint32_t srclen, uint32_t destlen)
- {
- int outpos = 0;
- struct rubin_state rs;
-@@ -330,14 +306,14 @@
- }
-
-
--void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 sourcelen, __u32 dstlen)
-+void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t sourcelen, uint32_t dstlen)
- {
- rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
- }
-
--void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 sourcelen, __u32 dstlen)
-+void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t sourcelen, uint32_t dstlen)
- {
- int bits[8];
- int c;
-diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rubin.h linux/fs/jffs2/compr_rubin.h
---- linux-mips-2.4.27/fs/jffs2/compr_rubin.h 2001-10-19 03:24:56.000000000 +0200
-+++ linux/fs/jffs2/compr_rubin.h 2004-11-19 10:25:12.090170760 +0100
-@@ -1,7 +1,7 @@
- /* Rubin encoder/decoder header */
- /* work started at : aug 3, 1994 */
- /* last modification : aug 15, 1994 */
--/* $Id$ */
-+/* $Id$ */
-
- #include "pushpull.h"
-
-@@ -19,10 +19,3 @@
- int bit_divider;
- int bits[8];
- };
--
--
--void init_rubin (struct rubin_state *rs, int div, int *bits);
--int encode (struct rubin_state *, long, long, int);
--void end_rubin (struct rubin_state *);
--void init_decode (struct rubin_state *, int div, int *bits);
--int decode (struct rubin_state *, long, long);
-diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_zlib.c linux/fs/jffs2/compr_zlib.c
---- linux-mips-2.4.27/fs/jffs2/compr_zlib.c 2003-01-11 18:53:17.000000000 +0100
-+++ linux/fs/jffs2/compr_zlib.c 2004-11-19 10:25:12.091170608 +0100
-@@ -1,50 +1,26 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001, 2002 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
--#ifndef __KERNEL__
-+#if !defined(__KERNEL__) && !defined(__ECOS)
- #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
- #endif
-
- #include <linux/config.h>
- #include <linux/kernel.h>
--#include <linux/mtd/compatmac.h> /* for min() */
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/zlib.h>
-+#include <linux/zutil.h>
-+#include <asm/semaphore.h>
- #include "nodelist.h"
-
- /* Plan: call deflate() with avail_in == *sourcelen,
-@@ -58,21 +34,24 @@
-
- static DECLARE_MUTEX(deflate_sem);
- static DECLARE_MUTEX(inflate_sem);
--static void *deflate_workspace;
--static void *inflate_workspace;
-+static z_stream inf_strm, def_strm;
-+
-+#ifdef __KERNEL__ /* Linux-only */
-+#include <linux/vmalloc.h>
-+#include <linux/init.h>
-
- int __init jffs2_zlib_init(void)
- {
-- deflate_workspace = vmalloc(zlib_deflate_workspacesize());
-- if (!deflate_workspace) {
-+ def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
-+ if (!def_strm.workspace) {
- printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
- return -ENOMEM;
- }
- D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
-- inflate_workspace = vmalloc(zlib_inflate_workspacesize());
-- if (!inflate_workspace) {
-+ inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
-+ if (!inf_strm.workspace) {
- printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
-- vfree(deflate_workspace);
-+ vfree(def_strm.workspace);
- return -ENOMEM;
- }
- D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
-@@ -81,97 +60,120 @@
-
- void jffs2_zlib_exit(void)
- {
-- vfree(deflate_workspace);
-- vfree(inflate_workspace);
-+ vfree(def_strm.workspace);
-+ vfree(inf_strm.workspace);
- }
-+#endif /* __KERNEL__ */
-
--int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *sourcelen, __u32 *dstlen)
-+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t *sourcelen, uint32_t *dstlen)
- {
-- z_stream strm;
- int ret;
-
- if (*dstlen <= STREAM_END_SPACE)
- return -1;
-
- down(&deflate_sem);
-- strm.workspace = deflate_workspace;
-
-- if (Z_OK != zlib_deflateInit(&strm, 3)) {
-+ if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
- printk(KERN_WARNING "deflateInit failed\n");
- up(&deflate_sem);
- return -1;
- }
-
-- strm.next_in = data_in;
-- strm.total_in = 0;
-+ def_strm.next_in = data_in;
-+ def_strm.total_in = 0;
-
-- strm.next_out = cpage_out;
-- strm.total_out = 0;
-+ def_strm.next_out = cpage_out;
-+ def_strm.total_out = 0;
-
-- while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
-- strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
-- strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
-+ while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
-+ def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
-+ def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
- D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
-- strm.avail_in, strm.avail_out));
-- ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
-+ def_strm.avail_in, def_strm.avail_out));
-+ ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
- D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
-- strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
-+ def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
- if (ret != Z_OK) {
- D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-- zlib_deflateEnd(&strm);
-+ zlib_deflateEnd(&def_strm);
- up(&deflate_sem);
- return -1;
- }
- }
-- strm.avail_out += STREAM_END_SPACE;
-- strm.avail_in = 0;
-- ret = zlib_deflate(&strm, Z_FINISH);
-- zlib_deflateEnd(&strm);
-- up(&deflate_sem);
-+ def_strm.avail_out += STREAM_END_SPACE;
-+ def_strm.avail_in = 0;
-+ ret = zlib_deflate(&def_strm, Z_FINISH);
-+ zlib_deflateEnd(&def_strm);
-+
- if (ret != Z_STREAM_END) {
- D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-- return -1;
-+ ret = -1;
-+ goto out;
- }
-
-- D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-- strm.total_in, strm.total_out));
-+ if (def_strm.total_out >= def_strm.total_in) {
-+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n",
-+ def_strm.total_in, def_strm.total_out));
-+ ret = -1;
-+ goto out;
-+ }
-
-- if (strm.total_out >= strm.total_in)
-- return -1;
-+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-+ def_strm.total_in, def_strm.total_out));
-
-- *dstlen = strm.total_out;
-- *sourcelen = strm.total_in;
-- return 0;
-+ *dstlen = def_strm.total_out;
-+ *sourcelen = def_strm.total_in;
-+ ret = 0;
-+ out:
-+ up(&deflate_sem);
-+ return ret;
- }
-
--void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 srclen, __u32 destlen)
-+void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-+ uint32_t srclen, uint32_t destlen)
- {
-- z_stream strm;
- int ret;
-+ int wbits = MAX_WBITS;
-
- down(&inflate_sem);
-- strm.workspace = inflate_workspace;
-
-- if (Z_OK != zlib_inflateInit(&strm)) {
-+ inf_strm.next_in = data_in;
-+ inf_strm.avail_in = srclen;
-+ inf_strm.total_in = 0;
-+
-+ inf_strm.next_out = cpage_out;
-+ inf_strm.avail_out = destlen;
-+ inf_strm.total_out = 0;
-+
-+ /* If it's deflate, and it's got no preset dictionary, then
-+ we can tell zlib to skip the adler32 check. */
-+ if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
-+ ((data_in[0] & 0x0f) == Z_DEFLATED) &&
-+ !(((data_in[0]<<8) + data_in[1]) % 31)) {
-+
-+ D2(printk(KERN_DEBUG "inflate skipping adler32\n"));
-+ wbits = -((data_in[0] >> 4) + 8);
-+ inf_strm.next_in += 2;
-+ inf_strm.avail_in -= 2;
-+ } else {
-+ /* Let this remain D1 for now -- it should never happen */
-+ D1(printk(KERN_DEBUG "inflate not skipping adler32\n"));
-+ }
-+
-+
-+ if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
- printk(KERN_WARNING "inflateInit failed\n");
- up(&inflate_sem);
- return;
- }
-- strm.next_in = data_in;
-- strm.avail_in = srclen;
-- strm.total_in = 0;
--
-- strm.next_out = cpage_out;
-- strm.avail_out = destlen;
-- strm.total_out = 0;
-
-- while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
-+ while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
- ;
- if (ret != Z_STREAM_END) {
- printk(KERN_NOTICE "inflate returned %d\n", ret);
- }
-- zlib_inflateEnd(&strm);
-+ zlib_inflateEnd(&inf_strm);
- up(&inflate_sem);
- }
-diff -Nurb linux-mips-2.4.27/fs/jffs2/comprtest.c linux/fs/jffs2/comprtest.c
---- linux-mips-2.4.27/fs/jffs2/comprtest.c 2001-10-19 03:24:56.000000000 +0200
-+++ linux/fs/jffs2/comprtest.c 2004-11-19 10:25:12.093170304 +0100
-@@ -1,4 +1,4 @@
--/* $Id$ */
-+/* $Id$ */
-
- #include <linux/kernel.h>
- #include <linux/string.h>
-@@ -266,13 +266,13 @@
- static unsigned char decomprbuf[TESTDATA_LEN];
-
- int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-- unsigned char *data_out, __u32 cdatalen, __u32 datalen);
-+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
- unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *datalen, __u32 *cdatalen);
-+ uint32_t *datalen, uint32_t *cdatalen);
-
- int init_module(void ) {
- unsigned char comprtype;
-- __u32 c, d;
-+ uint32_t c, d;
- int ret;
-
- printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-diff -Nurb linux-mips-2.4.27/fs/jffs2/crc32.c linux/fs/jffs2/crc32.c
---- linux-mips-2.4.27/fs/jffs2/crc32.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/crc32.c 2004-11-19 10:25:12.095170000 +0100
-@@ -0,0 +1,97 @@
-+/*
-+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
-+ * code or tables extracted from it, as desired without restriction.
-+ *
-+ * First, the polynomial itself and its table of feedback terms. The
-+ * polynomial is
-+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
-+ *
-+ * Note that we take it "backwards" and put the highest-order term in
-+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
-+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
-+ * the MSB being 1
-+ *
-+ * Note that the usual hardware shift register implementation, which
-+ * is what we're using (we're merely optimizing it by doing eight-bit
-+ * chunks at a time) shifts bits into the lowest-order term. In our
-+ * implementation, that means shifting towards the right. Why do we
-+ * do it this way? Because the calculated CRC must be transmitted in
-+ * order from highest-order term to lowest-order term. UARTs transmit
-+ * characters in order from LSB to MSB. By storing the CRC this way
-+ * we hand it to the UART in the order low-byte to high-byte; the UART
-+ * sends each low-bit to hight-bit; and the result is transmission bit
-+ * by bit from highest- to lowest-order term without requiring any bit
-+ * shuffling on our part. Reception works similarly
-+ *
-+ * The feedback terms table consists of 256, 32-bit entries. Notes
-+ *
-+ * The table can be generated at runtime if desired; code to do so
-+ * is shown later. It might not be obvious, but the feedback
-+ * terms simply represent the results of eight shift/xor opera
-+ * tions for all combinations of data and CRC register values
-+ *
-+ * The values must be right-shifted by eight bits by the "updcrc
-+ * logic; the shift must be unsigned (bring in zeroes). On some
-+ * hardware you could probably optimize the shift in assembler by
-+ * using byte-swap instructions
-+ * polynomial $edb88320
-+ */
-+
-+/* $Id$ */
-+
-+#include "crc32.h"
-+
-+const uint32_t crc32_table[256] = {
-+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
-+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
-+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
-+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
-+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
-+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
-+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
-+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
-+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
-+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
-+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
-+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
-+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
-+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
-+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
-+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
-+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
-+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
-+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
-+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
-+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
-+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
-+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
-+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
-+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
-+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
-+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
-+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
-+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
-+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
-+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
-+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
-+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
-+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
-+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
-+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
-+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
-+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
-+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
-+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
-+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
-+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
-+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
-+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
-+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
-+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
-+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
-+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
-+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
-+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
-+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
-+ 0x2d02ef8dL
-+};
-diff -Nurb linux-mips-2.4.27/fs/jffs2/crc32.h linux/fs/jffs2/crc32.h
---- linux-mips-2.4.27/fs/jffs2/crc32.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/crc32.h 2004-11-19 10:25:12.096169848 +0100
-@@ -0,0 +1,21 @@
-+#ifndef CRC32_H
-+#define CRC32_H
-+
-+/* $Id$ */
-+
-+#include <linux/types.h>
-+
-+extern const uint32_t crc32_table[256];
-+
-+/* Return a 32-bit CRC of the contents of the buffer. */
-+
-+static inline uint32_t
-+crc32(uint32_t val, const void *ss, int len)
-+{
-+ const unsigned char *s = ss;
-+ while (--len >= 0)
-+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
-+ return val;
-+}
-+
-+#endif
-diff -Nurb linux-mips-2.4.27/fs/jffs2/dir.c linux/fs/jffs2/dir.c
---- linux-mips-2.4.27/fs/jffs2/dir.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/dir.c 2004-11-19 10:25:12.097169696 +0100
-@@ -1,84 +1,73 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
-+#include <linux/sched.h>
- #include <linux/fs.h>
--#include <linux/mtd/compatmac.h> /* For completion */
-+#include <linux/crc32.h>
- #include <linux/jffs2.h>
- #include <linux/jffs2_fs_i.h>
- #include <linux/jffs2_fs_sb.h>
-+#include <linux/time.h>
- #include "nodelist.h"
--#include <linux/crc32.h>
-+
-+/* Urgh. Please tell me there's a nicer way of doing these. */
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
-+typedef int mknod_arg_t;
-+#define NAMEI_COMPAT(x) ((void *)x)
-+#else
-+typedef dev_t mknod_arg_t;
-+#define NAMEI_COMPAT(x) (x)
-+#endif
-
- static int jffs2_readdir (struct file *, void *, filldir_t);
-
--static int jffs2_create (struct inode *,struct dentry *,int);
--static struct dentry *jffs2_lookup (struct inode *,struct dentry *);
-+static int jffs2_create (struct inode *,struct dentry *,int,
-+ struct nameidata *);
-+static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
-+ struct nameidata *);
- static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
- static int jffs2_unlink (struct inode *,struct dentry *);
- static int jffs2_symlink (struct inode *,struct dentry *,const char *);
- static int jffs2_mkdir (struct inode *,struct dentry *,int);
- static int jffs2_rmdir (struct inode *,struct dentry *);
--static int jffs2_mknod (struct inode *,struct dentry *,int,int);
-+static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t);
- static int jffs2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
-
- struct file_operations jffs2_dir_operations =
- {
-- read: generic_read_dir,
-- readdir: jffs2_readdir,
-- ioctl: jffs2_ioctl,
-- fsync: jffs2_null_fsync
-+ .read = generic_read_dir,
-+ .readdir = jffs2_readdir,
-+ .ioctl = jffs2_ioctl,
-+ .fsync = jffs2_fsync
- };
-
-
- struct inode_operations jffs2_dir_inode_operations =
- {
-- create: jffs2_create,
-- lookup: jffs2_lookup,
-- link: jffs2_link,
-- unlink: jffs2_unlink,
-- symlink: jffs2_symlink,
-- mkdir: jffs2_mkdir,
-- rmdir: jffs2_rmdir,
-- mknod: jffs2_mknod,
-- rename: jffs2_rename,
-- setattr: jffs2_setattr,
-+ .create = NAMEI_COMPAT(jffs2_create),
-+ .lookup = NAMEI_COMPAT(jffs2_lookup),
-+ .link = jffs2_link,
-+ .unlink = jffs2_unlink,
-+ .symlink = jffs2_symlink,
-+ .mkdir = jffs2_mkdir,
-+ .rmdir = jffs2_rmdir,
-+ .mknod = jffs2_mknod,
-+ .rename = jffs2_rename,
-+ .setattr = jffs2_setattr,
- };
-
- /***********************************************************************/
-@@ -88,12 +77,13 @@
- and we use the same hash function as the dentries. Makes this
- nice and simple
- */
--static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target)
-+static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
-+ struct nameidata *nd)
- {
- struct jffs2_inode_info *dir_f;
- struct jffs2_sb_info *c;
- struct jffs2_full_dirent *fd = NULL, *fd_list;
-- __u32 ino = 0;
-+ uint32_t ino = 0;
- struct inode *inode = NULL;
-
- D1(printk(KERN_DEBUG "jffs2_lookup()\n"));
-@@ -153,8 +143,9 @@
- offset++;
- }
- if (offset == 1) {
-- D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", filp->f_dentry->d_parent->d_inode->i_ino));
-- if (filldir(dirent, "..", 2, 1, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
-+ unsigned long pino = parent_ino(filp->f_dentry);
-+ D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino));
-+ if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
- goto out;
- offset++;
- }
-@@ -188,18 +179,14 @@
-
- /***********************************************************************/
-
--static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
-+
-+static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
-+ struct nameidata *nd)
- {
-+ struct jffs2_raw_inode *ri;
- struct jffs2_inode_info *f, *dir_f;
- struct jffs2_sb_info *c;
- struct inode *inode;
-- struct jffs2_raw_inode *ri;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dnode *fn;
-- struct jffs2_full_dirent *fd;
-- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
- int ret;
-
- ri = jffs2_alloc_raw_inode();
-@@ -210,23 +197,11 @@
-
- D1(printk(KERN_DEBUG "jffs2_create()\n"));
-
-- /* Try to reserve enough space for both node and dirent.
-- * Just the node will do for now, though
-- */
-- namelen = dentry->d_name.len;
-- ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
-- D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen));
-- if (ret) {
-- jffs2_free_raw_inode(ri);
-- return ret;
-- }
--
- inode = jffs2_new_inode(dir_i, mode, ri);
-
- if (IS_ERR(inode)) {
- D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
- jffs2_free_raw_inode(ri);
-- jffs2_complete_reservation(c);
- return PTR_ERR(inode);
- }
-
-@@ -236,93 +211,22 @@
- inode->i_mapping->nrpages = 0;
-
- f = JFFS2_INODE_INFO(inode);
-+ dir_f = JFFS2_INODE_INFO(dir_i);
-
-- ri->data_crc = 0;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
--
-- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen);
-- D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode));
-- jffs2_free_raw_inode(ri);
--
-- if (IS_ERR(fn)) {
-- D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
-- /* Eeek. Wave bye bye */
-- up(&f->sem);
-- jffs2_complete_reservation(c);
-- jffs2_clear_inode(inode);
-- return PTR_ERR(fn);
-- }
-- /* No data here. Only a metadata node, which will be
-- obsoleted by the first data write
-- */
-- f->metadata = fn;
--
-- /* Work out where to put the dirent node now. */
-- writtenlen = PAD(writtenlen);
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
-- up(&f->sem);
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
-- jffs2_complete_reservation(c);
-- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ ret = jffs2_do_create(c, dir_f, f, ri,
-+ dentry->d_name.name, dentry->d_name.len);
-
- if (ret) {
-- /* Eep. */
-- D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
- jffs2_clear_inode(inode);
-+ make_bad_inode(inode);
-+ iput(inode);
-+ jffs2_free_raw_inode(ri);
- return ret;
- }
-- }
-
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd) {
-- /* Argh. Now we treat it like a normal delete */
-- jffs2_complete_reservation(c);
-- jffs2_clear_inode(inode);
-- return -ENOMEM;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = namelen;
-- rd->type = DT_REG;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
--
-- jffs2_complete_reservation(c);
--
-- if (IS_ERR(fd)) {
-- /* dirent failed to write. Delete the inode normally
-- as if it were the final unlink() */
-- jffs2_free_raw_dirent(rd);
-- up(&dir_f->sem);
-- jffs2_clear_inode(inode);
-- return PTR_ERR(fd);
-- }
--
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
--
-- jffs2_free_raw_dirent(rd);
--
-- /* Link the fd into the inode's list, obsoleting an old
-- one if necessary. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-
-+ jffs2_free_raw_inode(ri);
- d_instantiate(dentry, inode);
-
- D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
-@@ -332,173 +236,48 @@
-
- /***********************************************************************/
-
--static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename)
--{
-- struct jffs2_inode_info *dir_f, *f;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dirent *fd;
-- __u32 alloclen, phys_ofs;
-- int ret;
--
-- c = JFFS2_SB_INFO(dir_i->i_sb);
--
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd)
-- return -ENOMEM;
--
-- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION);
-- if (ret) {
-- jffs2_free_raw_dirent(rd);
-- return ret;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- /* Build a deletion node */
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + dentry->d_name.len;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = 0;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = dentry->d_name.len;
-- rd->type = DT_UNKNOWN;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL);
--
-- jffs2_complete_reservation(c);
-- jffs2_free_raw_dirent(rd);
--
-- if (IS_ERR(fd)) {
-- up(&dir_f->sem);
-- return PTR_ERR(fd);
-- }
--
-- /* File it. This will mark the old one obsolete. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
--
-- if (!rename) {
-- f = JFFS2_INODE_INFO(dentry->d_inode);
-- down(&f->sem);
--
-- while (f->dents) {
-- /* There can be only deleted ones */
-- fd = f->dents;
--
-- f->dents = fd->next;
--
-- if (fd->ino) {
-- printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-- f->inocache->ino, fd->name, fd->ino);
-- } else {
-- D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino));
-- }
-- jffs2_mark_node_obsolete(c, fd->raw);
-- jffs2_free_full_dirent(fd);
-- }
-- /* Don't oops on unlinking a bad inode */
-- if (f->inocache)
-- f->inocache->nlink--;
-- dentry->d_inode->i_nlink--;
-- up(&f->sem);
-- }
--
-- return 0;
--}
-
- static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
- {
-- return jffs2_do_unlink(dir_i, dentry, 0);
--}
--/***********************************************************************/
--
--static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename)
--{
-- struct jffs2_inode_info *dir_f, *f;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_dirent *rd;
-- struct jffs2_full_dirent *fd;
-- __u32 alloclen, phys_ofs;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
-+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
-+ struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode);
- int ret;
-
-- c = JFFS2_SB_INFO(dir_i->i_sb);
--
-- rd = jffs2_alloc_raw_dirent();
-- if (!rd)
-- return -ENOMEM;
--
-- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- jffs2_free_raw_dirent(rd);
-+ ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
-+ dentry->d_name.len, dead_f);
-+ if (dead_f->inocache)
-+ dentry->d_inode->i_nlink = dead_f->inocache->nlink;
- return ret;
-- }
--
-- dir_f = JFFS2_INODE_INFO(dir_i);
-- down(&dir_f->sem);
--
-- /* Build a deletion node */
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + dentry->d_name.len;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = old_dentry->d_inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-- rd->nsize = dentry->d_name.len;
--
-- /* XXX: This is ugly. */
-- rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-- if (!rd->type) rd->type = DT_REG;
--
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL);
--
-- jffs2_complete_reservation(c);
-- jffs2_free_raw_dirent(rd);
--
-- if (IS_ERR(fd)) {
-- up(&dir_f->sem);
-- return PTR_ERR(fd);
-- }
--
-- /* File it. This will mark the old one obsolete. */
-- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-- up(&dir_f->sem);
--
-- if (!rename) {
-- f = JFFS2_INODE_INFO(old_dentry->d_inode);
-- down(&f->sem);
-- old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
-- up(&f->sem);
-- }
-- return 0;
- }
-+/***********************************************************************/
-+
-
- static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
- {
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb);
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
-+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
- int ret;
-+ uint8_t type;
-
-- /* Can't link a bad inode. */
-- if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache)
-+ /* Don't let people make hard links to bad inodes. */
-+ if (!f->inocache)
- return -EIO;
-
- if (S_ISDIR(old_dentry->d_inode->i_mode))
- return -EPERM;
-
-- ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
-+ /* XXX: This is ugly */
-+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-+ if (!type) type = DT_REG;
-+
-+ ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len);
-+
- if (!ret) {
-+ down(&f->sem);
-+ old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
-+ up(&f->sem);
- d_instantiate(dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
- }
-@@ -517,8 +296,7 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
- /* FIXME: If you care. We'd need to use frags for the target
-@@ -556,15 +334,16 @@
-
- f = JFFS2_INODE_INFO(inode);
-
-- inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target);
-- ri->totlen = sizeof(*ri) + ri->dsize;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-+ inode->i_size = strlen(target);
-+ ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
- ri->compr = JFFS2_COMPR_NONE;
-- ri->data_crc = crc32(0, target, strlen(target));
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -581,13 +360,6 @@
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = (writtenlen+3)&~3;
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -595,7 +367,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -608,41 +379,42 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
- rd->type = DT_LNK;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
--
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
- return 0;
-@@ -659,8 +431,7 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
- mode |= S_IFDIR;
-@@ -692,13 +463,15 @@
-
- inode->i_op = &jffs2_dir_inode_operations;
- inode->i_fop = &jffs2_dir_operations;
-+ /* Directories get nlink 2 at start */
-+ inode->i_nlink = 2;
-
- f = JFFS2_INODE_INFO(inode);
-
-- ri->data_crc = 0;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(0);
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -715,13 +488,6 @@
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = PAD(writtenlen);
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -729,7 +495,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -742,41 +507,43 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
- rd->type = DT_DIR;
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
--
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-+ dir_i->i_nlink++;
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
- return 0;
-@@ -786,15 +553,19 @@
- {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
- struct jffs2_full_dirent *fd;
-+ int ret;
-
- for (fd = f->dents ; fd; fd = fd->next) {
- if (fd->ino)
- return -ENOTEMPTY;
- }
-- return jffs2_unlink(dir_i, dentry);
-+ ret = jffs2_unlink(dir_i, dentry);
-+ if (!ret)
-+ dir_i->i_nlink--;
-+ return ret;
- }
-
--static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
-+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev)
- {
- struct jffs2_inode_info *f, *dir_f;
- struct jffs2_sb_info *c;
-@@ -804,12 +575,14 @@
- struct jffs2_full_dnode *fn;
- struct jffs2_full_dirent *fd;
- int namelen;
-- unsigned short dev;
-+ jint16_t dev;
- int devlen = 0;
-- __u32 alloclen, phys_ofs;
-- __u32 writtenlen;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-+ if (!old_valid_dev(rdev))
-+ return -EINVAL;
-+
- ri = jffs2_alloc_raw_inode();
- if (!ri)
- return -ENOMEM;
-@@ -817,7 +590,7 @@
- c = JFFS2_SB_INFO(dir_i->i_sb);
-
- if (S_ISBLK(mode) || S_ISCHR(mode)) {
-- dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev));
-+ dev = cpu_to_je16(old_encode_dev(rdev));
- devlen = sizeof(dev);
- }
-
-@@ -844,15 +617,15 @@
-
- f = JFFS2_INODE_INFO(inode);
-
-- ri->dsize = ri->csize = devlen;
-- ri->totlen = sizeof(*ri) + ri->csize;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-+ ri->dsize = ri->csize = cpu_to_je32(devlen);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
- ri->compr = JFFS2_COMPR_NONE;
-- ri->data_crc = crc32(0, &dev, devlen);
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-+ ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-
-- fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen);
-+ fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL);
-
- jffs2_free_raw_inode(ri);
-
-@@ -869,13 +642,6 @@
- f->metadata = fn;
- up(&f->sem);
-
-- /* Work out where to put the dirent node now. */
-- writtenlen = (writtenlen+3)&~3;
-- phys_ofs += writtenlen;
-- alloclen -= writtenlen;
--
-- if (alloclen < sizeof(*rd)+namelen) {
-- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
-@@ -883,7 +649,6 @@
- jffs2_clear_inode(inode);
- return ret;
- }
-- }
-
- rd = jffs2_alloc_raw_dirent();
- if (!rd) {
-@@ -896,44 +661,45 @@
- dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
-
-- rd->magic = JFFS2_MAGIC_BITMASK;
-- rd->nodetype = JFFS2_NODETYPE_DIRENT;
-- rd->totlen = sizeof(*rd) + namelen;
-- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
--
-- rd->pino = dir_i->i_ino;
-- rd->version = ++dir_f->highest_version;
-- rd->ino = inode->i_ino;
-- rd->mctime = CURRENT_TIME;
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_i->i_ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(inode->i_ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
-
- /* XXX: This is ugly. */
- rd->type = (mode & S_IFMT) >> 12;
-
-- rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
-- rd->name_crc = crc32(0, dentry->d_name.name, namelen);
--
-- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
-
-- jffs2_complete_reservation(c);
-+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-
- if (IS_ERR(fd)) {
- /* dirent failed to write. Delete the inode normally
- as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
- }
-
-- dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
-+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-
- jffs2_free_raw_dirent(rd);
-
- /* Link the fd into the inode's list, obsoleting an old
- one if necessary. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
- up(&dir_f->sem);
-+ jffs2_complete_reservation(c);
-
- d_instantiate(dentry, inode);
-
-@@ -944,7 +710,9 @@
- struct inode *new_dir_i, struct dentry *new_dentry)
- {
- int ret;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
- struct jffs2_inode_info *victim_f = NULL;
-+ uint8_t type;
-
- /* The VFS will check for us and prevent trying to rename a
- * file over a directory and vice versa, but if it's a directory,
-@@ -973,7 +741,15 @@
- */
-
- /* Make a hard link */
-- ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1);
-+
-+ /* XXX: This is ugly */
-+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
-+ if (!type) type = DT_REG;
-+
-+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
-+ old_dentry->d_inode->i_ino, type,
-+ new_dentry->d_name.name, new_dentry->d_name.len);
-+
- if (ret)
- return ret;
-
-@@ -989,22 +765,36 @@
- }
- }
-
-+ /* If it was a directory we moved, and there was no victim,
-+ increase i_nlink on its new parent */
-+ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
-+ new_dir_i->i_nlink++;
-+
- /* Unlink the original */
-- ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
-+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
-+ old_dentry->d_name.name, old_dentry->d_name.len, NULL);
-+
-+ /* We don't touch inode->i_nlink */
-
- if (ret) {
- /* Oh shit. We really ought to make a single node which can do both atomically */
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
- down(&f->sem);
-+ old_dentry->d_inode->i_nlink++;
- if (f->inocache)
-- old_dentry->d_inode->i_nlink = f->inocache->nlink++;
-+ f->inocache->nlink++;
- up(&f->sem);
-
- printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
- /* Might as well let the VFS know */
- d_instantiate(new_dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
-- }
- return ret;
-+ }
-+
-+ if (S_ISDIR(old_dentry->d_inode->i_mode))
-+ old_dir_i->i_nlink--;
-+
-+ return 0;
- }
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/erase.c linux/fs/jffs2/erase.c
---- linux-mips-2.4.27/fs/jffs2/erase.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/erase.c 2004-11-19 10:25:12.099169392 +0100
-@@ -1,68 +1,60 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-+
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/mtd/mtd.h>
--#include <linux/jffs2.h>
--#include <linux/interrupt.h>
--#include "nodelist.h"
-+#include <linux/compiler.h>
- #include <linux/crc32.h>
-+#include <linux/sched.h>
-+#include <linux/pagemap.h>
-+#include "nodelist.h"
-
- struct erase_priv_struct {
- struct jffs2_eraseblock *jeb;
- struct jffs2_sb_info *c;
- };
-
-+#ifndef __ECOS
- static void jffs2_erase_callback(struct erase_info *);
-+#endif
-+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
- static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-
- void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
- {
-- struct erase_info *instr;
- int ret;
-+#ifdef __ECOS
-+ ret = jffs2_flash_erase(c, jeb);
-+ if (!ret) {
-+ jffs2_erase_succeeded(c, jeb);
-+ return;
-+ }
-+#else /* Linux */
-+ struct erase_info *instr;
-
- instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
- if (!instr) {
- printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- list_del(&jeb->list);
- list_add(&jeb->list, &c->erase_pending_list);
- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-+ c->dirty_size += c->sector_size;
-+ jeb->dirty_size = c->sector_size;
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
-
-@@ -77,19 +69,27 @@
- ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
- ((struct erase_priv_struct *)instr->priv)->c = c;
-
-+ /* NAND , read out the fail counter, if possible */
-+ if (!jffs2_can_mark_obsolete(c))
-+ jffs2_nand_read_failcnt(c,jeb);
-+
- ret = c->mtd->erase(c->mtd, instr);
-- if (!ret) {
-+ if (!ret)
- return;
-- }
-+
-+ kfree(instr);
-+#endif /* __ECOS */
-+
- if (ret == -ENOMEM || ret == -EAGAIN) {
- /* Erase failed immediately. Refile it on the list */
- D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- list_del(&jeb->list);
- list_add(&jeb->list, &c->erase_pending_list);
- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-- kfree(instr);
-+ c->dirty_size += c->sector_size;
-+ jeb->dirty_size = c->sector_size;
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
-
-@@ -97,74 +97,101 @@
- printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
- else
- printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
-- spin_lock_bh(&c->erase_completion_lock);
-- list_del(&jeb->list);
-- list_add(&jeb->list, &c->bad_list);
-- c->nr_erasing_blocks--;
-- c->bad_size += c->sector_size;
-- c->erasing_size -= c->sector_size;
-- spin_unlock_bh(&c->erase_completion_lock);
-- wake_up(&c->erase_wait);
-- kfree(instr);
-+
-+ jffs2_erase_failed(c, jeb);
- }
-
--void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
-+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
- {
- struct jffs2_eraseblock *jeb;
-
-- spin_lock_bh(&c->erase_completion_lock);
-- while (!list_empty(&c->erase_pending_list)) {
-+ down(&c->erase_free_sem);
-
-- jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
-+ spin_lock(&c->erase_completion_lock);
-
-- D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
-+ while (!list_empty(&c->erase_complete_list) ||
-+ !list_empty(&c->erase_pending_list)) {
-
-+ if (!list_empty(&c->erase_complete_list)) {
-+ jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
-+ list_del(&jeb->list);
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_mark_erased_block(c, jeb);
-+
-+ if (!--count) {
-+ D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n"));
-+ goto done;
-+ }
-+
-+ } else if (!list_empty(&c->erase_pending_list)) {
-+ jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
-+ D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
- list_del(&jeb->list);
- c->erasing_size += c->sector_size;
-+ c->wasted_size -= jeb->wasted_size;
- c->free_size -= jeb->free_size;
- c->used_size -= jeb->used_size;
- c->dirty_size -= jeb->dirty_size;
-- jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
-+ jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
- jffs2_free_all_node_refs(c, jeb);
- list_add(&jeb->list, &c->erasing_list);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
-
- jffs2_erase_block(c, jeb);
-+
-+ } else {
-+ BUG();
-+ }
-+
- /* Be nice */
-- if (current->need_resched)
-- schedule();
-- spin_lock_bh(&c->erase_completion_lock);
-+ cond_resched();
-+ spin_lock(&c->erase_completion_lock);
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ done:
- D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
-+
-+ up(&c->erase_free_sem);
-+}
-+
-+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
-+ spin_lock(&c->erase_completion_lock);
-+ list_del(&jeb->list);
-+ list_add_tail(&jeb->list, &c->erase_complete_list);
-+ spin_unlock(&c->erase_completion_lock);
-+ /* Ensure that kupdated calls us again to mark them clean */
-+ jffs2_erase_pending_trigger(c);
- }
-
-+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ spin_lock(&c->erase_completion_lock);
-+ c->erasing_size -= c->sector_size;
-+ c->bad_size += c->sector_size;
-+ list_del(&jeb->list);
-+ list_add(&jeb->list, &c->bad_list);
-+ c->nr_erasing_blocks--;
-+ spin_unlock(&c->erase_completion_lock);
-+ wake_up(&c->erase_wait);
-+}
-
-+#ifndef __ECOS
- static void jffs2_erase_callback(struct erase_info *instr)
- {
- struct erase_priv_struct *priv = (void *)instr->priv;
-
- if(instr->state != MTD_ERASE_DONE) {
- printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
-- spin_lock(&priv->c->erase_completion_lock);
-- priv->c->erasing_size -= priv->c->sector_size;
-- priv->c->bad_size += priv->c->sector_size;
-- list_del(&priv->jeb->list);
-- list_add(&priv->jeb->list, &priv->c->bad_list);
-- priv->c->nr_erasing_blocks--;
-- spin_unlock(&priv->c->erase_completion_lock);
-- wake_up(&priv->c->erase_wait);
-+ jffs2_erase_failed(priv->c, priv->jeb);
- } else {
-- D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", instr->addr));
-- spin_lock(&priv->c->erase_completion_lock);
-- list_del(&priv->jeb->list);
-- list_add_tail(&priv->jeb->list, &priv->c->erase_complete_list);
-- spin_unlock(&priv->c->erase_completion_lock);
-+ jffs2_erase_succeeded(priv->c, priv->jeb);
- }
-- /* Make sure someone picks up the block off the erase_complete list */
-- OFNI_BS_2SFFJ(priv->c)->s_dirt = 1;
- kfree(instr);
- }
-+#endif /* !__ECOS */
-
- /* Hmmm. Maybe we should accept the extra space it takes and make
- this a standard doubly-linked list? */
-@@ -221,7 +248,7 @@
- this = ic->nodes;
-
- while(this) {
-- printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3);
-+ printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
- if (++i == 5) {
- printk("\n" KERN_DEBUG);
- i=0;
-@@ -256,54 +283,43 @@
- jeb->last_node = NULL;
- }
-
--void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
- {
-- OFNI_BS_2SFFJ(c)->s_dirt = 1;
--}
--
--void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
--{
-- static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)};
-- struct jffs2_eraseblock *jeb;
-- struct jffs2_raw_node_ref *marker_ref;
-+ struct jffs2_raw_node_ref *marker_ref = NULL;
- unsigned char *ebuf;
-- ssize_t retlen;
-+ size_t retlen;
- int ret;
-
-- marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4);
--
-- spin_lock_bh(&c->erase_completion_lock);
-- while (!list_empty(&c->erase_complete_list)) {
-- jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
-- list_del(&jeb->list);
-- spin_unlock_bh(&c->erase_completion_lock);
--
-+ if (!jffs2_cleanmarker_oob(c)) {
- marker_ref = jffs2_alloc_raw_node_ref();
- if (!marker_ref) {
- printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
-- /* Come back later */
-+ /* Stick it back on the list from whence it came and come back later */
- jffs2_erase_pending_trigger(c);
-+ spin_lock(&c->erase_completion_lock);
-+ list_add(&jeb->list, &c->erase_complete_list);
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
--
-+ }
- ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!ebuf) {
- printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset);
- } else {
-- __u32 ofs = jeb->offset;
-+ uint32_t ofs = jeb->offset;
-
- D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
- while(ofs < jeb->offset + c->sector_size) {
-- __u32 readlen = min((__u32)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
-+ uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
- int i;
-
-- ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
-- if (ret < 0) {
-+ ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
-+ if (ret) {
- printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
- goto bad;
- }
- if (retlen != readlen) {
-- printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen);
-+ printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
- goto bad;
- }
- for (i=0; i<readlen; i += sizeof(unsigned long)) {
-@@ -312,62 +328,89 @@
- if (datum + 1) {
- printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
- bad:
-+ if (!jffs2_cleanmarker_oob(c))
- jffs2_free_raw_node_ref(marker_ref);
-+ else
-+ jffs2_write_nand_badblock( c ,jeb );
- kfree(ebuf);
- bad2:
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- c->erasing_size -= c->sector_size;
- c->bad_size += c->sector_size;
-
- list_add_tail(&jeb->list, &c->bad_list);
- c->nr_erasing_blocks--;
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- wake_up(&c->erase_wait);
- return;
- }
- }
- ofs += readlen;
-+ cond_resched();
- }
- kfree(ebuf);
- }
-
- /* Write the erase complete marker */
- D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
-- ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
-+ if (jffs2_cleanmarker_oob(c)) {
-+
-+ if (jffs2_write_nand_cleanmarker(c, jeb))
-+ goto bad2;
-+
-+ jeb->first_node = jeb->last_node = NULL;
-+
-+ jeb->free_size = c->sector_size;
-+ jeb->used_size = 0;
-+ jeb->dirty_size = 0;
-+ jeb->wasted_size = 0;
-+ } else {
-+ struct jffs2_unknown_node marker = {
-+ .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
-+ .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
-+ .totlen = cpu_to_je32(c->cleanmarker_size)
-+ };
-+
-+ marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
-+
-+ /* We only write the header; the rest was noise or padding anyway */
-+ ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
- if (ret) {
- printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
- jeb->offset, ret);
- goto bad2;
- }
- if (retlen != sizeof(marker)) {
-- printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n",
-+ printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n",
- jeb->offset, sizeof(marker), retlen);
- goto bad2;
- }
-
- marker_ref->next_in_ino = NULL;
- marker_ref->next_phys = NULL;
-- marker_ref->flash_offset = jeb->offset;
-- marker_ref->totlen = PAD(sizeof(marker));
-+ marker_ref->flash_offset = jeb->offset | REF_NORMAL;
-+ marker_ref->__totlen = c->cleanmarker_size;
-
- jeb->first_node = jeb->last_node = marker_ref;
-
-- jeb->free_size = c->sector_size - marker_ref->totlen;
-- jeb->used_size = marker_ref->totlen;
-+ jeb->free_size = c->sector_size - c->cleanmarker_size;
-+ jeb->used_size = c->cleanmarker_size;
- jeb->dirty_size = 0;
-+ jeb->wasted_size = 0;
-+ }
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- c->erasing_size -= c->sector_size;
- c->free_size += jeb->free_size;
- c->used_size += jeb->used_size;
-
- ACCT_SANITY_CHECK(c,jeb);
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-
- list_add_tail(&jeb->list, &c->free_list);
- c->nr_erasing_blocks--;
- c->nr_free_blocks++;
-+ spin_unlock(&c->erase_completion_lock);
- wake_up(&c->erase_wait);
-- }
-- spin_unlock_bh(&c->erase_completion_lock);
- }
-+
-diff -Nurb linux-mips-2.4.27/fs/jffs2/file.c linux/fs/jffs2/file.c
---- linux-mips-2.4.27/fs/jffs2/file.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/file.c 2004-11-19 10:25:12.101169088 +0100
-@@ -1,319 +1,106 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-+#include <linux/version.h>
- #include <linux/kernel.h>
--#include <linux/mtd/compatmac.h> /* for min() */
- #include <linux/slab.h>
- #include <linux/fs.h>
-+#include <linux/time.h>
- #include <linux/pagemap.h>
-+#include <linux/highmem.h>
-+#include <linux/crc32.h>
- #include <linux/jffs2.h>
- #include "nodelist.h"
--#include <linux/crc32.h>
-
- extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
- extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
-
-
--int jffs2_null_fsync(struct file *filp, struct dentry *dentry, int datasync)
-+int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
- {
-- /* Move along. Nothing to see here */
-+ struct inode *inode = dentry->d_inode;
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+
-+ /* Trigger GC to flush any pending writes for this inode */
-+ jffs2_flush_wbuf_gc(c, inode->i_ino);
-+
- return 0;
- }
-
- struct file_operations jffs2_file_operations =
- {
-- llseek: generic_file_llseek,
-- open: generic_file_open,
-- read: generic_file_read,
-- write: generic_file_write,
-- ioctl: jffs2_ioctl,
-- mmap: generic_file_mmap,
-- fsync: jffs2_null_fsync
-+ .llseek = generic_file_llseek,
-+ .open = generic_file_open,
-+ .read = generic_file_read,
-+ .write = generic_file_write,
-+ .ioctl = jffs2_ioctl,
-+ .mmap = generic_file_readonly_mmap,
-+ .fsync = jffs2_fsync,
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29)
-+ .sendfile = generic_file_sendfile
-+#endif
- };
-
- /* jffs2_file_inode_operations */
-
- struct inode_operations jffs2_file_inode_operations =
- {
-- setattr: jffs2_setattr
-+ .setattr = jffs2_setattr
- };
-
- struct address_space_operations jffs2_file_address_operations =
- {
-- readpage: jffs2_readpage,
-- prepare_write: jffs2_prepare_write,
-- commit_write: jffs2_commit_write
-+ .readpage = jffs2_readpage,
-+ .prepare_write =jffs2_prepare_write,
-+ .commit_write = jffs2_commit_write
- };
-
--int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
--{
-- struct jffs2_full_dnode *old_metadata, *new_metadata;
-- struct inode *inode = dentry->d_inode;
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_raw_inode *ri;
-- unsigned short dev;
-- unsigned char *mdata = NULL;
-- int mdatalen = 0;
-- unsigned int ivalid;
-- __u32 phys_ofs, alloclen;
-- int ret;
-- D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-- ret = inode_change_ok(inode, iattr);
-- if (ret)
-- return ret;
--
-- /* Special cases - we don't want more than one data node
-- for these types on the medium at any time. So setattr
-- must read the original data associated with the node
-- (i.e. the device numbers or the target name) and write
-- it out again with the appropriate data attached */
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-- /* For these, we don't actually need to read the old node */
-- dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) |
-- MINOR(to_kdev_t(dentry->d_inode->i_rdev));
-- mdata = (char *)&dev;
-- mdatalen = sizeof(dev);
-- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-- } else if (S_ISLNK(inode->i_mode)) {
-- mdatalen = f->metadata->size;
-- mdata = kmalloc(f->metadata->size, GFP_USER);
-- if (!mdata)
-- return -ENOMEM;
-- ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
-- if (ret) {
-- kfree(mdata);
-- return ret;
-- }
-- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
-- }
--
-- ri = jffs2_alloc_raw_inode();
-- if (!ri) {
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
-- return -ENOMEM;
-- }
--
-- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- jffs2_free_raw_inode(ri);
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
-- return ret;
-- }
-- down(&f->sem);
-- ivalid = iattr->ia_valid;
--
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = sizeof(*ri) + mdatalen;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri->ino = inode->i_ino;
-- ri->version = ++f->highest_version;
--
-- ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode;
-- ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid;
-- ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid;
--
-- if (ivalid & ATTR_MODE && ri->mode & S_ISGID &&
-- !in_group_p(ri->gid) && !capable(CAP_FSETID))
-- ri->mode &= ~S_ISGID;
--
-- ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size;
-- ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime;
-- ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime;
-- ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime;
--
-- ri->offset = 0;
-- ri->csize = ri->dsize = mdatalen;
-- ri->compr = JFFS2_COMPR_NONE;
-- if (inode->i_size < ri->isize) {
-- /* It's an extension. Make it a hole node */
-- ri->compr = JFFS2_COMPR_ZERO;
-- ri->dsize = ri->isize - inode->i_size;
-- ri->offset = inode->i_size;
-- }
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-- if (mdatalen)
-- ri->data_crc = crc32(0, mdata, mdatalen);
-- else
-- ri->data_crc = 0;
--
-- new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL);
-- if (S_ISLNK(inode->i_mode))
-- kfree(mdata);
--
-- jffs2_complete_reservation(c);
--
-- if (IS_ERR(new_metadata)) {
-- jffs2_free_raw_inode(ri);
-- up(&f->sem);
-- return PTR_ERR(new_metadata);
-- }
-- /* It worked. Update the inode */
-- inode->i_atime = ri->atime;
-- inode->i_ctime = ri->ctime;
-- inode->i_mtime = ri->mtime;
-- inode->i_mode = ri->mode;
-- inode->i_uid = ri->uid;
-- inode->i_gid = ri->gid;
--
--
-- old_metadata = f->metadata;
--
-- if (inode->i_size > ri->isize) {
-- vmtruncate(inode, ri->isize);
-- jffs2_truncate_fraglist (c, &f->fraglist, ri->isize);
-- }
--
-- if (inode->i_size < ri->isize) {
-- jffs2_add_full_dnode_to_inode(c, f, new_metadata);
-- inode->i_size = ri->isize;
-- f->metadata = NULL;
-- } else {
-- f->metadata = new_metadata;
-- }
-- if (old_metadata) {
-- jffs2_mark_node_obsolete(c, old_metadata->raw);
-- jffs2_free_full_dnode(old_metadata);
-- }
-- jffs2_free_raw_inode(ri);
-- up(&f->sem);
-- return 0;
--}
--
- int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
- {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_node_frag *frag = f->fraglist;
-- __u32 offset = pg->index << PAGE_CACHE_SHIFT;
-- __u32 end = offset + PAGE_CACHE_SIZE;
- unsigned char *pg_buf;
- int ret;
-
-- D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%x\n", inode->i_ino, offset));
-+ D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
-
- if (!PageLocked(pg))
- PAGE_BUG(pg);
-
-- while(frag && frag->ofs + frag->size <= offset) {
-- // D1(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size));
-- frag = frag->next;
-- }
--
- pg_buf = kmap(pg);
-+ /* FIXME: Can kmap fail? */
-
-- /* XXX FIXME: Where a single physical node actually shows up in two
-- frags, we read it twice. Don't do that. */
-- /* Now we're pointing at the first frag which overlaps our page */
-- while(offset < end) {
-- D2(printk(KERN_DEBUG "jffs2_readpage: offset %d, end %d\n", offset, end));
-- if (!frag || frag->ofs > offset) {
-- __u32 holesize = end - offset;
-- if (frag) {
-- D1(printk(KERN_NOTICE "Eep. Hole in ino %ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", inode->i_ino, frag->ofs, offset));
-- holesize = min(holesize, frag->ofs - offset);
-- D1(jffs2_print_frag_list(f));
-- }
-- D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
-- memset(pg_buf, 0, holesize);
-- pg_buf += holesize;
-- offset += holesize;
-- continue;
-- } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) {
-- D1(printk(KERN_NOTICE "Eep. Overlap in ino #%ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
-- inode->i_ino, frag->ofs, offset));
-- D1(jffs2_print_frag_list(f));
-- memset(pg_buf, 0, end - offset);
-- ClearPageUptodate(pg);
-- SetPageError(pg);
-- kunmap(pg);
-- return -EIO;
-- } else if (!frag->node) {
-- __u32 holeend = min(end, frag->ofs + frag->size);
-- D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
-- memset(pg_buf, 0, holeend - offset);
-- pg_buf += holeend - offset;
-- offset = holeend;
-- frag = frag->next;
-- continue;
-- } else {
-- __u32 readlen;
-- __u32 fragofs; /* offset within the frag to start reading */
-+ ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
-
-- fragofs = offset - frag->ofs;
-- readlen = min(frag->size - fragofs, end - offset);
-- D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs,
-- fragofs+frag->ofs+readlen, frag->node->raw->flash_offset & ~3));
-- ret = jffs2_read_dnode(c, frag->node, pg_buf, fragofs + frag->ofs - frag->node->ofs, readlen);
-- D2(printk(KERN_DEBUG "node read done\n"));
- if (ret) {
-- D1(printk(KERN_DEBUG"jffs2_readpage error %d\n",ret));
-- memset(pg_buf, 0, readlen);
- ClearPageUptodate(pg);
- SetPageError(pg);
-- kunmap(pg);
-- return ret;
-- }
--
-- pg_buf += readlen;
-- offset += readlen;
-- frag = frag->next;
-- D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
-- }
-- }
-- D2(printk(KERN_DEBUG "readpage finishing\n"));
-+ } else {
- SetPageUptodate(pg);
- ClearPageError(pg);
-+ }
-
- flush_dcache_page(pg);
--
- kunmap(pg);
-- D1(printk(KERN_DEBUG "readpage finished\n"));
-+
-+ D2(printk(KERN_DEBUG "readpage finished\n"));
- return 0;
- }
-
- int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
- {
- int ret = jffs2_do_readpage_nolock(inode, pg);
-- UnlockPage(pg);
-+ unlock_page(pg);
- return ret;
- }
-
-@@ -333,17 +120,17 @@
- {
- struct inode *inode = pg->mapping->host;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-- __u32 pageofs = pg->index << PAGE_CACHE_SHIFT;
-+ uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT;
- int ret = 0;
-
-- D1(printk(KERN_DEBUG "jffs2_prepare_write() nrpages %ld\n", inode->i_mapping->nrpages));
-+ D1(printk(KERN_DEBUG "jffs2_prepare_write()\n"));
-
- if (pageofs > inode->i_size) {
- /* Make new hole frag from old EOF to new page */
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- struct jffs2_raw_inode ri;
- struct jffs2_full_dnode *fn;
-- __u32 phys_ofs, alloc_len;
-+ uint32_t phys_ofs, alloc_len;
-
- D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
- (unsigned int)inode->i_size, pageofs));
-@@ -355,29 +142,30 @@
- down(&f->sem);
- memset(&ri, 0, sizeof(ri));
-
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri);
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri.ino = f->inocache->ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = max((__u32)inode->i_size, pageofs);
-- ri.atime = ri.ctime = ri.mtime = CURRENT_TIME;
-- ri.offset = inode->i_size;
-- ri.dsize = pageofs - inode->i_size;
-- ri.csize = 0;
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri));
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(inode->i_mode);
-+ ri.uid = cpu_to_je16(inode->i_uid);
-+ ri.gid = cpu_to_je16(inode->i_gid);
-+ ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
-+ ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds());
-+ ri.offset = cpu_to_je32(inode->i_size);
-+ ri.dsize = cpu_to_je32(pageofs - inode->i_size);
-+ ri.csize = cpu_to_je32(0);
- ri.compr = JFFS2_COMPR_ZERO;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = 0;
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(0);
-+
-+ fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-
-- fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);
-- jffs2_complete_reservation(c);
- if (IS_ERR(fn)) {
- ret = PTR_ERR(fn);
-+ jffs2_complete_reservation(c);
- up(&f->sem);
- return ret;
- }
-@@ -391,16 +179,17 @@
- D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
- jffs2_mark_node_obsolete(c, fn->raw);
- jffs2_free_full_dnode(fn);
-+ jffs2_complete_reservation(c);
- up(&f->sem);
- return ret;
- }
-+ jffs2_complete_reservation(c);
- inode->i_size = pageofs;
- up(&f->sem);
- }
-
--
- /* Read in the page if it wasn't already present, unless it's a whole page */
-- if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
-+ if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
- down(&f->sem);
- ret = jffs2_do_readpage_nolock(inode, pg);
- up(&f->sem);
-@@ -417,14 +206,12 @@
- struct inode *inode = pg->mapping->host;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- __u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end);
-- __u32 file_ofs = (pg->index << PAGE_CACHE_SHIFT);
-- __u32 writelen = min((__u32)PAGE_CACHE_SIZE, newsize - file_ofs);
- struct jffs2_raw_inode *ri;
- int ret = 0;
-- ssize_t writtenlen = 0;
-+ uint32_t writtenlen = 0;
-
-- D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
-+ D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
-+ inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
-
- if (!start && end == PAGE_CACHE_SIZE) {
- /* We need to avoid deadlock with page_cache_read() in
-@@ -435,109 +222,47 @@
- }
-
- ri = jffs2_alloc_raw_inode();
-- if (!ri)
-- return -ENOMEM;
--
-- while(writelen) {
-- struct jffs2_full_dnode *fn;
-- unsigned char *comprbuf = NULL;
-- unsigned char comprtype = JFFS2_COMPR_NONE;
-- __u32 phys_ofs, alloclen;
-- __u32 datalen, cdatalen;
-
-- D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, file_ofs));
--
-- ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
-- if (ret) {
-- SetPageError(pg);
-- D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
-- break;
-+ if (!ri) {
-+ D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n"));
-+ return -ENOMEM;
- }
-- down(&f->sem);
-- datalen = writelen;
-- cdatalen = min(alloclen - sizeof(*ri), writelen);
--
-- comprbuf = kmalloc(cdatalen, GFP_KERNEL);
-- if (comprbuf) {
-- comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen);
-- }
-- if (comprtype == JFFS2_COMPR_NONE) {
-- /* Either compression failed, or the allocation of comprbuf failed */
-- if (comprbuf)
-- kfree(comprbuf);
-- comprbuf = page_address(pg) + (file_ofs & (PAGE_CACHE_SIZE -1));
-- datalen = cdatalen;
-- }
-- /* Now comprbuf points to the data to be written, be it compressed or not.
-- comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means
-- that the comprbuf doesn't need to be kfree()d.
-- */
--
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = sizeof(*ri) + cdatalen;
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri->ino = inode->i_ino;
-- ri->version = ++f->highest_version;
-- ri->mode = inode->i_mode;
-- ri->uid = inode->i_uid;
-- ri->gid = inode->i_gid;
-- ri->isize = max((__u32)inode->i_size, file_ofs + datalen);
-- ri->atime = ri->ctime = ri->mtime = CURRENT_TIME;
-- ri->offset = file_ofs;
-- ri->csize = cdatalen;
-- ri->dsize = datalen;
-- ri->compr = comprtype;
-- ri->node_crc = crc32(0, ri, sizeof(*ri)-8);
-- ri->data_crc = crc32(0, comprbuf, cdatalen);
--
-- fn = jffs2_write_dnode(inode, ri, comprbuf, cdatalen, phys_ofs, NULL);
-
-- jffs2_complete_reservation(c);
-+ /* Set the fields that the generic jffs2_write_inode_range() code can't find */
-+ ri->ino = cpu_to_je32(inode->i_ino);
-+ ri->mode = cpu_to_jemode(inode->i_mode);
-+ ri->uid = cpu_to_je16(inode->i_uid);
-+ ri->gid = cpu_to_je16(inode->i_gid);
-+ ri->isize = cpu_to_je32((uint32_t)inode->i_size);
-+ ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds());
-+
-+ /* In 2.4, it was already kmapped by generic_file_write(). Doesn't
-+ hurt to do it again. The alternative is ifdefs, which are ugly. */
-+ kmap(pg);
-+
-+ ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start,
-+ (pg->index << PAGE_CACHE_SHIFT) + start,
-+ end - start, &writtenlen);
-
-- if (comprtype != JFFS2_COMPR_NONE)
-- kfree(comprbuf);
-+ kunmap(pg);
-
-- if (IS_ERR(fn)) {
-- ret = PTR_ERR(fn);
-- up(&f->sem);
-- SetPageError(pg);
-- break;
-- }
-- ret = jffs2_add_full_dnode_to_inode(c, f, fn);
-- if (f->metadata) {
-- jffs2_mark_node_obsolete(c, f->metadata->raw);
-- jffs2_free_full_dnode(f->metadata);
-- f->metadata = NULL;
-- }
-- up(&f->sem);
- if (ret) {
-- /* Eep */
-- D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
-- jffs2_mark_node_obsolete(c, fn->raw);
-- jffs2_free_full_dnode(fn);
-+ /* There was an error writing. */
- SetPageError(pg);
-- break;
- }
-- inode->i_size = ri->isize;
-+
-+ if (writtenlen) {
-+ if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
-+ inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
- inode->i_blocks = (inode->i_size + 511) >> 9;
-- inode->i_ctime = inode->i_mtime = ri->ctime;
-- if (!datalen) {
-- printk(KERN_WARNING "Eep. We didn't actually write any bloody data\n");
-- ret = -EIO;
-- SetPageError(pg);
-- break;
-+
-+ inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
- }
-- D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
-- writtenlen += datalen;
-- file_ofs += datalen;
-- writelen -= datalen;
- }
-
- jffs2_free_raw_inode(ri);
-
-- if (writtenlen < end) {
-+ if (start+writtenlen < end) {
- /* generic_file_write has written more to the page cache than we've
- actually written to the medium. Mark the page !Uptodate so that
- it gets reread */
-@@ -545,13 +270,7 @@
- SetPageError(pg);
- ClearPageUptodate(pg);
- }
-- if (writtenlen <= start) {
-- /* We didn't even get to the start of the affected part */
-- ret = ret?ret:-ENOSPC;
-- D1(printk(KERN_DEBUG "jffs2_commit_write(): Only %x bytes written to page. start (%x) not reached, returning %d\n", writtenlen, start, ret));
-- }
-- writtenlen = min(end-start, writtenlen-start);
-
-- D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d. nrpages is %ld\n",writtenlen?writtenlen:ret, inode->i_mapping->nrpages));
-+ D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret));
- return writtenlen?writtenlen:ret;
- }
-diff -Nurb linux-mips-2.4.27/fs/jffs2/fs.c linux/fs/jffs2/fs.c
---- linux-mips-2.4.27/fs/jffs2/fs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/fs.c 2004-11-19 10:25:12.102168936 +0100
-@@ -0,0 +1,618 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@redhat.com>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/list.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/pagemap.h>
-+#include <linux/slab.h>
-+#include <linux/vfs.h>
-+#include <linux/crc32.h>
-+#include "nodelist.h"
-+
-+
-+static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
-+{
-+ struct jffs2_full_dnode *old_metadata, *new_metadata;
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+ struct jffs2_raw_inode *ri;
-+ unsigned short dev;
-+ unsigned char *mdata = NULL;
-+ int mdatalen = 0;
-+ unsigned int ivalid;
-+ uint32_t phys_ofs, alloclen;
-+ int ret;
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-+ ret = inode_change_ok(inode, iattr);
-+ if (ret)
-+ return ret;
-+
-+ /* Special cases - we don't want more than one data node
-+ for these types on the medium at any time. So setattr
-+ must read the original data associated with the node
-+ (i.e. the device numbers or the target name) and write
-+ it out again with the appropriate data attached */
-+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-+ /* For these, we don't actually need to read the old node */
-+ dev = old_encode_dev(inode->i_rdev);
-+ mdata = (char *)&dev;
-+ mdatalen = sizeof(dev);
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-+ } else if (S_ISLNK(inode->i_mode)) {
-+ mdatalen = f->metadata->size;
-+ mdata = kmalloc(f->metadata->size, GFP_USER);
-+ if (!mdata)
-+ return -ENOMEM;
-+ ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
-+ if (ret) {
-+ kfree(mdata);
-+ return ret;
-+ }
-+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
-+ }
-+
-+ ri = jffs2_alloc_raw_inode();
-+ if (!ri) {
-+ if (S_ISLNK(inode->i_mode))
-+ kfree(mdata);
-+ return -ENOMEM;
-+ }
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ jffs2_free_raw_inode(ri);
-+ if (S_ISLNK(inode->i_mode & S_IFMT))
-+ kfree(mdata);
-+ return ret;
-+ }
-+ down(&f->sem);
-+ ivalid = iattr->ia_valid;
-+
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri->ino = cpu_to_je32(inode->i_ino);
-+ ri->version = cpu_to_je32(++f->highest_version);
-+
-+ ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
-+ ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
-+
-+ if (ivalid & ATTR_MODE)
-+ if (iattr->ia_mode & S_ISGID &&
-+ !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
-+ ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-+ else
-+ ri->mode = cpu_to_jemode(iattr->ia_mode);
-+ else
-+ ri->mode = cpu_to_jemode(inode->i_mode);
-+
-+
-+ ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
-+ ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
-+ ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
-+ ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
-+
-+ ri->offset = cpu_to_je32(0);
-+ ri->csize = ri->dsize = cpu_to_je32(mdatalen);
-+ ri->compr = JFFS2_COMPR_NONE;
-+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-+ /* It's an extension. Make it a hole node */
-+ ri->compr = JFFS2_COMPR_ZERO;
-+ ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
-+ ri->offset = cpu_to_je32(inode->i_size);
-+ }
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+ if (mdatalen)
-+ ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
-+ else
-+ ri->data_crc = cpu_to_je32(0);
-+
-+ new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
-+ if (S_ISLNK(inode->i_mode))
-+ kfree(mdata);
-+
-+ if (IS_ERR(new_metadata)) {
-+ jffs2_complete_reservation(c);
-+ jffs2_free_raw_inode(ri);
-+ up(&f->sem);
-+ return PTR_ERR(new_metadata);
-+ }
-+ /* It worked. Update the inode */
-+ inode->i_atime = ITIME(je32_to_cpu(ri->atime));
-+ inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-+ inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
-+ inode->i_mode = jemode_to_cpu(ri->mode);
-+ inode->i_uid = je16_to_cpu(ri->uid);
-+ inode->i_gid = je16_to_cpu(ri->gid);
-+
-+
-+ old_metadata = f->metadata;
-+
-+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
-+ jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
-+
-+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-+ jffs2_add_full_dnode_to_inode(c, f, new_metadata);
-+ inode->i_size = iattr->ia_size;
-+ f->metadata = NULL;
-+ } else {
-+ f->metadata = new_metadata;
-+ }
-+ if (old_metadata) {
-+ jffs2_mark_node_obsolete(c, old_metadata->raw);
-+ jffs2_free_full_dnode(old_metadata);
-+ }
-+ jffs2_free_raw_inode(ri);
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ /* We have to do the vmtruncate() without f->sem held, since
-+ some pages may be locked and waiting for it in readpage().
-+ We are protected from a simultaneous write() extending i_size
-+ back past iattr->ia_size, because do_truncate() holds the
-+ generic inode semaphore. */
-+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
-+ vmtruncate(inode, iattr->ia_size);
-+
-+ return 0;
-+}
-+
-+int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
-+{
-+ return jffs2_do_setattr(dentry->d_inode, iattr);
-+}
-+
-+int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+ unsigned long avail;
-+
-+ buf->f_type = JFFS2_SUPER_MAGIC;
-+ buf->f_bsize = 1 << PAGE_SHIFT;
-+ buf->f_blocks = c->flash_size >> PAGE_SHIFT;
-+ buf->f_files = 0;
-+ buf->f_ffree = 0;
-+ buf->f_namelen = JFFS2_MAX_NAME_LEN;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ avail = c->dirty_size + c->free_size;
-+ if (avail > c->sector_size * c->resv_blocks_write)
-+ avail -= c->sector_size * c->resv_blocks_write;
-+ else
-+ avail = 0;
-+
-+ buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
-+
-+ D1(jffs2_dump_block_lists(c));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ return 0;
-+}
-+
-+
-+void jffs2_clear_inode (struct inode *inode)
-+{
-+ /* We can forget about this inode for now - drop all
-+ * the nodelists associated with it, etc.
-+ */
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-+
-+ D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
-+
-+ jffs2_do_clear_inode(c, f);
-+}
-+
-+void jffs2_read_inode (struct inode *inode)
-+{
-+ struct jffs2_inode_info *f;
-+ struct jffs2_sb_info *c;
-+ struct jffs2_raw_inode latest_node;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
-+
-+ f = JFFS2_INODE_INFO(inode);
-+ c = JFFS2_SB_INFO(inode->i_sb);
-+
-+ jffs2_init_inode_info(f);
-+
-+ ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
-+
-+ if (ret) {
-+ make_bad_inode(inode);
-+ up(&f->sem);
-+ return;
-+ }
-+ inode->i_mode = jemode_to_cpu(latest_node.mode);
-+ inode->i_uid = je16_to_cpu(latest_node.uid);
-+ inode->i_gid = je16_to_cpu(latest_node.gid);
-+ inode->i_size = je32_to_cpu(latest_node.isize);
-+ inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
-+ inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
-+ inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
-+
-+ inode->i_nlink = f->inocache->nlink;
-+
-+ inode->i_blksize = PAGE_SIZE;
-+ inode->i_blocks = (inode->i_size + 511) >> 9;
-+
-+ switch (inode->i_mode & S_IFMT) {
-+ jint16_t rdev;
-+
-+ case S_IFLNK:
-+ inode->i_op = &jffs2_symlink_inode_operations;
-+ break;
-+
-+ case S_IFDIR:
-+ {
-+ struct jffs2_full_dirent *fd;
-+
-+ for (fd=f->dents; fd; fd = fd->next) {
-+ if (fd->type == DT_DIR && fd->ino)
-+ inode->i_nlink++;
-+ }
-+ /* and '..' */
-+ inode->i_nlink++;
-+ /* Root dir gets i_nlink 3 for some reason */
-+ if (inode->i_ino == 1)
-+ inode->i_nlink++;
-+
-+ inode->i_op = &jffs2_dir_inode_operations;
-+ inode->i_fop = &jffs2_dir_operations;
-+ break;
-+ }
-+ case S_IFREG:
-+ inode->i_op = &jffs2_file_inode_operations;
-+ inode->i_fop = &jffs2_file_operations;
-+ inode->i_mapping->a_ops = &jffs2_file_address_operations;
-+ inode->i_mapping->nrpages = 0;
-+ break;
-+
-+ case S_IFBLK:
-+ case S_IFCHR:
-+ /* Read the device numbers from the media */
-+ D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-+ if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
-+ /* Eep */
-+ printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ make_bad_inode(inode);
-+ return;
-+ }
-+
-+ case S_IFSOCK:
-+ case S_IFIFO:
-+ inode->i_op = &jffs2_file_inode_operations;
-+ init_special_inode(inode, inode->i_mode,
-+ old_decode_dev((je16_to_cpu(rdev))));
-+ break;
-+
-+ default:
-+ printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
-+ }
-+
-+ up(&f->sem);
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
-+}
-+
-+void jffs2_dirty_inode(struct inode *inode)
-+{
-+ struct iattr iattr;
-+
-+ if (!(inode->i_state & I_DIRTY_DATASYNC)) {
-+ D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
-+ return;
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino));
-+
-+ iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
-+ iattr.ia_mode = inode->i_mode;
-+ iattr.ia_uid = inode->i_uid;
-+ iattr.ia_gid = inode->i_gid;
-+ iattr.ia_atime = inode->i_atime;
-+ iattr.ia_mtime = inode->i_mtime;
-+ iattr.ia_ctime = inode->i_ctime;
-+
-+ jffs2_do_setattr(inode, &iattr);
-+}
-+
-+int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+
-+ if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
-+ return -EROFS;
-+
-+ /* We stop if it was running, then restart if it needs to.
-+ This also catches the case where it was stopped and this
-+ is just a remount to restart it */
-+ if (!(sb->s_flags & MS_RDONLY))
-+ jffs2_stop_garbage_collect_thread(c);
-+
-+ if (!(*flags & MS_RDONLY))
-+ jffs2_start_garbage_collect_thread(c);
-+
-+ sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY);
-+
-+ return 0;
-+}
-+
-+void jffs2_write_super (struct super_block *sb)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+ sb->s_dirt = 0;
-+
-+ if (sb->s_flags & MS_RDONLY)
-+ return;
-+
-+ D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
-+ jffs2_garbage_collect_trigger(c);
-+ jffs2_erase_pending_blocks(c, 0);
-+ jffs2_flush_wbuf_gc(c, 0);
-+}
-+
-+
-+/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
-+ fill in the raw_inode while you're at it. */
-+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
-+{
-+ struct inode *inode;
-+ struct super_block *sb = dir_i->i_sb;
-+ struct jffs2_sb_info *c;
-+ struct jffs2_inode_info *f;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
-+
-+ c = JFFS2_SB_INFO(sb);
-+
-+ inode = new_inode(sb);
-+
-+ if (!inode)
-+ return ERR_PTR(-ENOMEM);
-+
-+ f = JFFS2_INODE_INFO(inode);
-+ jffs2_init_inode_info(f);
-+
-+ memset(ri, 0, sizeof(*ri));
-+ /* Set OS-specific defaults for new inodes */
-+ ri->uid = cpu_to_je16(current->fsuid);
-+
-+ if (dir_i->i_mode & S_ISGID) {
-+ ri->gid = cpu_to_je16(dir_i->i_gid);
-+ if (S_ISDIR(mode))
-+ mode |= S_ISGID;
-+ } else {
-+ ri->gid = cpu_to_je16(current->fsgid);
-+ }
-+ ri->mode = cpu_to_jemode(mode);
-+ ret = jffs2_do_new_inode (c, f, mode, ri);
-+ if (ret) {
-+ make_bad_inode(inode);
-+ iput(inode);
-+ return ERR_PTR(ret);
-+ }
-+ inode->i_nlink = 1;
-+ inode->i_ino = je32_to_cpu(ri->ino);
-+ inode->i_mode = jemode_to_cpu(ri->mode);
-+ inode->i_gid = je16_to_cpu(ri->gid);
-+ inode->i_uid = je16_to_cpu(ri->uid);
-+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-+ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
-+
-+ inode->i_blksize = PAGE_SIZE;
-+ inode->i_blocks = 0;
-+ inode->i_size = 0;
-+
-+ insert_inode_hash(inode);
-+
-+ return inode;
-+}
-+
-+
-+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
-+{
-+ struct jffs2_sb_info *c;
-+ struct inode *root_i;
-+ int ret;
-+ size_t blocks;
-+
-+ c = JFFS2_SB_INFO(sb);
-+
-+ c->flash_size = c->mtd->size;
-+
-+ /*
-+ * Check, if we have to concatenate physical blocks to larger virtual blocks
-+ * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
-+ */
-+ blocks = c->flash_size / c->mtd->erasesize;
-+ while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024))
-+ blocks >>= 1;
-+
-+ c->sector_size = c->flash_size / blocks;
-+ if (c->sector_size != c->mtd->erasesize)
-+ printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n",
-+ c->mtd->erasesize / 1024, c->sector_size / 1024);
-+
-+ if (c->flash_size < 5*c->sector_size) {
-+ printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
-+ return -EINVAL;
-+ }
-+
-+ c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-+ /* Joern -- stick alignment for weird 8-byte-page flash here */
-+
-+ if (jffs2_cleanmarker_oob(c)) {
-+ /* NAND (or other bizarre) flash... do setup accordingly */
-+ ret = jffs2_nand_flash_setup(c);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
-+ if (!c->inocache_list) {
-+ ret = -ENOMEM;
-+ goto out_wbuf;
-+ }
-+ memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
-+
-+ if ((ret = jffs2_do_mount_fs(c)))
-+ goto out_inohash;
-+
-+ ret = -EINVAL;
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
-+ root_i = iget(sb, 1);
-+ if (is_bad_inode(root_i)) {
-+ D1(printk(KERN_WARNING "get root inode failed\n"));
-+ goto out_nodes;
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
-+ sb->s_root = d_alloc_root(root_i);
-+ if (!sb->s_root)
-+ goto out_root_i;
-+
-+#if LINUX_VERSION_CODE >= 0x20403
-+ sb->s_maxbytes = 0xFFFFFFFF;
-+#endif
-+ sb->s_blocksize = PAGE_CACHE_SIZE;
-+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-+ sb->s_magic = JFFS2_SUPER_MAGIC;
-+ if (!(sb->s_flags & MS_RDONLY))
-+ jffs2_start_garbage_collect_thread(c);
-+ return 0;
-+
-+ out_root_i:
-+ iput(root_i);
-+ out_nodes:
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ kfree(c->blocks);
-+ out_inohash:
-+ kfree(c->inocache_list);
-+ out_wbuf:
-+ jffs2_nand_flash_cleanup(c);
-+
-+ return ret;
-+}
-+
-+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f)
-+{
-+ iput(OFNI_EDONI_2SFFJ(f));
-+}
-+
-+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-+ int inum, int nlink)
-+{
-+ struct inode *inode;
-+ struct jffs2_inode_cache *ic;
-+ if (!nlink) {
-+ /* The inode has zero nlink but its nodes weren't yet marked
-+ obsolete. This has to be because we're still waiting for
-+ the final (close() and) iput() to happen.
-+
-+ There's a possibility that the final iput() could have
-+ happened while we were contemplating. In order to ensure
-+ that we don't cause a new read_inode() (which would fail)
-+ for the inode in question, we use ilookup() in this case
-+ instead of iget().
-+
-+ The nlink can't _become_ zero at this point because we're
-+ holding the alloc_sem, and jffs2_do_unlink() would also
-+ need that while decrementing nlink on any inode.
-+ */
-+ inode = ilookup(OFNI_BS_2SFFJ(c), inum);
-+ if (!inode) {
-+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
-+ inum));
-+
-+ spin_lock(&c->inocache_lock);
-+ ic = jffs2_get_ino_cache(c, inum);
-+ if (!ic) {
-+ D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
-+ spin_unlock(&c->inocache_lock);
-+ return NULL;
-+ }
-+ if (ic->state != INO_STATE_CHECKEDABSENT) {
-+ /* Wait for progress. Don't just loop */
-+ D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
-+ ic->ino, ic->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ } else {
-+ spin_unlock(&c->inocache_lock);
-+ }
-+
-+ return NULL;
-+ }
-+ } else {
-+ /* Inode has links to it still; they're not going away because
-+ jffs2_do_unlink() would need the alloc_sem and we have it.
-+ Just iget() it, and if read_inode() is necessary that's OK.
-+ */
-+ inode = iget(OFNI_BS_2SFFJ(c), inum);
-+ if (!inode)
-+ return ERR_PTR(-ENOMEM);
-+ }
-+ if (is_bad_inode(inode)) {
-+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
-+ inum, nlink);
-+ /* NB. This will happen again. We need to do something appropriate here. */
-+ iput(inode);
-+ return ERR_PTR(-EIO);
-+ }
-+
-+ return JFFS2_INODE_INFO(inode);
-+}
-+
-+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ unsigned long offset,
-+ unsigned long *priv)
-+{
-+ struct inode *inode = OFNI_EDONI_2SFFJ(f);
-+ struct page *pg;
-+
-+ pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
-+ (void *)jffs2_do_readpage_unlock, inode);
-+ if (IS_ERR(pg))
-+ return (void *)pg;
-+
-+ *priv = (unsigned long)pg;
-+ return kmap(pg);
-+}
-+
-+void jffs2_gc_release_page(struct jffs2_sb_info *c,
-+ unsigned char *ptr,
-+ unsigned long *priv)
-+{
-+ struct page *pg = (void *)*priv;
-+
-+ kunmap(pg);
-+ page_cache_release(pg);
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/gc.c linux/fs/jffs2/gc.c
---- linux-mips-2.4.27/fs/jffs2/gc.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/gc.c 2004-11-19 10:25:12.104168632 +0100
-@@ -1,76 +1,67 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/mtd/mtd.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
--#include <linux/sched.h>
--#include <linux/interrupt.h>
- #include <linux/pagemap.h>
--#include "nodelist.h"
- #include <linux/crc32.h>
-+#include <linux/compiler.h>
-+#include <linux/stat.h>
-+#include "nodelist.h"
-
-+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
-+ struct jffs2_inode_cache *ic,
-+ struct jffs2_raw_node_ref *raw);
- static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fd);
- static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
- static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd);
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
- static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *indeo, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end);
- static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end);
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end);
-+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f);
-
- /* Called with erase_completion_lock held */
- static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
- {
- struct jffs2_eraseblock *ret;
- struct list_head *nextlist = NULL;
-+ int n = jiffies % 128;
-
- /* Pick an eraseblock to garbage collect next. This is where we'll
- put the clever wear-levelling algorithms. Eventually. */
-- if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) {
-+ /* We possibly want to favour the dirtier blocks more when the
-+ number of free blocks is low. */
-+ if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
- D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
- nextlist = &c->bad_used_list;
-- } else if (jiffies % 100 && !list_empty(&c->dirty_list)) {
-- /* Most of the time, pick one off the dirty list */
-+ } else if (n < 50 && !list_empty(&c->erasable_list)) {
-+ /* Note that most of them will have gone directly to be erased.
-+ So don't favour the erasable_list _too_ much. */
-+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n"));
-+ nextlist = &c->erasable_list;
-+ } else if (n < 110 && !list_empty(&c->very_dirty_list)) {
-+ /* Most of the time, pick one off the very_dirty list */
-+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n"));
-+ nextlist = &c->very_dirty_list;
-+ } else if (n < 126 && !list_empty(&c->dirty_list)) {
- D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n"));
- nextlist = &c->dirty_list;
- } else if (!list_empty(&c->clean_list)) {
-@@ -80,9 +71,16 @@
- D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n"));
-
- nextlist = &c->dirty_list;
-+ } else if (!list_empty(&c->very_dirty_list)) {
-+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"));
-+ nextlist = &c->very_dirty_list;
-+ } else if (!list_empty(&c->erasable_list)) {
-+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
-+
-+ nextlist = &c->erasable_list;
- } else {
-- /* Eep. Both were empty */
-- printk(KERN_NOTICE "jffs2: No clean _or_ dirty blocks to GC from! Where are they all?\n");
-+ /* Eep. All were empty */
-+ printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
- return NULL;
- }
-
-@@ -94,6 +92,17 @@
- printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
- BUG();
- }
-+
-+ /* Have we accidentally picked a clean block with wasted space ? */
-+ if (ret->wasted_size) {
-+ D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size));
-+ ret->dirty_size += ret->wasted_size;
-+ c->wasted_size -= ret->wasted_size;
-+ c->dirty_size += ret->wasted_size;
-+ ret->wasted_size = 0;
-+ }
-+
-+ D1(jffs2_dump_block_lists(c));
- return ret;
- }
-
-@@ -103,21 +112,90 @@
- */
- int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
- {
-- struct jffs2_eraseblock *jeb;
- struct jffs2_inode_info *f;
-- struct jffs2_raw_node_ref *raw;
-- struct jffs2_node_frag *frag;
-- struct jffs2_full_dnode *fn = NULL;
-- struct jffs2_full_dirent *fd;
- struct jffs2_inode_cache *ic;
-- __u32 start = 0, end = 0, nrfrags = 0;
-- struct inode *inode;
-- int ret = 0;
-+ struct jffs2_eraseblock *jeb;
-+ struct jffs2_raw_node_ref *raw;
-+ int ret = 0, inum, nlink;
-
- if (down_interruptible(&c->alloc_sem))
- return -EINTR;
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ for (;;) {
-+ spin_lock(&c->erase_completion_lock);
-+ if (!c->unchecked_size)
-+ break;
-+
-+ /* We can't start doing GC yet. We haven't finished checking
-+ the node CRCs etc. Do it now. */
-+
-+ /* checked_ino is protected by the alloc_sem */
-+ if (c->checked_ino > c->highest_ino) {
-+ printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
-+ c->unchecked_size);
-+ D1(jffs2_dump_block_lists(c));
-+ spin_unlock(&c->erase_completion_lock);
-+ BUG();
-+ }
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ spin_lock(&c->inocache_lock);
-+
-+ ic = jffs2_get_ino_cache(c, c->checked_ino++);
-+
-+ if (!ic) {
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+ }
-+
-+ if (!ic->nlink) {
-+ D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
-+ ic->ino));
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+ }
-+ switch(ic->state) {
-+ case INO_STATE_CHECKEDABSENT:
-+ case INO_STATE_PRESENT:
-+ D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino));
-+ spin_unlock(&c->inocache_lock);
-+ continue;
-+
-+ case INO_STATE_GC:
-+ case INO_STATE_CHECKING:
-+ printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state);
-+ spin_unlock(&c->inocache_lock);
-+ BUG();
-+
-+ case INO_STATE_READING:
-+ /* We need to wait for it to finish, lest we move on
-+ and trigger the BUG() above while we haven't yet
-+ finished checking all its nodes */
-+ D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino));
-+ up(&c->alloc_sem);
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ return 0;
-+
-+ default:
-+ BUG();
-+
-+ case INO_STATE_UNCHECKED:
-+ ;
-+ }
-+ ic->state = INO_STATE_CHECKING;
-+ spin_unlock(&c->inocache_lock);
-+
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino));
-+
-+ ret = jffs2_do_crccheck_inode(c, ic);
-+ if (ret)
-+ printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
-+
-+ jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
-+ up(&c->alloc_sem);
-+ return ret;
-+ }
-
- /* First, work out which block we're garbage-collecting */
- jeb = c->gcblock;
-@@ -127,12 +205,14 @@
-
- if (!jeb) {
- printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
- return -EIO;
- }
-
-- D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset));
-+ D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size));
-+ D1(if (c->nextblock)
-+ printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
-
- if (!jeb->used_size) {
- up(&c->alloc_sem);
-@@ -141,92 +221,211 @@
-
- raw = jeb->gc_node;
-
-- while(raw->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3));
-- jeb->gc_node = raw = raw->next_phys;
-- if (!raw) {
-+ while(ref_obsolete(raw)) {
-+ D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
-+ raw = raw->next_phys;
-+ if (unlikely(!raw)) {
- printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
- printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
-- spin_unlock_bh(&c->erase_completion_lock);
-+ jeb->gc_node = raw;
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
- BUG();
- }
- }
-- D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3));
-+ jeb->gc_node = raw;
-+
-+ D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
-+
- if (!raw->next_in_ino) {
- /* Inode-less node. Clean marker, snapshot or something like that */
-- spin_unlock_bh(&c->erase_completion_lock);
-+ /* FIXME: If it's something that needs to be copied, including something
-+ we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
-+ spin_unlock(&c->erase_completion_lock);
- jffs2_mark_node_obsolete(c, raw);
- up(&c->alloc_sem);
- goto eraseit_lock;
- }
-
- ic = jffs2_raw_ref_to_ic(raw);
-- D1(printk(KERN_DEBUG "Inode number is #%u\n", ic->ino));
--
-- spin_unlock_bh(&c->erase_completion_lock);
-
-- D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, ic->ino));
-- if (!ic->nlink) {
-- /* The inode has zero nlink but its nodes weren't yet marked
-- obsolete. This has to be because we're still waiting for
-- the final (close() and) iput() to happen.
--
-- There's a possibility that the final iput() could have
-- happened while we were contemplating. In order to ensure
-- that we don't cause a new read_inode() (which would fail)
-- for the inode in question, we use ilookup() in this case
-- instead of iget().
--
-- The nlink can't _become_ zero at this point because we're
-- holding the alloc_sem, and jffs2_do_unlink() would also
-- need that while decrementing nlink on any inode.
-+ /* We need to hold the inocache. Either the erase_completion_lock or
-+ the inocache_lock are sufficient; we trade down since the inocache_lock
-+ causes less contention. */
-+ spin_lock(&c->inocache_lock);
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
-+
-+ /* Three possibilities:
-+ 1. Inode is already in-core. We must iget it and do proper
-+ updating to its fragtree, etc.
-+ 2. Inode is not in-core, node is REF_PRISTINE. We lock the
-+ inocache to prevent a read_inode(), copy the node intact.
-+ 3. Inode is not in-core, node is not pristine. We must iget()
-+ and take the slow path.
- */
-- inode = ilookup(OFNI_BS_2SFFJ(c), ic->ino);
-- if (!inode) {
-- D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
-+
-+ switch(ic->state) {
-+ case INO_STATE_CHECKEDABSENT:
-+ /* It's been checked, but it's not currently in-core.
-+ We can just copy any pristine nodes, but have
-+ to prevent anyone else from doing read_inode() while
-+ we're at it, so we set the state accordingly */
-+ if (ref_flags(raw) == REF_PRISTINE)
-+ ic->state = INO_STATE_GC;
-+ else {
-+ D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
- ic->ino));
-- up(&c->alloc_sem);
-- return 0;
- }
-- } else {
-- /* Inode has links to it still; they're not going away because
-- jffs2_do_unlink() would need the alloc_sem and we have it.
-- Just iget() it, and if read_inode() is necessary that's OK.
-+ break;
-+
-+ case INO_STATE_PRESENT:
-+ /* It's in-core. GC must iget() it. */
-+ break;
-+
-+ case INO_STATE_UNCHECKED:
-+ case INO_STATE_CHECKING:
-+ case INO_STATE_GC:
-+ /* Should never happen. We should have finished checking
-+ by the time we actually start doing any GC, and since
-+ we're holding the alloc_sem, no other garbage collection
-+ can happen.
- */
-- inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
-- if (!inode) {
-+ printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
-+ ic->ino, ic->state);
- up(&c->alloc_sem);
-- return -ENOMEM;
-+ spin_unlock(&c->inocache_lock);
-+ BUG();
-+
-+ case INO_STATE_READING:
-+ /* Someone's currently trying to read it. We must wait for
-+ them to finish and then go through the full iget() route
-+ to do the GC. However, sometimes read_inode() needs to get
-+ the alloc_sem() (for marking nodes invalid) so we must
-+ drop the alloc_sem before sleeping. */
-+
-+ up(&c->alloc_sem);
-+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
-+ ic->ino, ic->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ /* And because we dropped the alloc_sem we must start again from the
-+ beginning. Ponder chance of livelock here -- we're returning success
-+ without actually making any progress.
-+
-+ Q: What are the chances that the inode is back in INO_STATE_READING
-+ again by the time we next enter this function? And that this happens
-+ enough times to cause a real delay?
-+
-+ A: Small enough that I don't care :)
-+ */
-+ return 0;
- }
-+
-+ /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
-+ node intact, and we don't have to muck about with the fragtree etc.
-+ because we know it's not in-core. If it _was_ in-core, we go through
-+ all the iget() crap anyway */
-+
-+ if (ic->state == INO_STATE_GC) {
-+ spin_unlock(&c->inocache_lock);
-+
-+ ret = jffs2_garbage_collect_pristine(c, ic, raw);
-+
-+ spin_lock(&c->inocache_lock);
-+ ic->state = INO_STATE_CHECKEDABSENT;
-+ wake_up(&c->inocache_wq);
-+
-+ if (ret != -EBADFD) {
-+ spin_unlock(&c->inocache_lock);
-+ goto release_sem;
- }
-- if (is_bad_inode(inode)) {
-- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
-- /* NB. This will happen again. We need to do something appropriate here. */
-+
-+ /* Fall through if it wanted us to, with inocache_lock held */
-+ }
-+
-+ /* Prevent the fairly unlikely race where the gcblock is
-+ entirely obsoleted by the final close of a file which had
-+ the only valid nodes in the block, followed by erasure,
-+ followed by freeing of the ic because the erased block(s)
-+ held _all_ the nodes of that inode.... never been seen but
-+ it's vaguely possible. */
-+
-+ inum = ic->ino;
-+ nlink = ic->nlink;
-+ spin_unlock(&c->inocache_lock);
-+
-+ f = jffs2_gc_fetch_inode(c, inum, nlink);
-+ if (IS_ERR(f))
-+ return PTR_ERR(f);
-+ if (!f)
-+ return 0;
-+
-+ ret = jffs2_garbage_collect_live(c, jeb, raw, f);
-+
-+ jffs2_gc_release_inode(c, f);
-+
-+ release_sem:
- up(&c->alloc_sem);
-- iput(inode);
-- return -EIO;
-+
-+ eraseit_lock:
-+ /* If we've finished this block, start it erasing */
-+ spin_lock(&c->erase_completion_lock);
-+
-+ eraseit:
-+ if (c->gcblock && !c->gcblock->used_size) {
-+ D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
-+ /* We're GC'ing an empty block? */
-+ list_add_tail(&c->gcblock->list, &c->erase_pending_list);
-+ c->gcblock = NULL;
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
- }
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ return ret;
-+}
-+
-+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f)
-+{
-+ struct jffs2_node_frag *frag;
-+ struct jffs2_full_dnode *fn = NULL;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t start = 0, end = 0, nrfrags = 0;
-+ int ret = 0;
-
-- f = JFFS2_INODE_INFO(inode);
- down(&f->sem);
-+
- /* Now we have the lock for this inode. Check that it's still the one at the head
- of the list. */
-
-- if (raw->flash_offset & 1) {
-+ spin_lock(&c->erase_completion_lock);
-+
-+ if (c->gcblock != jeb) {
-+ spin_unlock(&c->erase_completion_lock);
-+ D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));
-+ goto upnout;
-+ }
-+ if (ref_obsolete(raw)) {
-+ spin_unlock(&c->erase_completion_lock);
- D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
- /* They'll call again */
- goto upnout;
- }
-+ spin_unlock(&c->erase_completion_lock);
-+
- /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */
- if (f->metadata && f->metadata->raw == raw) {
- fn = f->metadata;
-- ret = jffs2_garbage_collect_metadata(c, jeb, inode, fn);
-+ ret = jffs2_garbage_collect_metadata(c, jeb, f, fn);
- goto upnout;
- }
-
-- for (frag = f->fraglist; frag; frag = frag->next) {
-+ /* FIXME. Read node and do lookup? */
-+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
- if (frag->node && frag->node->raw == raw) {
- fn = frag->node;
- end = frag->ofs + frag->size;
-@@ -237,13 +436,22 @@
- }
- }
- if (fn) {
-+ if (ref_flags(raw) == REF_PRISTINE) {
-+ ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
-+ if (!ret) {
-+ /* Urgh. Return it sensibly. */
-+ frag->node->raw = f->inocache->nodes;
-+ }
-+ if (ret != -EBADFD)
-+ goto upnout;
-+ }
- /* We found a datanode. Do the GC */
- if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) {
- /* It crosses a page boundary. Therefore, it must be a hole. */
-- ret = jffs2_garbage_collect_hole(c, jeb, inode, fn, start, end);
-+ ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end);
- } else {
- /* It could still be a hole. But we GC the page this way anyway */
-- ret = jffs2_garbage_collect_dnode(c, jeb, inode, fn, start, end);
-+ ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end);
- }
- goto upnout;
- }
-@@ -255,12 +463,13 @@
- }
-
- if (fd && fd->ino) {
-- ret = jffs2_garbage_collect_dirent(c, jeb, inode, fd);
-+ ret = jffs2_garbage_collect_dirent(c, jeb, f, fd);
- } else if (fd) {
-- ret = jffs2_garbage_collect_deletion_dirent(c, jeb, inode, fd);
-+ ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd);
- } else {
-- printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%lu\n", raw->flash_offset&~3, inode->i_ino);
-- if (raw->flash_offset & 1) {
-+ printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n",
-+ ref_offset(raw), f->inocache->ino);
-+ if (ref_obsolete(raw)) {
- printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
- } else {
- ret = -EIO;
-@@ -268,46 +477,197 @@
- }
- upnout:
- up(&f->sem);
-- up(&c->alloc_sem);
-- iput(inode);
-
-- eraseit_lock:
-- /* If we've finished this block, start it erasing */
-- spin_lock_bh(&c->erase_completion_lock);
-+ return ret;
-+}
-
-- eraseit:
-- if (c->gcblock && !c->gcblock->used_size) {
-- D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
-- /* We're GC'ing an empty block? */
-- list_add_tail(&c->gcblock->list, &c->erase_pending_list);
-- c->gcblock = NULL;
-- c->nr_erasing_blocks++;
-- jffs2_erase_pending_trigger(c);
-+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
-+ struct jffs2_inode_cache *ic,
-+ struct jffs2_raw_node_ref *raw)
-+{
-+ union jffs2_node_union *node;
-+ struct jffs2_raw_node_ref *nraw;
-+ size_t retlen;
-+ int ret;
-+ uint32_t phys_ofs, alloclen;
-+ uint32_t crc, rawlen;
-+ int retried = 0;
-+
-+ D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
-+
-+ rawlen = ref_totlen(c, c->gcblock, raw);
-+
-+ /* Ask for a small amount of space (or the totlen if smaller) because we
-+ don't want to force wastage of the end of a block if splitting would
-+ work. */
-+ ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN,
-+ rawlen), &phys_ofs, &alloclen);
-+ if (ret)
-+ return ret;
-+
-+ if (alloclen < rawlen) {
-+ /* Doesn't fit untouched. We'll go the old route and split it */
-+ return -EBADFD;
-+ }
-+
-+ node = kmalloc(rawlen, GFP_KERNEL);
-+ if (!node)
-+ return -ENOMEM;
-+
-+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
-+ if (!ret && retlen != rawlen)
-+ ret = -EIO;
-+ if (ret)
-+ goto out_node;
-+
-+ crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4);
-+ if (je32_to_cpu(node->u.hdr_crc) != crc) {
-+ printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);
-+ goto bail;
-+ }
-+
-+ switch(je16_to_cpu(node->u.nodetype)) {
-+ case JFFS2_NODETYPE_INODE:
-+ crc = crc32(0, node, sizeof(node->i)-8);
-+ if (je32_to_cpu(node->i.node_crc) != crc) {
-+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->i.node_crc), crc);
-+ goto bail;
-+ }
-+
-+ if (je32_to_cpu(node->i.dsize)) {
-+ crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize));
-+ if (je32_to_cpu(node->i.data_crc) != crc) {
-+ printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->i.data_crc), crc);
-+ goto bail;
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ }
-+ break;
-+
-+ case JFFS2_NODETYPE_DIRENT:
-+ crc = crc32(0, node, sizeof(node->d)-8);
-+ if (je32_to_cpu(node->d.node_crc) != crc) {
-+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->d.node_crc), crc);
-+ goto bail;
-+ }
-+
-+ if (node->d.nsize) {
-+ crc = crc32(0, node->d.name, node->d.nsize);
-+ if (je32_to_cpu(node->d.name_crc) != crc) {
-+ printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
-+ goto bail;
-+ }
-+ }
-+ break;
-+ default:
-+ printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
-+ ref_offset(raw), je16_to_cpu(node->u.nodetype));
-+ goto bail;
-+ }
-+
-+ nraw = jffs2_alloc_raw_node_ref();
-+ if (!nraw) {
-+ ret = -ENOMEM;
-+ goto out_node;
-+ }
-+
-+ /* OK, all the CRCs are good; this node can just be copied as-is. */
-+ retry:
-+ nraw->flash_offset = phys_ofs;
-+ nraw->__totlen = rawlen;
-+ nraw->next_phys = NULL;
-+
-+ ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
-+
-+ if (ret || (retlen != rawlen)) {
-+ printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
-+ rawlen, phys_ofs, ret, retlen);
-+ if (retlen) {
-+ /* Doesn't belong to any inode */
-+ nraw->next_in_ino = NULL;
-+
-+ nraw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, nraw);
-+ jffs2_mark_node_obsolete(c, nraw);
-+ } else {
-+ printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
-+ jffs2_free_raw_node_ref(nraw);
-+ }
-+ if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
-+
-+ retried = 1;
-+
-+ D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
-+
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
-
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(nraw);
-+ }
-+
-+ if (!ret)
-+ ret = -EIO;
-+ goto out_node;
-+ }
-+ nraw->flash_offset |= REF_PRISTINE;
-+ jffs2_add_physical_node_ref(c, nraw);
-+
-+ /* Link into per-inode list. This is safe because of the ic
-+ state being INO_STATE_GC. Note that if we're doing this
-+ for an inode which is in-code, the 'nraw' pointer is then
-+ going to be fetched from ic->nodes by our caller. */
-+ nraw->next_in_ino = ic->nodes;
-+ ic->nodes = nraw;
-+
-+ jffs2_mark_node_obsolete(c, raw);
-+ D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
-+
-+ out_node:
-+ kfree(node);
- return ret;
-+ bail:
-+ ret = -EBADFD;
-+ goto out_node;
- }
-
- static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dnode *new_fn;
- struct jffs2_raw_inode ri;
-- unsigned short dev;
-+ jint16_t dev;
- char *mdata = NULL, mdatalen = 0;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-+ if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
-+ S_ISCHR(JFFS2_F_I_MODE(f)) ) {
- /* For these, we don't actually need to read the old node */
-- dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) |
-- MINOR(to_kdev_t(inode->i_rdev));
-+ /* FIXME: for minor or major > 255. */
-+ dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) |
-+ JFFS2_F_I_RDEV_MIN(f)));
- mdata = (char *)&dev;
- mdatalen = sizeof(dev);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
-- } else if (S_ISLNK(inode->i_mode)) {
-+ } else if (S_ISLNK(JFFS2_F_I_MODE(f))) {
- mdatalen = fn->size;
- mdata = kmalloc(fn->size, GFP_KERNEL);
- if (!mdata) {
-@@ -326,34 +686,34 @@
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
- sizeof(ri)+ mdatalen, ret);
- goto out;
- }
-
- memset(&ri, 0, sizeof(ri));
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri) + mdatalen;
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.offset = 0;
-- ri.csize = mdatalen;
-- ri.dsize = mdatalen;
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen);
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.offset = cpu_to_je32(0);
-+ ri.csize = cpu_to_je32(mdatalen);
-+ ri.dsize = cpu_to_je32(mdatalen);
- ri.compr = JFFS2_COMPR_NONE;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = crc32(0, mdata, mdatalen);
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
-
-- new_fn = jffs2_write_dnode(inode, &ri, mdata, mdatalen, phys_ofs, NULL);
-+ new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
-@@ -364,41 +724,40 @@
- jffs2_free_full_dnode(fn);
- f->metadata = new_fn;
- out:
-- if (S_ISLNK(inode->i_mode))
-+ if (S_ISLNK(JFFS2_F_I_MODE(f)))
- kfree(mdata);
- return ret;
- }
-
- static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd)
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dirent *new_fd;
- struct jffs2_raw_dirent rd;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- rd.magic = JFFS2_MAGIC_BITMASK;
-- rd.nodetype = JFFS2_NODETYPE_DIRENT;
-+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
- rd.nsize = strlen(fd->name);
-- rd.totlen = sizeof(rd) + rd.nsize;
-- rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4);
-+ rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize);
-+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4));
-
-- rd.pino = inode->i_ino;
-- rd.version = ++f->highest_version;
-- rd.ino = fd->ino;
-- rd.mctime = max(inode->i_mtime, inode->i_ctime);
-+ rd.pino = cpu_to_je32(f->inocache->ino);
-+ rd.version = cpu_to_je32(++f->highest_version);
-+ rd.ino = cpu_to_je32(fd->ino);
-+ rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));
- rd.type = fd->type;
-- rd.node_crc = crc32(0, &rd, sizeof(rd)-8);
-- rd.name_crc = crc32(0, fd->name, rd.nsize);
-+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
-+ rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
-
- ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
- sizeof(rd)+rd.nsize, ret);
- return ret;
- }
-- new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL);
-+ new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fd)) {
- printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
-@@ -409,19 +768,98 @@
- }
-
- static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dirent *fd)
-+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dirent **fdp = &f->dents;
- int found = 0;
-
-- /* FIXME: When we run on NAND flash, we need to work out whether
-- this deletion dirent is still needed to actively delete a
-- 'real' dirent with the same name that's still somewhere else
-- on the flash. For now, we know that we've actually obliterated
-- all the older dirents when they became obsolete, so we didn't
-- really need to write the deletion to flash in the first place.
-- */
-+ /* On a medium where we can't actually mark nodes obsolete
-+ pernamently, such as NAND flash, we need to work out
-+ whether this deletion dirent is still needed to actively
-+ delete a 'real' dirent with the same name that's still
-+ somewhere else on the flash. */
-+ if (!jffs2_can_mark_obsolete(c)) {
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_raw_node_ref *raw;
-+ int ret;
-+ size_t retlen;
-+ int name_len = strlen(fd->name);
-+ uint32_t name_crc = crc32(0, fd->name, name_len);
-+ uint32_t rawlen = ref_totlen(c, jeb, fd->raw);
-+
-+ rd = kmalloc(rawlen, GFP_KERNEL);
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ /* Prevent the erase code from nicking the obsolete node refs while
-+ we're looking at them. I really don't like this extra lock but
-+ can't see any alternative. Suggestions on a postcard to... */
-+ down(&c->erase_free_sem);
-+
-+ for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
-+
-+ /* We only care about obsolete ones */
-+ if (!(ref_obsolete(raw)))
-+ continue;
-+
-+ /* Any dirent with the same name is going to have the same length... */
-+ if (ref_totlen(c, NULL, raw) != rawlen)
-+ continue;
-+
-+ /* Doesn't matter if there's one in the same erase block. We're going to
-+ delete it too at the same time. */
-+ if ((raw->flash_offset & ~(c->sector_size-1)) ==
-+ (fd->raw->flash_offset & ~(c->sector_size-1)))
-+ continue;
-+
-+ D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
-+
-+ /* This is an obsolete node belonging to the same directory, and it's of the right
-+ length. We need to take a closer look...*/
-+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);
-+ if (ret) {
-+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));
-+ /* If we can't read it, we don't need to continue to obsolete it. Continue */
-+ continue;
-+ }
-+ if (retlen != rawlen) {
-+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n",
-+ retlen, rawlen, ref_offset(raw));
-+ continue;
-+ }
-+
-+ if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)
-+ continue;
-+
-+ /* If the name CRC doesn't match, skip */
-+ if (je32_to_cpu(rd->name_crc) != name_crc)
-+ continue;
-+
-+ /* If the name length doesn't match, or it's another deletion dirent, skip */
-+ if (rd->nsize != name_len || !je32_to_cpu(rd->ino))
-+ continue;
-+
-+ /* OK, check the actual name now */
-+ if (memcmp(rd->name, fd->name, name_len))
-+ continue;
-+
-+ /* OK. The name really does match. There really is still an older node on
-+ the flash which our deletion dirent obsoletes. So we have to write out
-+ a new deletion dirent to replace it */
-+ up(&c->erase_free_sem);
-+
-+ D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
-+ ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
-+ kfree(rd);
-+
-+ return jffs2_garbage_collect_dirent(c, jeb, f, fd);
-+ }
-+
-+ up(&c->erase_free_sem);
-+ kfree(rd);
-+ }
-+
-+ /* No need for it any more. Just mark it obsolete and remove it from the list */
- while (*fdp) {
- if ((*fdp) == fd) {
- found = 1;
-@@ -431,7 +869,7 @@
- fdp = &(*fdp)->next;
- }
- if (!found) {
-- printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino);
-+ printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino);
- }
- jffs2_mark_node_obsolete(c, fd->raw);
- jffs2_free_full_dirent(fd);
-@@ -439,93 +877,95 @@
- }
-
- static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_inode ri;
- struct jffs2_node_frag *frag;
- struct jffs2_full_dnode *new_fn;
-- __u32 alloclen, phys_ofs;
-+ uint32_t alloclen, phys_ofs;
- int ret;
-
-- D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n",
-- inode->i_ino, start, end));
-+ D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
-+ f->inocache->ino, start, end));
-
- memset(&ri, 0, sizeof(ri));
-
- if(fn->frags > 1) {
- size_t readlen;
-- __u32 crc;
-+ uint32_t crc;
- /* It's partially obsoleted by a later write. So we have to
- write it out again with the _same_ version as before */
-- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri);
-+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
- if (readlen != sizeof(ri) || ret) {
-- printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen);
-+ printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);
- goto fill;
- }
-- if (ri.nodetype != JFFS2_NODETYPE_INODE) {
-+ if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
-- fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE);
-+ ref_offset(fn->raw),
-+ je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
- return -EIO;
- }
-- if (ri.totlen != sizeof(ri)) {
-- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",
-- fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri));
-+ if (je32_to_cpu(ri.totlen) != sizeof(ri)) {
-+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",
-+ ref_offset(fn->raw),
-+ je32_to_cpu(ri.totlen), sizeof(ri));
- return -EIO;
- }
- crc = crc32(0, &ri, sizeof(ri)-8);
-- if (crc != ri.node_crc) {
-+ if (crc != je32_to_cpu(ri.node_crc)) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
-- fn->raw->flash_offset & ~3, ri.node_crc, crc);
-+ ref_offset(fn->raw),
-+ je32_to_cpu(ri.node_crc), crc);
- /* FIXME: We could possibly deal with this by writing new holes for each frag */
-- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n",
-- start, end, inode->i_ino);
-+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-+ start, end, f->inocache->ino);
- goto fill;
- }
- if (ri.compr != JFFS2_COMPR_ZERO) {
-- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3);
-- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n",
-- start, end, inode->i_ino);
-+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));
-+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-+ start, end, f->inocache->ino);
- goto fill;
- }
- } else {
- fill:
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri);
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.offset = start;
-- ri.dsize = end - start;
-- ri.csize = 0;
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri));
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.offset = cpu_to_je32(start);
-+ ri.dsize = cpu_to_je32(end - start);
-+ ri.csize = cpu_to_je32(0);
- ri.compr = JFFS2_COMPR_ZERO;
- }
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.data_crc = 0;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.data_crc = cpu_to_je32(0);
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
- sizeof(ri), ret);
- return ret;
- }
-- new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);
-+ new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
- return PTR_ERR(new_fn);
- }
-- if (ri.version == f->highest_version) {
-+ if (je32_to_cpu(ri.version) == f->highest_version) {
- jffs2_add_full_dnode_to_inode(c, f, new_fn);
- if (f->metadata) {
- jffs2_mark_node_obsolete(c, f->metadata->raw);
-@@ -541,12 +981,17 @@
- * number as before. (Except in case of error -- see 'goto fill;'
- * above.)
- */
-- D1(if(fn->frags <= 1) {
-+ D1(if(unlikely(fn->frags <= 1)) {
- printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
-- fn->frags, ri.version, f->highest_version, ri.ino);
-+ fn->frags, je32_to_cpu(ri.version), f->highest_version,
-+ je32_to_cpu(ri.ino));
- });
-
-- for (frag = f->fraglist; frag; frag = frag->next) {
-+ /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
-+ mark_ref_normal(new_fn->raw);
-+
-+ for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);
-+ frag; frag = frag_next(frag)) {
- if (frag->ofs > fn->size + fn->ofs)
- break;
- if (frag->node == fn) {
-@@ -571,49 +1016,146 @@
- }
-
- static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-- struct inode *inode, struct jffs2_full_dnode *fn,
-- __u32 start, __u32 end)
-+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
-+ uint32_t start, uint32_t end)
- {
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_full_dnode *new_fn;
- struct jffs2_raw_inode ri;
-- __u32 alloclen, phys_ofs, offset, orig_end;
-+ uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
- int ret = 0;
- unsigned char *comprbuf = NULL, *writebuf;
-- struct page *pg;
-+ unsigned long pg;
- unsigned char *pg_ptr;
-
--
- memset(&ri, 0, sizeof(ri));
-
-- D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n",
-- inode->i_ino, start, end));
-+ D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
-+ f->inocache->ino, start, end));
-
- orig_end = end;
-+ orig_start = start;
-
-+ if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {
-+ /* Attempt to do some merging. But only expand to cover logically
-+ adjacent frags if the block containing them is already considered
-+ to be dirty. Otherwise we end up with GC just going round in
-+ circles dirtying the nodes it already wrote out, especially
-+ on NAND where we have small eraseblocks and hence a much higher
-+ chance of nodes having to be split to cross boundaries. */
-
-- /* If we're looking at the last node in the block we're
-- garbage-collecting, we allow ourselves to merge as if the
-- block was already erasing. We're likely to be GC'ing a
-- partial page, and the next block we GC is likely to have
-- the other half of this page right at the beginning, which
-- means we'd expand it _then_, as nr_erasing_blocks would have
-- increased since we checked, and in doing so would obsolete
-- the partial node which we'd have written here. Meaning that
-- the GC would churn and churn, and just leave dirty blocks in
-- it's wake.
-- */
-- if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {
-- /* Shitloads of space */
-- /* FIXME: Integrate this properly with GC calculations */
-- start &= ~(PAGE_CACHE_SIZE-1);
-- end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size);
-- D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",
-- start, end));
-- if (end < orig_end) {
-- printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);
-- end = orig_end;
-+ struct jffs2_node_frag *frag;
-+ uint32_t min, max;
-+
-+ min = start & ~(PAGE_CACHE_SIZE-1);
-+ max = min + PAGE_CACHE_SIZE;
-+
-+ frag = jffs2_lookup_node_frag(&f->fragtree, start);
-+
-+ /* BUG_ON(!frag) but that'll happen anyway... */
-+
-+ BUG_ON(frag->ofs != start);
-+
-+ /* First grow down... */
-+ while((frag = frag_prev(frag)) && frag->ofs >= min) {
-+
-+ /* If the previous frag doesn't even reach the beginning, there's
-+ excessive fragmentation. Just merge. */
-+ if (frag->ofs > min) {
-+ D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ start = frag->ofs;
-+ continue;
-+ }
-+ /* OK. This frag holds the first byte of the page. */
-+ if (!frag->node || !frag->node->raw) {
-+ D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ break;
-+ } else {
-+
-+ /* OK, it's a frag which extends to the beginning of the page. Does it live
-+ in a block which is still considered clean? If so, don't obsolete it.
-+ If not, cover it anyway. */
-+
-+ struct jffs2_raw_node_ref *raw = frag->node->raw;
-+ struct jffs2_eraseblock *jeb;
-+
-+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
-+
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
-+ start = frag->ofs;
-+ break;
- }
-+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-+ D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ break;
-+ }
-+
-+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ start = frag->ofs;
-+ break;
-+ }
-+ }
-+
-+ /* ... then up */
-+
-+ /* Find last frag which is actually part of the node we're to GC. */
-+ frag = jffs2_lookup_node_frag(&f->fragtree, end-1);
-+
-+ while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) {
-+
-+ /* If the previous frag doesn't even reach the beginning, there's lots
-+ of fragmentation. Just merge. */
-+ if (frag->ofs+frag->size < max) {
-+ D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ end = frag->ofs + frag->size;
-+ continue;
-+ }
-+
-+ if (!frag->node || !frag->node->raw) {
-+ D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ break;
-+ } else {
-+
-+ /* OK, it's a frag which extends to the beginning of the page. Does it live
-+ in a block which is still considered clean? If so, don't obsolete it.
-+ If not, cover it anyway. */
-+
-+ struct jffs2_raw_node_ref *raw = frag->node->raw;
-+ struct jffs2_eraseblock *jeb;
-+
-+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
-+
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
-+ end = frag->ofs + frag->size;
-+ break;
-+ }
-+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-+ D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ break;
-+ }
-+
-+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
-+ frag->ofs, frag->ofs+frag->size, jeb->offset));
-+ end = frag->ofs + frag->size;
-+ break;
-+ }
-+ }
-+ D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
-+ orig_start, orig_end, start, end));
-+
-+ BUG_ON(end > JFFS2_F_I_SIZE(f));
-+ BUG_ON(end < orig_end);
-+ BUG_ON(start > orig_start);
- }
-
- /* First, use readpage() to read the appropriate page into the page cache */
-@@ -623,63 +1165,57 @@
- * page OK. We'll actually write it out again in commit_write, which is a little
- * suboptimal, but at least we're correct.
- */
-- pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-+ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
-
-- if (IS_ERR(pg)) {
-- printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
-- return PTR_ERR(pg);
-+ if (IS_ERR(pg_ptr)) {
-+ printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
-+ return PTR_ERR(pg_ptr);
- }
-- pg_ptr = (char *)kmap(pg);
-- comprbuf = kmalloc(end - start, GFP_KERNEL);
-
- offset = start;
- while(offset < orig_end) {
-- __u32 datalen;
-- __u32 cdatalen;
-+ uint32_t datalen;
-+ uint32_t cdatalen;
- char comprtype = JFFS2_COMPR_NONE;
-
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
-
- if (ret) {
-- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n",
-+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
- sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
- break;
- }
-- cdatalen = min(alloclen - sizeof(ri), end - offset);
-+ cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);
- datalen = end - offset;
-
- writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
-
-- if (comprbuf) {
-- comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
-- }
-- if (comprtype) {
-- writebuf = comprbuf;
-- } else {
-- datalen = cdatalen;
-- }
-- ri.magic = JFFS2_MAGIC_BITMASK;
-- ri.nodetype = JFFS2_NODETYPE_INODE;
-- ri.totlen = sizeof(ri) + cdatalen;
-- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
--
-- ri.ino = inode->i_ino;
-- ri.version = ++f->highest_version;
-- ri.mode = inode->i_mode;
-- ri.uid = inode->i_uid;
-- ri.gid = inode->i_gid;
-- ri.isize = inode->i_size;
-- ri.atime = inode->i_atime;
-- ri.ctime = inode->i_ctime;
-- ri.mtime = inode->i_mtime;
-- ri.offset = offset;
-- ri.csize = cdatalen;
-- ri.dsize = datalen;
-+ comprtype = jffs2_compress(writebuf, &comprbuf, &datalen, &cdatalen);
-+
-+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
-+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri.ino = cpu_to_je32(f->inocache->ino);
-+ ri.version = cpu_to_je32(++f->highest_version);
-+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
-+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
-+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
-+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
-+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
-+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
-+ ri.offset = cpu_to_je32(offset);
-+ ri.csize = cpu_to_je32(cdatalen);
-+ ri.dsize = cpu_to_je32(datalen);
- ri.compr = comprtype;
-- ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.data_crc = crc32(0, writebuf, cdatalen);
-+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-+ ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
-+
-+ new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
-
-- new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL);
-+ jffs2_free_comprbuf(comprbuf, writebuf);
-
- if (IS_ERR(new_fn)) {
- printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
-@@ -694,12 +1230,8 @@
- f->metadata = NULL;
- }
- }
-- if (comprbuf) kfree(comprbuf);
-
-- kunmap(pg);
-- /* XXX: Does the page get freed automatically? */
-- /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
-- page_cache_release(pg);
-+ jffs2_gc_release_page(c, pg_ptr, &pg);
- return ret;
- }
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/ioctl.c linux/fs/jffs2/ioctl.c
---- linux-mips-2.4.27/fs/jffs2/ioctl.c 2001-10-19 03:24:56.000000000 +0200
-+++ linux/fs/jffs2/ioctl.c 2004-11-19 10:25:12.108168024 +0100
-@@ -1,37 +1,13 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-@@ -42,6 +18,6 @@
- {
- /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which
- will include compression support etc. */
-- return -EINVAL;
-+ return -ENOTTY;
- }
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/malloc.c linux/fs/jffs2/malloc.c
---- linux-mips-2.4.27/fs/jffs2/malloc.c 2001-10-19 03:24:56.000000000 +0200
-+++ linux/fs/jffs2/malloc.c 2004-11-19 10:25:12.110167720 +0100
-@@ -1,37 +1,13 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-@@ -47,6 +23,9 @@
- #define JFFS2_SLAB_POISON 0
- #endif
-
-+// replace this by #define D3 (x) x for cache debugging
-+#define D3(x)
-+
- /* These are initialised to NULL in the kernel startup code.
- If you're porting to other operating systems, beware */
- static kmem_cache_t *full_dnode_slab;
-@@ -57,57 +36,47 @@
- static kmem_cache_t *node_frag_slab;
- static kmem_cache_t *inode_cache_slab;
-
--void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
--{
-- struct jffs2_tmp_dnode_info *next;
--
-- while (tn) {
-- next = tn;
-- tn = tn->next;
-- jffs2_free_full_dnode(next->fn);
-- jffs2_free_tmp_dnode_info(next);
-- }
--}
--
--void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
--{
-- struct jffs2_full_dirent *next;
--
-- while (fd) {
-- next = fd->next;
-- jffs2_free_full_dirent(fd);
-- fd = next;
-- }
--}
--
- int __init jffs2_create_slab_caches(void)
- {
-- full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
-+ sizeof(struct jffs2_full_dnode),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!full_dnode_slab)
- goto err;
-
-- raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
-+ sizeof(struct jffs2_raw_dirent),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_dirent_slab)
- goto err;
-
-- raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
-+ sizeof(struct jffs2_raw_inode),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_inode_slab)
- goto err;
-
-- tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
-+ sizeof(struct jffs2_tmp_dnode_info),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!tmp_dnode_info_slab)
- goto err;
-
-- raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref",
-+ sizeof(struct jffs2_raw_node_ref),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!raw_node_ref_slab)
- goto err;
-
-- node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), 0, JFFS2_SLAB_POISON, NULL, NULL);
-+ node_frag_slab = kmem_cache_create("jffs2_node_frag",
-+ sizeof(struct jffs2_node_frag),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (!node_frag_slab)
- goto err;
-
-- inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
--
-+ inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
-+ sizeof(struct jffs2_inode_cache),
-+ 0, JFFS2_SLAB_POISON, NULL, NULL);
- if (inode_cache_slab)
- return 0;
- err:
-@@ -131,7 +100,6 @@
- kmem_cache_destroy(node_frag_slab);
- if(inode_cache_slab)
- kmem_cache_destroy(inode_cache_slab);
--
- }
-
- struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
-@@ -146,75 +114,92 @@
-
- struct jffs2_full_dnode *jffs2_alloc_full_dnode(void)
- {
-- void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
-+ struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret));
- return ret;
- }
-
- void jffs2_free_full_dnode(struct jffs2_full_dnode *x)
- {
-+ D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x));
- kmem_cache_free(full_dnode_slab, x);
- }
-
- struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void)
- {
-- return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
-+ struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x));
- kmem_cache_free(raw_dirent_slab, x);
- }
-
- struct jffs2_raw_inode *jffs2_alloc_raw_inode(void)
- {
-- return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
-+ struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_inode(struct jffs2_raw_inode *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x));
- kmem_cache_free(raw_inode_slab, x);
- }
-
- struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void)
- {
-- return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
-+ struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
- {
-+ D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x));
- kmem_cache_free(tmp_dnode_info_slab, x);
- }
-
- struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
- {
-- return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
-+ struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
- {
-+ D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x));
- kmem_cache_free(raw_node_ref_slab, x);
- }
-
- struct jffs2_node_frag *jffs2_alloc_node_frag(void)
- {
-- return kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
-+ struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
-+ D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret));
-+ return ret;
- }
-
- void jffs2_free_node_frag(struct jffs2_node_frag *x)
- {
-+ D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x));
- kmem_cache_free(node_frag_slab, x);
- }
-
- struct jffs2_inode_cache *jffs2_alloc_inode_cache(void)
- {
- struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL);
-- D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
-+ D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
- return ret;
- }
-
- void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
- {
-- D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x));
-+ D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x));
- kmem_cache_free(inode_cache_slab, x);
- }
-
-diff -Nurb linux-mips-2.4.27/fs/jffs2/nodelist.c linux/fs/jffs2/nodelist.c
---- linux-mips-2.4.27/fs/jffs2/nodelist.c 2003-07-05 05:23:44.000000000 +0200
-+++ linux/fs/jffs2/nodelist.c 2004-11-19 10:25:12.112167416 +0100
-@@ -1,44 +1,24 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001, 2002 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
--#include <linux/jffs2.h>
-+#include <linux/sched.h>
- #include <linux/fs.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/rbtree.h>
-+#include <linux/crc32.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
- #include "nodelist.h"
-
- void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
-@@ -78,7 +58,7 @@
- /* Put a new tmp_dnode_info into the list, keeping the list in
- order of increasing version
- */
--void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
-+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
- {
- struct jffs2_tmp_dnode_info **prev = list;
-
-@@ -89,13 +69,37 @@
- *prev = tn;
- }
-
-+static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
-+{
-+ struct jffs2_tmp_dnode_info *next;
-+
-+ while (tn) {
-+ next = tn;
-+ tn = tn->next;
-+ jffs2_free_full_dnode(next->fn);
-+ jffs2_free_tmp_dnode_info(next);
-+ }
-+}
-+
-+static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
-+{
-+ struct jffs2_full_dirent *next;
-+
-+ while (fd) {
-+ next = fd->next;
-+ jffs2_free_full_dirent(fd);
-+ fd = next;
-+ }
-+}
-+
-+
- /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
- with this ino, returning the former in order of version */
-
- int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-- __u32 *highest_version, __u32 *latest_mctime,
-- __u32 *mctime_ver)
-+ uint32_t *highest_version, uint32_t *latest_mctime,
-+ uint32_t *mctime_ver)
- {
- struct jffs2_raw_node_ref *ref = f->inocache->nodes;
- struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
-@@ -109,43 +113,71 @@
-
- D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
- if (!f->inocache->nodes) {
-- printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino);
-+ printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino);
- }
-+
-+ spin_lock(&c->erase_completion_lock);
-+
- for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
- /* Work out whether it's a data node or a dirent node */
-- if (ref->flash_offset & 1) {
-+ if (ref_obsolete(ref)) {
- /* FIXME: On NAND flash we may need to read these */
-- D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
- continue;
- }
-- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
-+ /* We can hold a pointer to a non-obsolete node without the spinlock,
-+ but _obsolete_ nodes may disappear at any time, if the block
-+ they're in gets erased */
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ cond_resched();
-+
-+ /* FIXME: point() */
-+ err = jffs2_flash_read(c, (ref_offset(ref)),
-+ min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
-+ &retlen, (void *)&node);
- if (err) {
-- printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3);
-+ printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
- goto free_out;
- }
-
-
- /* Check we've managed to read at least the common node header */
-- if (retlen < min(ref->totlen, sizeof(node.u))) {
-+ if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
- printk(KERN_WARNING "short read in get_inode_nodes()\n");
- err = -EIO;
- goto free_out;
- }
-
-- switch (node.u.nodetype) {
-+ switch (je16_to_cpu(node.u.nodetype)) {
- case JFFS2_NODETYPE_DIRENT:
-- D1(printk(KERN_DEBUG "Node at %08x is a dirent node\n", ref->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
-+ BUG();
-+ }
- if (retlen < sizeof(node.d)) {
- printk(KERN_WARNING "short read in get_inode_nodes()\n");
- err = -EIO;
- goto free_out;
- }
-- if (node.d.version > *highest_version)
-- *highest_version = node.d.version;
-- if (ref->flash_offset & 1) {
-- /* Obsoleted */
-+ /* sanity check */
-+ if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
-+ ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
- continue;
- }
-+ if (je32_to_cpu(node.d.version) > *highest_version)
-+ *highest_version = je32_to_cpu(node.d.version);
-+ if (ref_obsolete(ref)) {
-+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-+ printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
-+ ref_offset(ref));
-+ BUG();
-+ }
-+
- fd = jffs2_alloc_full_dirent(node.d.nsize+1);
- if (!fd) {
- err = -ENOMEM;
-@@ -153,29 +185,30 @@
- }
- memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
- fd->raw = ref;
-- fd->version = node.d.version;
-- fd->ino = node.d.ino;
-+ fd->version = je32_to_cpu(node.d.version);
-+ fd->ino = je32_to_cpu(node.d.ino);
- fd->type = node.d.type;
-
- /* Pick out the mctime of the latest dirent */
- if(fd->version > *mctime_ver) {
- *mctime_ver = fd->version;
-- *latest_mctime = node.d.mctime;
-+ *latest_mctime = je32_to_cpu(node.d.mctime);
- }
-
- /* memcpy as much of the name as possible from the raw
- dirent we've already read from the flash
- */
- if (retlen > sizeof(struct jffs2_raw_dirent))
-- memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
-+ memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
-
- /* Do we need to copy any more of the name directly
- from the flash?
- */
- if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
-+ /* FIXME: point() */
- int already = retlen - sizeof(struct jffs2_raw_dirent);
-
-- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3) + retlen,
-+ err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
- node.d.nsize - already, &retlen, &fd->name[already]);
- if (!err && retlen != node.d.nsize - already)
- err = -EIO;
-@@ -196,21 +229,126 @@
- break;
-
- case JFFS2_NODETYPE_INODE:
-- D1(printk(KERN_DEBUG "Node at %08x is a data node\n", ref->flash_offset &~3));
-+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
- if (retlen < sizeof(node.i)) {
- printk(KERN_WARNING "read too short for dnode\n");
- err = -EIO;
- goto free_out;
- }
-- if (node.i.version > *highest_version)
-- *highest_version = node.i.version;
-- D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.i.version, *highest_version));
--
-- if (ref->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "obsoleted\n"));
-- /* Obsoleted */
-+ if (je32_to_cpu(node.i.version) > *highest_version)
-+ *highest_version = je32_to_cpu(node.i.version);
-+ D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
-+
-+ if (ref_obsolete(ref)) {
-+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-+ printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
-+ ref_offset(ref));
-+ BUG();
-+ }
-+
-+ /* If we've never checked the CRCs on this node, check them now. */
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ uint32_t crc, len;
-+ struct jffs2_eraseblock *jeb;
-+
-+ crc = crc32(0, &node, sizeof(node.i)-8);
-+ if (crc != je32_to_cpu(node.i.node_crc)) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
- continue;
- }
-+
-+ /* sanity checks */
-+ if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
-+ PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n",
-+ ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino),
-+ je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize),
-+ je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
-+ continue;
-+ }
-+
-+ if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
-+ unsigned char *buf=NULL;
-+ uint32_t pointed = 0;
-+#ifndef __ECOS
-+ if (c->mtd->point) {
-+ err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-+ &retlen, &buf);
-+ if (!err && retlen < je32_to_cpu(node.i.csize)) {
-+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
-+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
-+ } else if (err){
-+ D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
-+ } else
-+ pointed = 1; /* succefully pointed to device */
-+ }
-+#endif
-+ if(!pointed){
-+ buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-+ &retlen, buf);
-+ if (!err && retlen != je32_to_cpu(node.i.csize))
-+ err = -EIO;
-+ if (err) {
-+ kfree(buf);
-+ return err;
-+ }
-+ }
-+ crc = crc32(0, buf, je32_to_cpu(node.i.csize));
-+ if(!pointed)
-+ kfree(buf);
-+#ifndef __ECOS
-+ else
-+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
-+#endif
-+
-+ if (crc != je32_to_cpu(node.i.data_crc)) {
-+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
-+ jffs2_mark_node_obsolete(c, ref);
-+ spin_lock(&c->erase_completion_lock);
-+ continue;
-+ }
-+
-+ }
-+
-+ /* Mark the node as having been checked and fix the accounting accordingly */
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, ref);
-+
-+ jeb->used_size += len;
-+ jeb->unchecked_size -= len;
-+ c->used_size += len;
-+ c->unchecked_size -= len;
-+
-+ /* If node covers at least a whole page, or if it starts at the
-+ beginning of a page and runs to the end of the file, or if
-+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
-+
-+ If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
-+ when the overlapping node(s) get added to the tree anyway.
-+ */
-+ if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
-+ ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
-+ (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) {
-+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
-+ ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
-+ } else {
-+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
-+ ref->flash_offset = ref_offset(ref) | REF_NORMAL;
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+
- tn = jffs2_alloc_tmp_dnode_info();
- if (!tn) {
- D1(printk(KERN_DEBUG "alloc tn failed\n"));
-@@ -225,36 +363,76 @@
- jffs2_free_tmp_dnode_info(tn);
- goto free_out;
- }
-- tn->version = node.i.version;
-- tn->fn->ofs = node.i.offset;
-+ tn->version = je32_to_cpu(node.i.version);
-+ tn->fn->ofs = je32_to_cpu(node.i.offset);
- /* There was a bug where we wrote hole nodes out with
- csize/dsize swapped. Deal with it */
-- if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize)
-- tn->fn->size = node.i.csize;
-+ if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
-+ tn->fn->size = je32_to_cpu(node.i.csize);
- else // normal case...
-- tn->fn->size = node.i.dsize;
-+ tn->fn->size = je32_to_cpu(node.i.dsize);
- tn->fn->raw = ref;
-- D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize));
-+ D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
-+ ref_offset(ref), je32_to_cpu(node.i.version),
-+ je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
- jffs2_add_tn_to_list(tn, &ret_tn);
- break;
-
- default:
-- switch(node.u.nodetype & JFFS2_COMPAT_MASK) {
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ struct jffs2_eraseblock *jeb;
-+ uint32_t len;
-+
-+ printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
-+ je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+
-+ /* Mark the node as having been checked and fix the accounting accordingly */
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, ref);
-+
-+ jeb->used_size += len;
-+ jeb->unchecked_size -= len;
-+ c->used_size += len;
-+ c->unchecked_size -= len;
-+
-+ mark_ref_normal(ref);
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+ node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
-+ if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
-+ /* Hmmm. This should have been caught at scan time. */
-+ printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
-+ ref_offset(ref));
-+ printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
-+ je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
-+ je32_to_cpu(node.u.hdr_crc));
-+ jffs2_mark_node_obsolete(c, ref);
-+ } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
- case JFFS2_FEATURE_INCOMPAT:
-- printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ /* EEP */
-+ BUG();
- break;
- case JFFS2_FEATURE_ROCOMPAT:
-- printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ if (!(c->flags & JFFS2_SB_FLAG_RO))
-+ BUG();
- break;
- case JFFS2_FEATURE_RWCOMPAT_COPY:
-- printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
- break;
- case JFFS2_FEATURE_RWCOMPAT_DELETE:
-- printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3);
-+ printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-+ jffs2_mark_node_obsolete(c, ref);
- break;
- }
-+
- }
-+ spin_lock(&c->erase_completion_lock);
-+
- }
-+ spin_unlock(&c->erase_completion_lock);
- *tnp = ret_tn;
- *fdp = ret_fd;
-
-@@ -266,19 +444,30 @@
- return err;
- }
-
-+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
-+{
-+ spin_lock(&c->inocache_lock);
-+ ic->state = state;
-+ wake_up(&c->inocache_wq);
-+ spin_unlock(&c->inocache_lock);
-+}
-+
-+/* During mount, this needs no locking. During normal operation, its
-+ callers want to do other stuff while still holding the inocache_lock.
-+ Rather than introducing special case get_ino_cache functions or
-+ callbacks, we just let the caller do the locking itself. */
-+
- struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
- {
- struct jffs2_inode_cache *ret;
-
- D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
-- spin_lock (&c->inocache_lock);
-+
- ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
- while (ret && ret->ino < ino) {
- ret = ret->next;
- }
-
-- spin_unlock(&c->inocache_lock);
--
- if (ret && ret->ino != ino)
- ret = NULL;
-
-@@ -299,6 +488,7 @@
- }
- new->next = *prev;
- *prev = new;
-+
- spin_unlock(&c->inocache_lock);
- }
-
-@@ -316,6 +506,7 @@
- if ((*prev) == old) {
- *prev = old->next;
- }
-+
- spin_unlock(&c->inocache_lock);
- }
-
-@@ -352,3 +543,128 @@
- }
- }
-
-+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
-+{
-+ /* The common case in lookup is that there will be a node
-+ which precisely matches. So we go looking for that first */
-+ struct rb_node *next;
-+ struct jffs2_node_frag *prev = NULL;
-+ struct jffs2_node_frag *frag = NULL;
-+
-+ D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
-+
-+ next = fragtree->rb_node;
-+
-+ while(next) {
-+ frag = rb_entry(next, struct jffs2_node_frag, rb);
-+
-+ D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
-+ frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
-+ if (frag->ofs + frag->size <= offset) {
-+ D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ /* Remember the closest smaller match on the way down */
-+ if (!prev || frag->ofs > prev->ofs)
-+ prev = frag;
-+ next = frag->rb.rb_right;
-+ } else if (frag->ofs > offset) {
-+ D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ next = frag->rb.rb_left;
-+ } else {
-+ D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
-+ frag->ofs, frag->ofs+frag->size));
-+ return frag;
-+ }
-+ }
-+
-+ /* Exact match not found. Go back up looking at each parent,
-+ and return the closest smaller one */
-+
-+ if (prev)
-+ D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
-+ prev->ofs, prev->ofs+prev->size));
-+ else
-+ D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
-+
-+ return prev;
-+}
-+
-+/* Pass 'c' argument to indicate that nodes should be marked obsolete as
-+ they're killed. */
-+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
-+{
-+ struct jffs2_node_frag *frag;
-+ struct jffs2_node_frag *parent;
-+
-+ if (!root->rb_node)
-+ return;
-+
-+ frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
-+
-+ while(frag) {
-+ if (frag->rb.rb_left) {
-+ D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n",
-+ frag, frag->ofs, frag->ofs+frag->size));
-+ frag = frag_left(frag);
-+ continue;
-+ }
-+ if (frag->rb.rb_right) {
-+ D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n",
-+ frag, frag->ofs, frag->ofs+frag->size));
-+ frag = frag_right(frag);
-+ continue;
-+ }
-+
-+ D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
-+ frag->ofs, frag->ofs+frag->size, frag->node,
-+ frag->node?frag->node->frags:0));
-+
-+ if (frag->node && !(--frag->node->frags)) {
-+ /* Not a hole, and it's the final remaining frag
-+ of this node. Free the node */
-+ if (c)
-+ jffs2_mark_node_obsolete(c, frag->node->raw);
-+
-+ jffs2_free_full_dnode(frag->node);
-+ }
-+ parent = frag_parent(frag);
-+ if (parent) {
-+ if (frag_left(parent) == frag)
-+ parent->rb.rb_left = NULL;
-+ else
-+ parent->rb.rb_right = NULL;
-+ }
-+
-+ jffs2_free_node_frag(frag);
-+ frag = parent;
-+
-+ cond_resched();
-+ }
-+}
-+
-+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
-+{
-+ struct rb_node *parent = &base->rb;
-+ struct rb_node **link = &parent;
-+
-+ D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag,
-+ newfrag->ofs, newfrag->ofs+newfrag->size, base));
-+
-+ while (*link) {
-+ parent = *link;
-+ base = rb_entry(parent, struct jffs2_node_frag, rb);
-+
-+ D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
-+ if (newfrag->ofs > base->ofs)
-+ link = &base->rb.rb_right;
-+ else if (newfrag->ofs < base->ofs)
-+ link = &base->rb.rb_left;
-+ else {
-+ printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
-+ BUG();
-+ }
-+ }
-+
-+ rb_link_node(&newfrag->rb, &base->rb, link);
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/nodelist.h linux/fs/jffs2/nodelist.h
---- linux-mips-2.4.27/fs/jffs2/nodelist.h 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/nodelist.h 2004-11-19 10:25:12.113167264 +0100
-@@ -1,48 +1,35 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-+#ifndef __JFFS2_NODELIST_H__
-+#define __JFFS2_NODELIST_H__
-+
- #include <linux/config.h>
- #include <linux/fs.h>
--
-+#include <linux/types.h>
-+#include <linux/jffs2.h>
- #include <linux/jffs2_fs_sb.h>
- #include <linux/jffs2_fs_i.h>
-
-+#ifdef __ECOS
-+#include "os-ecos.h"
-+#else
-+#include <linux/mtd/compatmac.h> /* For min/max in older kernels */
-+#include "os-linux.h"
-+#endif
-+
- #ifndef CONFIG_JFFS2_FS_DEBUG
--#define CONFIG_JFFS2_FS_DEBUG 2
-+#define CONFIG_JFFS2_FS_DEBUG 1
- #endif
-
- #if CONFIG_JFFS2_FS_DEBUG > 0
-@@ -71,17 +58,21 @@
- for this inode instead. The inode_cache will have NULL in the first
- word so you know when you've got there :) */
- struct jffs2_raw_node_ref *next_phys;
-- // __u32 ino;
-- __u32 flash_offset;
-- __u32 totlen;
--// __u16 nodetype;
-+ uint32_t flash_offset;
-+ uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
-+};
-
- /* flash_offset & 3 always has to be zero, because nodes are
- always aligned at 4 bytes. So we have a couple of extra bits
-- to play with. So we set the least significant bit to 1 to
-- signify that the node is obsoleted by later nodes.
-- */
--};
-+ to play with, which indicate the node's status; see below: */
-+#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */
-+#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */
-+#define REF_PRISTINE 2 /* Completely clean. GC without looking */
-+#define REF_NORMAL 3 /* Possibly overlapped. Read the page and write again on GC */
-+#define ref_flags(ref) ((ref)->flash_offset & 3)
-+#define ref_offset(ref) ((ref)->flash_offset & ~3)
-+#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
-+#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
-
- /*
- Used for keeping track of deletion nodes &c, which can only be marked
-@@ -101,19 +92,35 @@
- a pointer to the first physical node which is part of this inode, too.
- */
- struct jffs2_inode_cache {
-- struct jffs2_scan_info *scan; /* Used during scan to hold
-- temporary lists of nodes, and later must be set to
-+ struct jffs2_full_dirent *scan_dents; /* Used during scan to hold
-+ temporary lists of dirents, and later must be set to
- NULL to mark the end of the raw_node_ref->next_in_ino
- chain. */
- struct jffs2_inode_cache *next;
- struct jffs2_raw_node_ref *nodes;
-- __u32 ino;
-+ uint32_t ino;
- int nlink;
-+ int state;
- };
-
-+/* Inode states for 'state' above. We need the 'GC' state to prevent
-+ someone from doing a read_inode() while we're moving a 'REF_PRISTINE'
-+ node without going through all the iget() nonsense */
-+#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */
-+#define INO_STATE_CHECKING 1 /* CRC checks in progress */
-+#define INO_STATE_PRESENT 2 /* In core */
-+#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */
-+#define INO_STATE_GC 4 /* GCing a 'pristine' node */
-+#define INO_STATE_READING 5 /* In read_inode() */
-+
-+#define INOCACHE_HASHSIZE 128
-+
- struct jffs2_scan_info {
- struct jffs2_full_dirent *dents;
- struct jffs2_tmp_dnode_info *tmpnodes;
-+ /* Latest i_size info */
-+ uint32_t version;
-+ uint32_t isize;
- };
- /*
- Larger representation of a raw node, kept in-core only when the
-@@ -123,9 +130,9 @@
- struct jffs2_full_dnode
- {
- struct jffs2_raw_node_ref *raw;
-- __u32 ofs; /* Don't really need this, but optimisation */
-- __u32 size;
-- __u32 frags; /* Number of fragments which currently refer
-+ uint32_t ofs; /* Don't really need this, but optimisation */
-+ uint32_t size;
-+ uint32_t frags; /* Number of fragments which currently refer
- to this node. When this reaches zero,
- the node is obsolete.
- */
-@@ -140,15 +147,15 @@
- {
- struct jffs2_tmp_dnode_info *next;
- struct jffs2_full_dnode *fn;
-- __u32 version;
-+ uint32_t version;
- };
-
- struct jffs2_full_dirent
- {
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *next;
-- __u32 version;
-- __u32 ino; /* == zero for unlink */
-+ uint32_t version;
-+ uint32_t ino; /* == zero for unlink */
- unsigned int nhash;
- unsigned char type;
- unsigned char name[0];
-@@ -159,21 +166,23 @@
- */
- struct jffs2_node_frag
- {
-- struct jffs2_node_frag *next;
-+ struct rb_node rb;
- struct jffs2_full_dnode *node; /* NULL for holes */
-- __u32 size;
-- __u32 ofs; /* Don't really need this, but optimisation */
-+ uint32_t size;
-+ uint32_t ofs; /* Don't really need this, but optimisation */
- };
-
- struct jffs2_eraseblock
- {
- struct list_head list;
- int bad_count;
-- __u32 offset; /* of this block in the MTD */
-+ uint32_t offset; /* of this block in the MTD */
-
-- __u32 used_size;
-- __u32 dirty_size;
-- __u32 free_size; /* Note that sector_size - free_size
-+ uint32_t unchecked_size;
-+ uint32_t used_size;
-+ uint32_t dirty_size;
-+ uint32_t wasted_size;
-+ uint32_t free_size; /* Note that sector_size - free_size
- is the address of the first free space */
- struct jffs2_raw_node_ref *first_node;
- struct jffs2_raw_node_ref *last_node;
-@@ -190,45 +199,134 @@
- };
-
- #define ACCT_SANITY_CHECK(c, jeb) do { \
-- if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \
-- printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
-- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \
-- jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \
-+ struct jffs2_eraseblock *___j = jeb; \
-+ if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \
-+ printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \
-+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
-+ ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \
- BUG(); \
- } \
-- if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \
-+ if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
- printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \
-- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \
-- c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \
-+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \
-+ c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \
- BUG(); \
- } \
- } while(0)
-
-+static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_raw_node_ref *ref;
-+ int i=0;
-+
-+ printk(KERN_NOTICE);
-+ for (ref = jeb->first_node; ref; ref = ref->next_phys) {
-+ printk("%08x->", ref_offset(ref));
-+ if (++i == 8) {
-+ i = 0;
-+ printk("\n" KERN_NOTICE);
-+ }
-+ }
-+ printk("\n");
-+}
-+
-+
- #define ACCT_PARANOIA_CHECK(jeb) do { \
-- __u32 my_used_size = 0; \
-+ uint32_t my_used_size = 0; \
-+ uint32_t my_unchecked_size = 0; \
- struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
- while (ref2) { \
-- if (!(ref2->flash_offset & 1)) \
-- my_used_size += ref2->totlen; \
-+ if (unlikely(ref2->flash_offset < jeb->offset || \
-+ ref2->flash_offset > jeb->offset + c->sector_size)) { \
-+ printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \
-+ ref_offset(ref2), jeb->offset); \
-+ paranoia_failed_dump(jeb); \
-+ BUG(); \
-+ } \
-+ if (ref_flags(ref2) == REF_UNCHECKED) \
-+ my_unchecked_size += ref_totlen(c, jeb, ref2); \
-+ else if (!ref_obsolete(ref2)) \
-+ my_used_size += ref_totlen(c, jeb, ref2); \
-+ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
-+ printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
-+ ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
-+ jeb->last_node, ref_offset(jeb->last_node)); \
-+ paranoia_failed_dump(jeb); \
-+ BUG(); \
-+ } \
- ref2 = ref2->next_phys; \
- } \
- if (my_used_size != jeb->used_size) { \
- printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
- BUG(); \
- } \
-+ if (my_unchecked_size != jeb->unchecked_size) { \
-+ printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \
-+ BUG(); \
-+ } \
- } while(0)
-
-+/* Calculate totlen from surrounding nodes or eraseblock */
-+static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
-+ struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *ref)
-+{
-+ uint32_t ref_end;
-+
-+ if (ref->next_phys)
-+ ref_end = ref_offset(ref->next_phys);
-+ else {
-+ if (!jeb)
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+
-+ /* Last node in block. Use free_space */
-+ BUG_ON(ref != jeb->last_node);
-+ ref_end = jeb->offset + c->sector_size - jeb->free_size;
-+ }
-+ return ref_end - ref_offset(ref);
-+}
-+
-+static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
-+ struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_node_ref *ref)
-+{
-+ uint32_t ret;
-+
-+ D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
-+ printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
-+ jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
-+ BUG();
-+ })
-+
-+#if 1
-+ ret = ref->__totlen;
-+#else
-+ /* This doesn't actually work yet */
-+ ret = __ref_totlen(c, jeb, ref);
-+ if (ret != ref->__totlen) {
-+ printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
-+ ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
-+ ret, ref->__totlen);
-+ if (!jeb)
-+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
-+ paranoia_failed_dump(jeb);
-+ BUG();
-+ }
-+#endif
-+ return ret;
-+}
-+
-+
- #define ALLOC_NORMAL 0 /* Normal allocation */
- #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
- #define ALLOC_GC 2 /* Space requested for GC. Give it or die */
-+#define ALLOC_NORETRY 3 /* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */
-
--#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */
--#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */
--#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */
--#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */
--#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */
--#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */
-+/* How much dirty space before it goes on the very_dirty_list */
-+#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
-
-+/* check if dirty space is more than 255 Byte */
-+#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
-
- #define PAD(x) (((x)+3)&~3)
-
-@@ -241,43 +339,75 @@
- return ((struct jffs2_inode_cache *)raw);
- }
-
-+static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
-+{
-+ struct rb_node *node = root->rb_node;
-+
-+ if (!node)
-+ return NULL;
-+ while(node->rb_left)
-+ node = node->rb_left;
-+ return rb_entry(node, struct jffs2_node_frag, rb);
-+}
-+#define rb_parent(rb) ((rb)->rb_parent)
-+#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
-+#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb)
-+#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
-+#define frag_erase(frag, list) rb_erase(&frag->rb, list);
-+
- /* nodelist.c */
- D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
- void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
--void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
- int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-- __u32 *highest_version, __u32 *latest_mctime,
-- __u32 *mctime_ver);
-+ uint32_t *highest_version, uint32_t *latest_mctime,
-+ uint32_t *mctime_ver);
-+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
- struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
- void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new);
- void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
- void jffs2_free_ino_caches(struct jffs2_sb_info *c);
- void jffs2_free_raw_node_refs(struct jffs2_sb_info *c);
-+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset);
-+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete);
-+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base);
-+struct rb_node *rb_next(struct rb_node *);
-+struct rb_node *rb_prev(struct rb_node *);
-+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
-
- /* nodemgmt.c */
--int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio);
--int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len);
--int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty);
-+int jffs2_thread_should_wake(struct jffs2_sb_info *c);
-+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
-+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
-+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
- void jffs2_complete_reservation(struct jffs2_sb_info *c);
- void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
-+void jffs2_dump_block_lists(struct jffs2_sb_info *c);
-
- /* write.c */
--struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri);
--struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen);
--struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen);
-+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri);
-+
-+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode);
-+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode);
-+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *ri, unsigned char *buf,
-+ uint32_t offset, uint32_t writelen, uint32_t *retlen);
-+int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen);
-+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f);
-+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen);
-+
-
- /* readinode.c */
--void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size);
--int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn);
-+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
- int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
--void jffs2_read_inode (struct inode *);
--void jffs2_clear_inode (struct inode *);
-+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ uint32_t ino, struct jffs2_raw_inode *latest_node);
-+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
-+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
-
- /* malloc.c */
--void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn);
--void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd);
--
- int jffs2_create_slab_caches(void);
- void jffs2_destroy_slab_caches(void);
-
-@@ -301,54 +431,41 @@
- /* gc.c */
- int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
-
--/* background.c */
--int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
--void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
--void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
--
--/* dir.c */
--extern struct file_operations jffs2_dir_operations;
--extern struct inode_operations jffs2_dir_inode_operations;
--
--/* file.c */
--extern struct file_operations jffs2_file_operations;
--extern struct inode_operations jffs2_file_inode_operations;
--extern struct address_space_operations jffs2_file_address_operations;
--int jffs2_null_fsync(struct file *, struct dentry *, int);
--int jffs2_setattr (struct dentry *dentry, struct iattr *iattr);
--int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
--int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
--int jffs2_readpage (struct file *, struct page *);
--int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
--int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
--
--/* ioctl.c */
--int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
--
- /* read.c */
- int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len);
-+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ unsigned char *buf, uint32_t offset, uint32_t len);
-+char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
-
- /* compr.c */
--unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-- __u32 *datalen, __u32 *cdatalen);
-+unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
-+ uint32_t *datalen, uint32_t *cdatalen);
-+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
- int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-- unsigned char *data_out, __u32 cdatalen, __u32 datalen);
-+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-
- /* scan.c */
- int jffs2_scan_medium(struct jffs2_sb_info *c);
-+void jffs2_rotate_lists(struct jffs2_sb_info *c);
-
- /* build.c */
--int jffs2_build_filesystem(struct jffs2_sb_info *c);
--
--/* symlink.c */
--extern struct inode_operations jffs2_symlink_inode_operations;
-+int jffs2_do_mount_fs(struct jffs2_sb_info *c);
-
- /* erase.c */
- void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
--void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
--void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
--void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
-+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
-+
-+#ifdef CONFIG_JFFS2_FS_NAND
-+/* wbuf.c */
-+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
-+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
-+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+#endif
-
- /* compr_zlib.c */
- int jffs2_zlib_init(void);
- void jffs2_zlib_exit(void);
-+
-+#endif /* __JFFS2_NODELIST_H__ */
-diff -Nurb linux-mips-2.4.27/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c
---- linux-mips-2.4.27/fs/jffs2/nodemgmt.c 2002-06-27 00:36:20.000000000 +0200
-+++ linux/fs/jffs2/nodemgmt.c 2004-11-19 10:25:12.115166960 +0100
-@@ -1,45 +1,21 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
-+#include <linux/compiler.h>
-+#include <linux/sched.h> /* For cond_resched() */
- #include "nodelist.h"
-
- /**
-@@ -62,53 +38,95 @@
- * for the requested allocation.
- */
-
--static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len);
-+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
-
--int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio)
-+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
- {
- int ret = -EAGAIN;
-- int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
-+ int blocksneeded = c->resv_blocks_write;
- /* align it */
- minsize = PAD(minsize);
-
-- if (prio == ALLOC_DELETION)
-- blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
--
- D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
- down(&c->alloc_sem);
-
- D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
-
-- /* this needs a little more thought */
-+ /* this needs a little more thought (true <tglx> :)) */
- while(ret == -EAGAIN) {
- while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
- int ret;
-+ uint32_t dirty, avail;
-+
-+ /* calculate real dirty size
-+ * dirty_size contains blocks on erase_pending_list
-+ * those blocks are counted in c->nr_erasing_blocks.
-+ * If one block is actually erased, it is not longer counted as dirty_space
-+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
-+ * with c->nr_erasing_blocks * c->sector_size again.
-+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
-+ * This helps us to force gc and pick eventually a clean block to spread the load.
-+ * We add unchecked_size here, as we hopefully will find some space to use.
-+ * This will affect the sum only once, as gc first finishes checking
-+ * of nodes.
-+ */
-+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
-+ if (dirty < c->nospc_dirty_size) {
-+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
-+ break;
-+ }
-+ D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
-+ dirty, c->unchecked_size, c->sector_size));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ up(&c->alloc_sem);
-+ return -ENOSPC;
-+ }
-
-+ /* Calc possibly available space. Possibly available means that we
-+ * don't know, if unchecked size contains obsoleted nodes, which could give us some
-+ * more usable space. This will affect the sum only once, as gc first finishes checking
-+ * of nodes.
-+ + Return -ENOSPC, if the maximum possibly available space is less or equal than
-+ * blocksneeded * sector_size.
-+ * This blocks endless gc looping on a filesystem, which is nearly full, even if
-+ * the check above passes.
-+ */
-+ avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
-+ if ( (avail / c->sector_size) <= blocksneeded) {
-+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
-+ break;
-+ }
-+
-+ D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
-+ avail, blocksneeded * c->sector_size));
-+ spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
-- if (c->dirty_size < c->sector_size) {
-- D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size));
-- spin_unlock_bh(&c->erase_completion_lock);
- return -ENOSPC;
- }
-- D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
-- c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
-- c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
-- spin_unlock_bh(&c->erase_completion_lock);
-+
-+ up(&c->alloc_sem);
-+
-+ D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
-+ c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
-+ c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
-+ spin_unlock(&c->erase_completion_lock);
-
- ret = jffs2_garbage_collect_pass(c);
- if (ret)
- return ret;
-
-- if (current->need_resched)
-- schedule();
-+ cond_resched();
-
- if (signal_pending(current))
- return -EINTR;
-
- down(&c->alloc_sem);
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- }
-
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
-@@ -116,45 +134,72 @@
- D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
- }
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- if (ret)
- up(&c->alloc_sem);
- return ret;
- }
-
--int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
-+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
- {
- int ret = -EAGAIN;
- minsize = PAD(minsize);
-
- D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
-
-- spin_lock_bh(&c->erase_completion_lock);
-+ spin_lock(&c->erase_completion_lock);
- while(ret == -EAGAIN) {
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
- if (ret) {
- D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
- }
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- return ret;
- }
-
- /* Called with alloc sem _and_ erase_completion_lock */
--static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
-+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
- {
- struct jffs2_eraseblock *jeb = c->nextblock;
-
- restart:
- if (jeb && minsize > jeb->free_size) {
- /* Skip the end of this block and file it as having some dirty space */
-- c->dirty_size += jeb->free_size;
-+ /* If there's a pending write to it, flush now */
-+ if (jffs2_wbuf_dirty(c)) {
-+ spin_unlock(&c->erase_completion_lock);
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ jeb = c->nextblock;
-+ goto restart;
-+ }
-+ c->wasted_size += jeb->free_size;
- c->free_size -= jeb->free_size;
-- jeb->dirty_size += jeb->free_size;
-+ jeb->wasted_size += jeb->free_size;
- jeb->free_size = 0;
-+
-+ /* Check, if we have a dirty block now, or if it was dirty already */
-+ if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->dirty_size += jeb->wasted_size;
-+ jeb->wasted_size = 0;
-+ if (VERYDIRTY(c, jeb->dirty_size)) {
-+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ list_add_tail(&jeb->list, &c->very_dirty_list);
-+ } else {
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- list_add_tail(&jeb->list, &c->dirty_list);
-+ }
-+ } else {
-+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ list_add_tail(&jeb->list, &c->clean_list);
-+ }
- c->nextblock = jeb = NULL;
- }
-
-@@ -164,33 +209,44 @@
-
- if (list_empty(&c->free_list)) {
-
-- DECLARE_WAITQUEUE(wait, current);
-+ if (!c->nr_erasing_blocks &&
-+ !list_empty(&c->erasable_list)) {
-+ struct jffs2_eraseblock *ejeb;
-+
-+ ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
-+ list_del(&ejeb->list);
-+ list_add_tail(&ejeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
-+ ejeb->offset));
-+ }
-+
-+ if (!c->nr_erasing_blocks &&
-+ !list_empty(&c->erasable_pending_wbuf_list)) {
-+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-+ /* c->nextblock is NULL, no update to c->nextblock allowed */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ /* Have another go. It'll be on the erasable_list now */
-+ return -EAGAIN;
-+ }
-
- if (!c->nr_erasing_blocks) {
--// if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) {
- /* Ouch. We're in GC, or we wouldn't have got here.
- And there's no space left. At all. */
-- printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
-- c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
-+ printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
-+ c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
-+ list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
- return -ENOSPC;
- }
-- /* Make sure this can't deadlock. Someone has to start the erases
-- of erase_pending blocks */
-- set_current_state(TASK_INTERRUPTIBLE);
-- add_wait_queue(&c->erase_wait, &wait);
-- D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
-- c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
-- if (!list_empty(&c->erase_pending_list)) {
-- D1(printk(KERN_DEBUG "Triggering pending erases\n"));
-- jffs2_erase_pending_trigger(c);
-- }
-- spin_unlock_bh(&c->erase_completion_lock);
-- schedule();
-- remove_wait_queue(&c->erase_wait, &wait);
-- spin_lock_bh(&c->erase_completion_lock);
-- if (signal_pending(current)) {
-- return -EINTR;
-- }
-+
-+ spin_unlock(&c->erase_completion_lock);
-+ /* Don't wait for it; just erase one right now */
-+ jffs2_erase_pending_blocks(c, 1);
-+ spin_lock(&c->erase_completion_lock);
-+
- /* An erase may have failed, decreasing the
- amount of free space available. So we must
- restart from the beginning */
-@@ -201,7 +257,8 @@
- list_del(next);
- c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
- c->nr_free_blocks--;
-- if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) {
-+
-+ if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
- printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
- goto restart;
- }
-@@ -210,6 +267,20 @@
- enough space */
- *ofs = jeb->offset + (c->sector_size - jeb->free_size);
- *len = jeb->free_size;
-+
-+ if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
-+ !jeb->first_node->next_in_ino) {
-+ /* Only node in it beforehand was a CLEANMARKER node (we think).
-+ So mark it obsolete now that there's going to be another node
-+ in the block. This will reduce used_size to zero but We've
-+ already set c->nextblock so that jffs2_mark_node_obsolete()
-+ won't try to refile it to the dirty_list.
-+ */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_mark_node_obsolete(c, jeb->first_node);
-+ spin_lock(&c->erase_completion_lock);
-+ }
-+
- D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
- return 0;
- }
-@@ -217,9 +288,9 @@
- /**
- * jffs2_add_physical_node_ref - add a physical node reference to the list
- * @c: superblock info
-- * @ofs: physical location of this physical node
-+ * @new: new node reference to add
- * @len: length of this physical node
-- * @ino: inode number with which this physical node is associated
-+ * @dirty: dirty flag for new node
- *
- * Should only be used to report nodes for which space has been allocated
- * by jffs2_reserve_space.
-@@ -227,47 +298,58 @@
- * Must be called with the alloc_sem held.
- */
-
--int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty)
-+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
- {
- struct jffs2_eraseblock *jeb;
-+ uint32_t len;
-+
-+ jeb = &c->blocks[new->flash_offset / c->sector_size];
-+ len = ref_totlen(c, jeb, new);
-
-- len = PAD(len);
-- jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size];
-- D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len));
-+ D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
- #if 1
-- if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) {
-+ if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
- printk(KERN_WARNING "argh. node added in wrong place\n");
- jffs2_free_raw_node_ref(new);
- return -EINVAL;
- }
- #endif
-+ spin_lock(&c->erase_completion_lock);
-+
- if (!jeb->first_node)
- jeb->first_node = new;
- if (jeb->last_node)
- jeb->last_node->next_phys = new;
- jeb->last_node = new;
-
-- spin_lock_bh(&c->erase_completion_lock);
- jeb->free_size -= len;
- c->free_size -= len;
-- if (dirty) {
-- new->flash_offset |= 1;
-+ if (ref_obsolete(new)) {
- jeb->dirty_size += len;
- c->dirty_size += len;
- } else {
- jeb->used_size += len;
- c->used_size += len;
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-+
- if (!jeb->free_size && !jeb->dirty_size) {
- /* If it lives on the dirty_list, jffs2_reserve_space will put it there */
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-+ if (jffs2_wbuf_dirty(c)) {
-+ /* Flush the last write in the block if it's outstanding */
-+ spin_unlock(&c->erase_completion_lock);
-+ jffs2_flush_wbuf_pad(c);
-+ spin_lock(&c->erase_completion_lock);
-+ }
-+
- list_add_tail(&jeb->list, &c->clean_list);
- c->nextblock = NULL;
- }
- ACCT_SANITY_CHECK(c,jeb);
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ spin_unlock(&c->erase_completion_lock);
-
- return 0;
- }
-@@ -280,20 +362,34 @@
- up(&c->alloc_sem);
- }
-
-+static inline int on_list(struct list_head *obj, struct list_head *head)
-+{
-+ struct list_head *this;
-+
-+ list_for_each(this, head) {
-+ if (this == obj) {
-+ D1(printk("%p is on list at %p\n", obj, head));
-+ return 1;
-+
-+ }
-+ }
-+ return 0;
-+}
-+
- void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
- {
- struct jffs2_eraseblock *jeb;
- int blocknr;
- struct jffs2_unknown_node n;
-- int ret;
-- ssize_t retlen;
-+ int ret, addedsize;
-+ size_t retlen;
-
- if(!ref) {
- printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
- return;
- }
-- if (ref->flash_offset & 1) {
-- D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3));
-+ if (ref_obsolete(ref)) {
-+ D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref)));
- return;
- }
- blocknr = ref->flash_offset / c->sector_size;
-@@ -302,22 +398,63 @@
- BUG();
- }
- jeb = &c->blocks[blocknr];
-- if (jeb->used_size < ref->totlen) {
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ if (ref_flags(ref) == REF_UNCHECKED) {
-+ D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
-+ printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
-+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
-+ BUG();
-+ })
-+ D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
-+ jeb->unchecked_size -= ref_totlen(c, jeb, ref);
-+ c->unchecked_size -= ref_totlen(c, jeb, ref);
-+ } else {
-+ D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
- printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
-- ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
-+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
- BUG();
-+ })
-+ D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
-+ jeb->used_size -= ref_totlen(c, jeb, ref);
-+ c->used_size -= ref_totlen(c, jeb, ref);
-+ }
-+
-+ // Take care, that wasted size is taken into concern
-+ if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
-+ D1(printk("Dirtying\n"));
-+ addedsize = ref_totlen(c, jeb, ref);
-+ jeb->dirty_size += ref_totlen(c, jeb, ref);
-+ c->dirty_size += ref_totlen(c, jeb, ref);
-+
-+ /* Convert wasted space to dirty, if not a bad block */
-+ if (jeb->wasted_size) {
-+ if (on_list(&jeb->list, &c->bad_used_list)) {
-+ D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n",
-+ jeb->offset));
-+ addedsize = 0; /* To fool the refiling code later */
-+ } else {
-+ D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n",
-+ jeb->wasted_size, jeb->offset));
-+ addedsize += jeb->wasted_size;
-+ jeb->dirty_size += jeb->wasted_size;
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->wasted_size = 0;
- }
--
-- spin_lock_bh(&c->erase_completion_lock);
-- jeb->used_size -= ref->totlen;
-- jeb->dirty_size += ref->totlen;
-- c->used_size -= ref->totlen;
-- c->dirty_size += ref->totlen;
-- ref->flash_offset |= 1;
-+ }
-+ } else {
-+ D1(printk("Wasting\n"));
-+ addedsize = 0;
-+ jeb->wasted_size += ref_totlen(c, jeb, ref);
-+ c->wasted_size += ref_totlen(c, jeb, ref);
-+ }
-+ ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
-
- ACCT_SANITY_CHECK(c, jeb);
-
-- ACCT_PARANOIA_CHECK(jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-
- if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
- /* Mount in progress. Don't muck about with the block
-@@ -325,68 +462,280 @@
- obliterate nodes that look obsolete. If they weren't
- marked obsolete on the flash at the time they _became_
- obsolete, there was probably a reason for that. */
-- spin_unlock_bh(&c->erase_completion_lock);
-+ spin_unlock(&c->erase_completion_lock);
- return;
- }
-+
- if (jeb == c->nextblock) {
- D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
-- } else if (jeb == c->gcblock) {
-- D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
--#if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static
-- data and a few blocks free, and you just create new files and keep deleting/overwriting
-- them, then you'd keep erasing and reusing those blocks without ever moving stuff around.
-- So we leave completely obsoleted blocks on the dirty_list and let the GC delete them
-- when it finds them there. That way, we still get the 'once in a while, take a clean block'
-- to spread out the flash usage */
-- } else if (!jeb->used_size) {
-+ } else if (!jeb->used_size && !jeb->unchecked_size) {
-+ if (jeb == c->gcblock) {
-+ D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset));
-+ c->gcblock = NULL;
-+ } else {
- D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
- list_del(&jeb->list);
-+ }
-+ if (jffs2_wbuf_dirty(c)) {
-+ D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
-+ } else {
-+ if (jiffies & 127) {
-+ /* Most of the time, we just erase it immediately. Otherwise we
-+ spend ages scanning it on mount, etc. */
- D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
- list_add_tail(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
-- // OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+ } else {
-+ /* Sometimes, however, we leave it elsewhere so it doesn't get
-+ immediately reused, and we spread the load a bit. */
-+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_list);
-+ }
-+ }
- D1(printk(KERN_DEBUG "Done OK\n"));
--#endif
-- } else if (jeb->dirty_size == ref->totlen) {
-+ } else if (jeb == c->gcblock) {
-+ D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset));
-+ } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) {
- D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
- list_del(&jeb->list);
- D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
- list_add_tail(&jeb->list, &c->dirty_list);
-+ } else if (VERYDIRTY(c, jeb->dirty_size) &&
-+ !VERYDIRTY(c, jeb->dirty_size - addedsize)) {
-+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
-+ list_del(&jeb->list);
-+ D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
-+ list_add_tail(&jeb->list, &c->very_dirty_list);
-+ } else {
-+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
-+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- }
-- spin_unlock_bh(&c->erase_completion_lock);
-
-- if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM)
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ if (!jffs2_can_mark_obsolete(c))
- return;
-- if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
-+ if (jffs2_is_readonly(c))
- return;
-
-- D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3));
-- ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n);
-+ D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
-+ ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
- if (ret) {
-- printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
-+ printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
- return;
- }
- if (retlen != sizeof(n)) {
-- printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
-+ printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
- return;
- }
-- if (PAD(n.totlen) != PAD(ref->totlen)) {
-- printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen);
-+ if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
-+ printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
- return;
- }
-- if (!(n.nodetype & JFFS2_NODE_ACCURATE)) {
-- D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype));
-+ if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
-+ D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
- return;
- }
-- n.nodetype &= ~JFFS2_NODE_ACCURATE;
-- ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n);
-+ /* XXX FIXME: This is ugly now */
-+ n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
-+ ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
- if (ret) {
-- printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
-+ printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
- return;
- }
- if (retlen != sizeof(n)) {
-- printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
-+ printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
- return;
- }
- }
-+
-+#if CONFIG_JFFS2_FS_DEBUG > 0
-+void jffs2_dump_block_lists(struct jffs2_sb_info *c)
-+{
-+
-+
-+ printk(KERN_DEBUG "jffs2_dump_block_lists:\n");
-+ printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-+ printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-+ printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-+ printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size);
-+ printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size);
-+ printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-+ printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-+ printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-+ printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-+ printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write);
-+
-+ if (c->nextblock) {
-+ printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size);
-+ } else {
-+ printk(KERN_DEBUG "nextblock: NULL\n");
-+ }
-+ if (c->gcblock) {
-+ printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
-+ } else {
-+ printk(KERN_DEBUG "gcblock: NULL\n");
-+ }
-+ if (list_empty(&c->clean_list)) {
-+ printk(KERN_DEBUG "clean_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->clean_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->wasted_size;
-+ printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->very_dirty_list)) {
-+ printk(KERN_DEBUG "very_dirty_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->very_dirty_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->dirty_size;
-+ printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-+ numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->dirty_list)) {
-+ printk(KERN_DEBUG "dirty_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+ int numblocks = 0;
-+ uint32_t dirty = 0;
-+
-+ list_for_each(this, &c->dirty_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ numblocks ++;
-+ dirty += jeb->dirty_size;
-+ printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-+ numblocks, dirty, dirty / numblocks);
-+ }
-+ if (list_empty(&c->erasable_list)) {
-+ printk(KERN_DEBUG "erasable_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasable_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erasing_list)) {
-+ printk(KERN_DEBUG "erasing_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasing_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erase_pending_list)) {
-+ printk(KERN_DEBUG "erase_pending_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erase_pending_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->erasable_pending_wbuf_list)) {
-+ printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->erasable_pending_wbuf_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->free_list)) {
-+ printk(KERN_DEBUG "free_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->free_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->bad_list)) {
-+ printk(KERN_DEBUG "bad_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->bad_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+ if (list_empty(&c->bad_used_list)) {
-+ printk(KERN_DEBUG "bad_used_list: empty\n");
-+ } else {
-+ struct list_head *this;
-+
-+ list_for_each(this, &c->bad_used_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+ printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-+ }
-+ }
-+}
-+#endif /* CONFIG_JFFS2_FS_DEBUG */
-+
-+int jffs2_thread_should_wake(struct jffs2_sb_info *c)
-+{
-+ int ret = 0;
-+ uint32_t dirty;
-+
-+ if (c->unchecked_size) {
-+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
-+ c->unchecked_size, c->checked_ino));
-+ return 1;
-+ }
-+
-+ /* dirty_size contains blocks on erase_pending_list
-+ * those blocks are counted in c->nr_erasing_blocks.
-+ * If one block is actually erased, it is not longer counted as dirty_space
-+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
-+ * with c->nr_erasing_blocks * c->sector_size again.
-+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
-+ * This helps us to force gc and pick eventually a clean block to spread the load.
-+ */
-+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
-+
-+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
-+ (dirty > c->nospc_dirty_size))
-+ ret = 1;
-+
-+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
-+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
-+
-+ return ret;
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/os-linux.h linux/fs/jffs2/os-linux.h
---- linux-mips-2.4.27/fs/jffs2/os-linux.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/os-linux.h 2004-11-19 10:25:12.116166808 +0100
-@@ -0,0 +1,212 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2002-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@redhat.com>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#ifndef __JFFS2_OS_LINUX_H__
-+#define __JFFS2_OS_LINUX_H__
-+#include <linux/version.h>
-+
-+/* JFFS2 uses Linux mode bits natively -- no need for conversion */
-+#define os_to_jffs2_mode(x) (x)
-+#define jffs2_to_os_mode(x) (x)
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-+#define kstatfs statfs
-+#endif
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
-+#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
-+#define JFFS2_SB_INFO(sb) (sb->s_fs_info)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv)
-+#elif defined(JFFS2_OUT_OF_KERNEL)
-+#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
-+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-+#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+#else
-+#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
-+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-+#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+#endif
-+
-+
-+#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
-+#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
-+#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
-+#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
-+#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f)))
-+#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f)))
-+#else
-+#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-+#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-+#endif
-+
-+/* Urgh. The things we do to keep the 2.4 build working */
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)
-+#define ITIME(sec) ((struct timespec){sec, 0})
-+#define I_SEC(tv) ((tv).tv_sec)
-+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
-+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
-+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
-+#else
-+#define ITIME(x) (x)
-+#define I_SEC(x) (x)
-+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
-+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
-+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
-+#endif
-+
-+#define sleep_on_spinunlock(wq, s) \
-+ do { \
-+ DECLARE_WAITQUEUE(__wait, current); \
-+ add_wait_queue((wq), &__wait); \
-+ set_current_state(TASK_UNINTERRUPTIBLE); \
-+ spin_unlock(s); \
-+ schedule(); \
-+ remove_wait_queue((wq), &__wait); \
-+ } while(0)
-+
-+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
-+{
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+ f->highest_version = 0;
-+ f->fragtree = RB_ROOT;
-+ f->metadata = NULL;
-+ f->dents = NULL;
-+ f->flags = 0;
-+ f->usercompr = 0;
-+#else
-+ memset(f, 0, sizeof(*f));
-+ init_MUTEX_LOCKED(&f->sem);
-+#endif
-+}
-+
-+#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
-+
-+#ifndef CONFIG_JFFS2_FS_NAND
-+#define jffs2_can_mark_obsolete(c) (1)
-+#define jffs2_cleanmarker_oob(c) (0)
-+#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
-+
-+#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
-+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
-+#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
-+#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
-+#define jffs2_nand_flash_setup(c) (0)
-+#define jffs2_nand_flash_cleanup(c) do {} while(0)
-+#define jffs2_wbuf_dirty(c) (0)
-+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
-+#define jffs2_wbuf_timeout NULL
-+#define jffs2_wbuf_process NULL
-+
-+#else /* NAND support present */
-+
-+#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
-+#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
-+
-+#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
-+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
-+struct kstatfs;
-+
-+/* wbuf.c */
-+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
-+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
-+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
-+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
-+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+void jffs2_wbuf_timeout(unsigned long data);
-+void jffs2_wbuf_process(void *data);
-+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
-+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
-+#endif /* NAND */
-+
-+/* erase.c */
-+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-+{
-+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+}
-+
-+/* background.c */
-+int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
-+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
-+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
-+
-+/* dir.c */
-+extern struct file_operations jffs2_dir_operations;
-+extern struct inode_operations jffs2_dir_inode_operations;
-+
-+/* file.c */
-+extern struct file_operations jffs2_file_operations;
-+extern struct inode_operations jffs2_file_inode_operations;
-+extern struct address_space_operations jffs2_file_address_operations;
-+int jffs2_fsync(struct file *, struct dentry *, int);
-+int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
-+int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
-+int jffs2_readpage (struct file *, struct page *);
-+int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
-+int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
-+
-+/* ioctl.c */
-+int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-+
-+/* symlink.c */
-+extern struct inode_operations jffs2_symlink_inode_operations;
-+
-+/* fs.c */
-+int jffs2_setattr (struct dentry *, struct iattr *);
-+void jffs2_read_inode (struct inode *);
-+void jffs2_clear_inode (struct inode *);
-+void jffs2_dirty_inode(struct inode *inode);
-+struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
-+ struct jffs2_raw_inode *ri);
-+int jffs2_statfs (struct super_block *, struct kstatfs *);
-+void jffs2_write_super (struct super_block *);
-+int jffs2_remount_fs (struct super_block *, int *, char *);
-+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
-+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f);
-+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-+ int inum, int nlink);
-+
-+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ unsigned long offset,
-+ unsigned long *priv);
-+void jffs2_gc_release_page(struct jffs2_sb_info *c,
-+ unsigned char *pg,
-+ unsigned long *priv);
-+
-+
-+/* writev.c */
-+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen);
-+
-+/* Compression config */
-+#define JFFS2_COMPRESSION
-+#undef JFFS2_USE_DYNRUBIN /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
-+#undef JFFS2_USE_RUBINMIPS /* Disabled 26/2/1. Obsoleted by dynrubin */
-+#define JFFS2_USE_ZLIB
-+#define JFFS2_USE_RTIME /* rtime does manage to recompress already-compressed data */
-+
-+
-+#endif /* __JFFS2_OS_LINUX_H__ */
-+
-+
-diff -Nurb linux-mips-2.4.27/fs/jffs2/pushpull.h linux/fs/jffs2/pushpull.h
---- linux-mips-2.4.27/fs/jffs2/pushpull.h 2001-11-05 21:16:19.000000000 +0100
-+++ linux/fs/jffs2/pushpull.h 2004-11-19 10:25:12.118166504 +0100
-@@ -1,42 +1,21 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #ifndef __PUSHPULL_H__
- #define __PUSHPULL_H__
-+
-+#include <linux/errno.h>
-+
- struct pushpull {
- unsigned char *buf;
- unsigned int buflen;
-@@ -44,9 +23,36 @@
- unsigned int reserve;
- };
-
--void init_pushpull(struct pushpull *, char *, unsigned, unsigned, unsigned);
--int pushbit(struct pushpull *pp, int bit, int use_reserved);
--int pushedbits(struct pushpull *pp);
-+
-+static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
-+{
-+ pp->buf = buf;
-+ pp->buflen = buflen;
-+ pp->ofs = ofs;
-+ pp->reserve = reserve;
-+}
-+
-+static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
-+{
-+ if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
-+ return -ENOSPC;
-+ }
-+
-+ if (bit) {
-+ pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
-+ }
-+ else {
-+ pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
-+ }
-+ pp->ofs++;
-+
-+ return 0;
-+}
-+
-+static inline int pushedbits(struct pushpull *pp)
-+{
-+ return pp->ofs;
-+}
-
- static inline int pullbit(struct pushpull *pp)
- {
-diff -Nurb linux-mips-2.4.27/fs/jffs2/rbtree.c linux/fs/jffs2/rbtree.c
---- linux-mips-2.4.27/fs/jffs2/rbtree.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/rbtree.c 2004-11-19 10:25:12.120166200 +0100
-@@ -0,0 +1,363 @@
-+/*
-+ Red Black Trees
-+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
-+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+ $Id$
-+*/
-+
-+#ifdef __ECOS /* This file is _not_ under the eCos licence; it is pure GPL. */
-+#error "Licence problem. eCos has its own rbtree code."
-+#endif
-+
-+#include <linux/version.h>
-+#include <linux/rbtree.h>
-+
-+/* This wasn't present till 2.4.11, wasn't exported till 2.4.19 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,11) || \
-+ (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) && defined(MODULE))
-+static void __rb_rotate_left(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * right = node->rb_right;
-+
-+ if ((node->rb_right = right->rb_left))
-+ right->rb_left->rb_parent = node;
-+ right->rb_left = node;
-+
-+ if ((right->rb_parent = node->rb_parent))
-+ {
-+ if (node == node->rb_parent->rb_left)
-+ node->rb_parent->rb_left = right;
-+ else
-+ node->rb_parent->rb_right = right;
-+ }
-+ else
-+ root->rb_node = right;
-+ node->rb_parent = right;
-+}
-+
-+static void __rb_rotate_right(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * left = node->rb_left;
-+
-+ if ((node->rb_left = left->rb_right))
-+ left->rb_right->rb_parent = node;
-+ left->rb_right = node;
-+
-+ if ((left->rb_parent = node->rb_parent))
-+ {
-+ if (node == node->rb_parent->rb_right)
-+ node->rb_parent->rb_right = left;
-+ else
-+ node->rb_parent->rb_left = left;
-+ }
-+ else
-+ root->rb_node = left;
-+ node->rb_parent = left;
-+}
-+
-+void rb_insert_color(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * parent, * gparent;
-+
-+ while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
-+ {
-+ gparent = parent->rb_parent;
-+
-+ if (parent == gparent->rb_left)
-+ {
-+ {
-+ register struct rb_node * uncle = gparent->rb_right;
-+ if (uncle && uncle->rb_color == RB_RED)
-+ {
-+ uncle->rb_color = RB_BLACK;
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ node = gparent;
-+ continue;
-+ }
-+ }
-+
-+ if (parent->rb_right == node)
-+ {
-+ register struct rb_node * tmp;
-+ __rb_rotate_left(parent, root);
-+ tmp = parent;
-+ parent = node;
-+ node = tmp;
-+ }
-+
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ __rb_rotate_right(gparent, root);
-+ } else {
-+ {
-+ register struct rb_node * uncle = gparent->rb_left;
-+ if (uncle && uncle->rb_color == RB_RED)
-+ {
-+ uncle->rb_color = RB_BLACK;
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ node = gparent;
-+ continue;
-+ }
-+ }
-+
-+ if (parent->rb_left == node)
-+ {
-+ register struct rb_node * tmp;
-+ __rb_rotate_right(parent, root);
-+ tmp = parent;
-+ parent = node;
-+ node = tmp;
-+ }
-+
-+ parent->rb_color = RB_BLACK;
-+ gparent->rb_color = RB_RED;
-+ __rb_rotate_left(gparent, root);
-+ }
-+ }
-+
-+ root->rb_node->rb_color = RB_BLACK;
-+}
-+
-+static void __rb_erase_color(struct rb_node * node, struct rb_node * parent,
-+ struct rb_root * root)
-+{
-+ struct rb_node * other;
-+
-+ while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
-+ {
-+ if (parent->rb_left == node)
-+ {
-+ other = parent->rb_right;
-+ if (other->rb_color == RB_RED)
-+ {
-+ other->rb_color = RB_BLACK;
-+ parent->rb_color = RB_RED;
-+ __rb_rotate_left(parent, root);
-+ other = parent->rb_right;
-+ }
-+ if ((!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ && (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK))
-+ {
-+ other->rb_color = RB_RED;
-+ node = parent;
-+ parent = node->rb_parent;
-+ }
-+ else
-+ {
-+ if (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK)
-+ {
-+ register struct rb_node * o_left;
-+ if ((o_left = other->rb_left))
-+ o_left->rb_color = RB_BLACK;
-+ other->rb_color = RB_RED;
-+ __rb_rotate_right(other, root);
-+ other = parent->rb_right;
-+ }
-+ other->rb_color = parent->rb_color;
-+ parent->rb_color = RB_BLACK;
-+ if (other->rb_right)
-+ other->rb_right->rb_color = RB_BLACK;
-+ __rb_rotate_left(parent, root);
-+ node = root->rb_node;
-+ break;
-+ }
-+ }
-+ else
-+ {
-+ other = parent->rb_left;
-+ if (other->rb_color == RB_RED)
-+ {
-+ other->rb_color = RB_BLACK;
-+ parent->rb_color = RB_RED;
-+ __rb_rotate_right(parent, root);
-+ other = parent->rb_left;
-+ }
-+ if ((!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ && (!other->rb_right ||
-+ other->rb_right->rb_color == RB_BLACK))
-+ {
-+ other->rb_color = RB_RED;
-+ node = parent;
-+ parent = node->rb_parent;
-+ }
-+ else
-+ {
-+ if (!other->rb_left ||
-+ other->rb_left->rb_color == RB_BLACK)
-+ {
-+ register struct rb_node * o_right;
-+ if ((o_right = other->rb_right))
-+ o_right->rb_color = RB_BLACK;
-+ other->rb_color = RB_RED;
-+ __rb_rotate_left(other, root);
-+ other = parent->rb_left;
-+ }
-+ other->rb_color = parent->rb_color;
-+ parent->rb_color = RB_BLACK;
-+ if (other->rb_left)
-+ other->rb_left->rb_color = RB_BLACK;
-+ __rb_rotate_right(parent, root);
-+ node = root->rb_node;
-+ break;
-+ }
-+ }
-+ }
-+ if (node)
-+ node->rb_color = RB_BLACK;
-+}
-+
-+void rb_erase(struct rb_node * node, struct rb_root * root)
-+{
-+ struct rb_node * child, * parent;
-+ int color;
-+
-+ if (!node->rb_left)
-+ child = node->rb_right;
-+ else if (!node->rb_right)
-+ child = node->rb_left;
-+ else
-+ {
-+ struct rb_node * old = node, * left;
-+
-+ node = node->rb_right;
-+ while ((left = node->rb_left))
-+ node = left;
-+ child = node->rb_right;
-+ parent = node->rb_parent;
-+ color = node->rb_color;
-+
-+ if (child)
-+ child->rb_parent = parent;
-+ if (parent)
-+ {
-+ if (parent->rb_left == node)
-+ parent->rb_left = child;
-+ else
-+ parent->rb_right = child;
-+ }
-+ else
-+ root->rb_node = child;
-+
-+ if (node->rb_parent == old)
-+ parent = node;
-+ node->rb_parent = old->rb_parent;
-+ node->rb_color = old->rb_color;
-+ node->rb_right = old->rb_right;
-+ node->rb_left = old->rb_left;
-+
-+ if (old->rb_parent)
-+ {
-+ if (old->rb_parent->rb_left == old)
-+ old->rb_parent->rb_left = node;
-+ else
-+ old->rb_parent->rb_right = node;
-+ } else
-+ root->rb_node = node;
-+
-+ old->rb_left->rb_parent = node;
-+ if (old->rb_right)
-+ old->rb_right->rb_parent = node;
-+ goto color;
-+ }
-+
-+ parent = node->rb_parent;
-+ color = node->rb_color;
-+
-+ if (child)
-+ child->rb_parent = parent;
-+ if (parent)
-+ {
-+ if (parent->rb_left == node)
-+ parent->rb_left = child;
-+ else
-+ parent->rb_right = child;
-+ }
-+ else
-+ root->rb_node = child;
-+
-+ color:
-+ if (color == RB_BLACK)
-+ __rb_erase_color(child, parent, root);
-+}
-+#endif /* Before 2.4.11 */
-+
-+ /* These routines haven't made it into 2.4 (yet) */
-+struct rb_node *rb_next(struct rb_node *node)
-+{
-+ /* If we have a right-hand child, go down and then left as far
-+ as we can. */
-+ if (node->rb_right) {
-+ node = node->rb_right;
-+ while (node->rb_left)
-+ node=node->rb_left;
-+ return node;
-+ }
-+
-+ /* No right-hand children. Everything down and left is
-+ smaller than us, so any 'next' node must be in the general
-+ direction of our parent. Go up the tree; any time the
-+ ancestor is a right-hand child of its parent, keep going
-+ up. First time it's a left-hand child of its parent, said
-+ parent is our 'next' node. */
-+ while (node->rb_parent && node == node->rb_parent->rb_right)
-+ node = node->rb_parent;
-+
-+ return node->rb_parent;
-+}
-+
-+struct rb_node *rb_prev(struct rb_node *node)
-+{
-+ if (node->rb_left) {
-+ node = node->rb_left;
-+ while (node->rb_right)
-+ node=node->rb_right;
-+ return node;
-+ }
-+ while (node->rb_parent && node == node->rb_parent->rb_left)
-+ node = node->rb_parent;
-+
-+ return node->rb_parent;
-+}
-+
-+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root)
-+{
-+ struct rb_node *parent = victim->rb_parent;
-+
-+ /* Set the surrounding nodes to point to the replacement */
-+ if (parent) {
-+ if (victim == parent->rb_left)
-+ parent->rb_left = new;
-+ else
-+ parent->rb_right = new;
-+ } else {
-+ root->rb_node = new;
-+ }
-+ if (victim->rb_left)
-+ victim->rb_left->rb_parent = new;
-+ if (victim->rb_right)
-+ victim->rb_right->rb_parent = new;
-+
-+ /* Copy the pointers/colour from the victim to the replacement */
-+ *new = *victim;
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/read.c linux/fs/jffs2/read.c
---- linux-mips-2.4.27/fs/jffs2/read.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/read.c 2004-11-19 10:25:12.121166048 +0100
-@@ -1,52 +1,29 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
-+#include <linux/crc32.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
-+#include <linux/compiler.h>
- #include "nodelist.h"
--#include <linux/crc32.h>
-
- int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
- {
- struct jffs2_raw_inode *ri;
- size_t readlen;
-- __u32 crc;
-+ uint32_t crc;
- unsigned char *decomprbuf = NULL;
- unsigned char *readbuf = NULL;
- int ret = 0;
-@@ -55,35 +32,41 @@
- if (!ri)
- return -ENOMEM;
-
-- ret = c->mtd->read(c->mtd, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri);
-+ ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri);
- if (ret) {
- jffs2_free_raw_inode(ri);
-- printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret);
-+ printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret);
- return ret;
- }
- if (readlen != sizeof(*ri)) {
- jffs2_free_raw_inode(ri);
-- printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n",
-- fd->raw->flash_offset & ~3, sizeof(*ri), readlen);
-+ printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
-+ ref_offset(fd->raw), sizeof(*ri), readlen);
- return -EIO;
- }
- crc = crc32(0, ri, sizeof(*ri)-8);
-
-- D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", fd->raw->flash_offset & ~3, ri->node_crc, crc, ri->dsize, ri->csize, ri->offset, buf));
-- if (crc != ri->node_crc) {
-- printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", ri->node_crc, crc, fd->raw->flash_offset & ~3);
-+ D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
-+ ref_offset(fd->raw), je32_to_cpu(ri->node_crc),
-+ crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
-+ je32_to_cpu(ri->offset), buf));
-+ if (crc != je32_to_cpu(ri->node_crc)) {
-+ printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n",
-+ je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw));
- ret = -EIO;
- goto out_ri;
- }
- /* There was a bug where we wrote hole nodes out with csize/dsize
- swapped. Deal with it */
-- if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) {
-+ if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) &&
-+ je32_to_cpu(ri->csize)) {
- ri->dsize = ri->csize;
-- ri->csize = 0;
-+ ri->csize = cpu_to_je32(0);
- }
-
-- D1(if(ofs + len > ri->dsize) {
-- printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize);
-+ D1(if(ofs + len > je32_to_cpu(ri->dsize)) {
-+ printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
-+ len, ofs, je32_to_cpu(ri->dsize));
- ret = -EINVAL;
- goto out_ri;
- });
-@@ -100,18 +83,18 @@
- Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
- Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
- */
-- if (ri->compr == JFFS2_COMPR_NONE && len == ri->dsize) {
-+ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) {
- readbuf = buf;
- } else {
-- readbuf = kmalloc(ri->csize, GFP_KERNEL);
-+ readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL);
- if (!readbuf) {
- ret = -ENOMEM;
- goto out_ri;
- }
- }
- if (ri->compr != JFFS2_COMPR_NONE) {
-- if (len < ri->dsize) {
-- decomprbuf = kmalloc(ri->dsize, GFP_KERNEL);
-+ if (len < je32_to_cpu(ri->dsize)) {
-+ decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL);
- if (!decomprbuf) {
- ret = -ENOMEM;
- goto out_readbuf;
-@@ -123,31 +106,35 @@
- decomprbuf = readbuf;
- }
-
-- D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf));
-- ret = c->mtd->read(c->mtd, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf);
-+ D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize),
-+ readbuf));
-+ ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri),
-+ je32_to_cpu(ri->csize), &readlen, readbuf);
-
-- if (!ret && readlen != ri->csize)
-+ if (!ret && readlen != je32_to_cpu(ri->csize))
- ret = -EIO;
- if (ret)
- goto out_decomprbuf;
-
-- crc = crc32(0, readbuf, ri->csize);
-- if (crc != ri->data_crc) {
-- printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", ri->data_crc, crc, fd->raw->flash_offset & ~3);
-+ crc = crc32(0, readbuf, je32_to_cpu(ri->csize));
-+ if (crc != je32_to_cpu(ri->data_crc)) {
-+ printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n",
-+ je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw));
- ret = -EIO;
- goto out_decomprbuf;
- }
- D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
- if (ri->compr != JFFS2_COMPR_NONE) {
-- D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf));
-- ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize);
-+ D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
-+ je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
-+ ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
- if (ret) {
- printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
- goto out_decomprbuf;
- }
- }
-
-- if (len < ri->dsize) {
-+ if (len < je32_to_cpu(ri->dsize)) {
- memcpy(buf, decomprbuf+ofs, len);
- }
- out_decomprbuf:
-@@ -161,3 +148,96 @@
-
- return ret;
- }
-+
-+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ unsigned char *buf, uint32_t offset, uint32_t len)
-+{
-+ uint32_t end = offset + len;
-+ struct jffs2_node_frag *frag;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
-+ f->inocache->ino, offset, offset+len));
-+
-+ frag = jffs2_lookup_node_frag(&f->fragtree, offset);
-+
-+ /* XXX FIXME: Where a single physical node actually shows up in two
-+ frags, we read it twice. Don't do that. */
-+ /* Now we're pointing at the first frag which overlaps our page */
-+ while(offset < end) {
-+ D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
-+ if (unlikely(!frag || frag->ofs > offset)) {
-+ uint32_t holesize = end - offset;
-+ if (frag) {
-+ D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
-+ holesize = min(holesize, frag->ofs - offset);
-+ D1(jffs2_print_frag_list(f));
-+ }
-+ D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
-+ memset(buf, 0, holesize);
-+ buf += holesize;
-+ offset += holesize;
-+ continue;
-+ } else if (unlikely(!frag->node)) {
-+ uint32_t holeend = min(end, frag->ofs + frag->size);
-+ D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
-+ memset(buf, 0, holeend - offset);
-+ buf += holeend - offset;
-+ offset = holeend;
-+ frag = frag_next(frag);
-+ continue;
-+ } else {
-+ uint32_t readlen;
-+ uint32_t fragofs; /* offset within the frag to start reading */
-+
-+ fragofs = offset - frag->ofs;
-+ readlen = min(frag->size - fragofs, end - offset);
-+ D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
-+ frag->ofs+fragofs, frag->ofs+fragofs+readlen,
-+ ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
-+ ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
-+ D2(printk(KERN_DEBUG "node read done\n"));
-+ if (ret) {
-+ D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
-+ memset(buf, 0, readlen);
-+ return ret;
-+ }
-+ buf += readlen;
-+ offset += readlen;
-+ frag = frag_next(frag);
-+ D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
-+ }
-+ }
-+ return 0;
-+}
-+
-+/* Core function to read symlink target. */
-+char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
-+{
-+ char *buf;
-+ int ret;
-+
-+ down(&f->sem);
-+
-+ if (!f->metadata) {
-+ printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
-+ up(&f->sem);
-+ return ERR_PTR(-EINVAL);
-+ }
-+ buf = kmalloc(f->metadata->size+1, GFP_USER);
-+ if (!buf) {
-+ up(&f->sem);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+ buf[f->metadata->size]=0;
-+
-+ ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size);
-+
-+ up(&f->sem);
-+
-+ if (ret) {
-+ kfree(buf);
-+ return ERR_PTR(ret);
-+ }
-+ return buf;
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/readinode.c linux/fs/jffs2/readinode.c
---- linux-mips-2.4.27/fs/jffs2/readinode.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/readinode.c 2004-11-19 10:25:12.123165744 +0100
-@@ -1,79 +1,122 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
--/* Given an inode, probably with existing list of fragments, add the new node
-- * to the fragment list.
-- */
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
-+#include <linux/crc32.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
--#include <linux/jffs2.h>
-+#include <linux/compiler.h>
- #include "nodelist.h"
--#include <linux/crc32.h>
-
-+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag);
-
--D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
-+#if CONFIG_JFFS2_FS_DEBUG >= 1
-+static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
- {
-- struct jffs2_node_frag *this = f->fraglist;
-+ struct jffs2_node_frag *this = frag_first(list);
-+ uint32_t lastofs = 0;
-+ int buggy = 0;
-
- while(this) {
- if (this->node)
-- printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next);
-+ printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n",
-+ this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw),
-+ this, frag_left(this), frag_right(this), frag_parent(this));
- else
-- printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next);
-- this = this->next;
-+ printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs,
-+ this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this));
-+ if (this->ofs != lastofs)
-+ buggy = 1;
-+ lastofs = this->ofs+this->size;
-+ this = frag_next(this);
-+ }
-+ if (buggy && !permitbug) {
-+ printk(KERN_CRIT "Frag tree got a hole in it\n");
-+ BUG();
- }
-+}
-+
-+void jffs2_print_frag_list(struct jffs2_inode_info *f)
-+{
-+ jffs2_print_fragtree(&f->fragtree, 0);
-+
- if (f->metadata) {
-- printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3);
-+ printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
- }
--})
--
-+}
-
--int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
-+static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
- {
-- int ret;
-- D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
-+ struct jffs2_node_frag *frag;
-+ int bitched = 0;
-
-- ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn);
-+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
-
-- D2(jffs2_print_frag_list(f));
-- return ret;
-+ struct jffs2_full_dnode *fn = frag->node;
-+ if (!fn || !fn->raw)
-+ continue;
-+
-+ if (ref_flags(fn->raw) == REF_PRISTINE) {
-+
-+ if (fn->frags > 1) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags);
-+ bitched = 1;
-+ }
-+ /* A hole node which isn't multi-page should be garbage-collected
-+ and merged anyway, so we just check for the frag size here,
-+ rather than mucking around with actually reading the node
-+ and checking the compression type, which is the real way
-+ to tell a hole node. */
-+ if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
-+ ref_offset(fn->raw));
-+ bitched = 1;
-+ }
-+
-+ if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
-+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
-+ ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
-+ bitched = 1;
-+ }
-+ }
-+ }
-+
-+ if (bitched) {
-+ struct jffs2_node_frag *thisfrag;
-+
-+ printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino);
-+ thisfrag = frag_first(&f->fragtree);
-+ while (thisfrag) {
-+ if (!thisfrag->node) {
-+ printk("Frag @0x%x-0x%x; node-less hole\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-+ } else if (!thisfrag->node->raw) {
-+ printk("Frag @0x%x-0x%x; raw-less hole\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-+ } else {
-+ printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n",
-+ thisfrag->ofs, thisfrag->size + thisfrag->ofs,
-+ ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw),
-+ thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size);
-+ }
-+ thisfrag = frag_next(thisfrag);
-+ }
-+ }
-+ return bitched;
- }
-+#endif /* D1 */
-
- static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
- {
-@@ -82,42 +125,38 @@
- if (!this->node->frags) {
- /* The node has no valid frags left. It's totally obsoleted */
- D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
-- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size));
-+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size));
- jffs2_mark_node_obsolete(c, this->node->raw);
- jffs2_free_full_dnode(this->node);
- } else {
-- D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n",
-- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size,
-+ D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
-+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size,
- this->node->frags));
-+ mark_ref_normal(this->node->raw);
- }
-
- }
- jffs2_free_node_frag(this);
- }
-
--/* Doesn't set inode->i_size */
--int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn)
-+/* Given an inode, probably with existing list of fragments, add the new node
-+ * to the fragment list.
-+ */
-+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
- {
-+ int ret;
-+ struct jffs2_node_frag *newfrag;
-
-- struct jffs2_node_frag *this, **prev, *old;
-- struct jffs2_node_frag *newfrag, *newfrag2;
-- __u32 lastend = 0;
--
-+ D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
-
- newfrag = jffs2_alloc_node_frag();
-- if (!newfrag) {
-+ if (unlikely(!newfrag))
- return -ENOMEM;
-- }
--
-- D2(if (fn->raw)
-- printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag);
-- else
-- printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag));
-
-- prev = list;
-- this = *list;
-+ D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
-
-- if (!fn->size) {
-+ if (unlikely(!fn->size)) {
- jffs2_free_node_frag(newfrag);
- return 0;
- }
-@@ -126,176 +165,358 @@
- newfrag->size = fn->size;
- newfrag->node = fn;
- newfrag->node->frags = 1;
-- newfrag->next = (void *)0xdeadbeef;
-+
-+ ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
-+ if (ret)
-+ return ret;
-+
-+ /* If we now share a page with other nodes, mark either previous
-+ or next node REF_NORMAL, as appropriate. */
-+ if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) {
-+ struct jffs2_node_frag *prev = frag_prev(newfrag);
-+
-+ mark_ref_normal(fn->raw);
-+ /* If we don't start at zero there's _always_ a previous */
-+ if (prev->node)
-+ mark_ref_normal(prev->node->raw);
-+ }
-+
-+ if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) {
-+ struct jffs2_node_frag *next = frag_next(newfrag);
-+
-+ if (next) {
-+ mark_ref_normal(fn->raw);
-+ if (next->node)
-+ mark_ref_normal(next->node->raw);
-+ }
-+ }
-+ D2(if (jffs2_sanitycheck_fragtree(f)) {
-+ printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
-+ return 0;
-+ })
-+ D2(jffs2_print_frag_list(f));
-+ return 0;
-+}
-+
-+/* Doesn't set inode->i_size */
-+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag)
-+{
-+ struct jffs2_node_frag *this;
-+ uint32_t lastend;
-
- /* Skip all the nodes which are completed before this one starts */
-- while(this && fn->ofs >= this->ofs+this->size) {
-- lastend = this->ofs + this->size;
-+ this = jffs2_lookup_node_frag(list, newfrag->node->ofs);
-
-- D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
-- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
-- prev = &this->next;
-- this = this->next;
-+ if (this) {
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
-+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
-+ lastend = this->ofs + this->size;
-+ } else {
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n"));
-+ lastend = 0;
- }
-
- /* See if we ran off the end of the list */
-- if (!this) {
-+ if (lastend <= newfrag->ofs) {
- /* We did */
-- if (lastend < fn->ofs) {
-+
-+ /* Check if 'this' node was on the same page as the new node.
-+ If so, both 'this' and the new node get marked REF_NORMAL so
-+ the GC can take a look.
-+ */
-+ if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+ mark_ref_normal(newfrag->node->raw);
-+ }
-+
-+ if (lastend < newfrag->node->ofs) {
- /* ... and we need to put a hole in before the new node */
- struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
-- if (!holefrag)
-+ if (!holefrag) {
-+ jffs2_free_node_frag(newfrag);
- return -ENOMEM;
-+ }
- holefrag->ofs = lastend;
-- holefrag->size = fn->ofs - lastend;
-- holefrag->next = NULL;
-+ holefrag->size = newfrag->node->ofs - lastend;
- holefrag->node = NULL;
-- *prev = holefrag;
-- prev = &holefrag->next;
-+ if (this) {
-+ /* By definition, the 'this' node has no right-hand child,
-+ because there are no frags with offset greater than it.
-+ So that's where we want to put the hole */
-+ D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this));
-+ rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
-+ } else {
-+ D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag));
-+ rb_link_node(&holefrag->rb, NULL, &list->rb_node);
-+ }
-+ rb_insert_color(&holefrag->rb, list);
-+ this = holefrag;
- }
-- newfrag->next = NULL;
-- *prev = newfrag;
-+ if (this) {
-+ /* By definition, the 'this' node has no right-hand child,
-+ because there are no frags with offset greater than it.
-+ So that's where we want to put the hole */
-+ D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this));
-+ rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
-+ } else {
-+ D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag));
-+ rb_link_node(&newfrag->rb, NULL, &list->rb_node);
-+ }
-+ rb_insert_color(&newfrag->rb, list);
- return 0;
- }
-
-- D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
-- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
-+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
-+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
-
-- /* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes,
-- * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs
-+ /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
-+ * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
- */
-- if (fn->ofs > this->ofs) {
-+ if (newfrag->ofs > this->ofs) {
- /* This node isn't completely obsoleted. The start of it remains valid */
-- if (this->ofs + this->size > fn->ofs + fn->size) {
-+
-+ /* Mark the new node and the partially covered node REF_NORMAL -- let
-+ the GC take a look at them */
-+ mark_ref_normal(newfrag->node->raw);
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+
-+ if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
- /* The new node splits 'this' frag into two */
-- newfrag2 = jffs2_alloc_node_frag();
-+ struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag();
- if (!newfrag2) {
- jffs2_free_node_frag(newfrag);
- return -ENOMEM;
- }
-- D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
-+ D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
- if (this->node)
-- printk("phys 0x%08x\n", this->node->raw->flash_offset &~3);
-+ printk("phys 0x%08x\n", ref_offset(this->node->raw));
- else
- printk("hole\n");
- )
-- newfrag2->ofs = fn->ofs + fn->size;
-+
-+ /* New second frag pointing to this's node */
-+ newfrag2->ofs = newfrag->ofs + newfrag->size;
- newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
-- newfrag2->next = this->next;
- newfrag2->node = this->node;
- if (this->node)
- this->node->frags++;
-- newfrag->next = newfrag2;
-- this->next = newfrag;
-+
-+ /* Adjust size of original 'this' */
- this->size = newfrag->ofs - this->ofs;
-+
-+ /* Now, we know there's no node with offset
-+ greater than this->ofs but smaller than
-+ newfrag2->ofs or newfrag->ofs, for obvious
-+ reasons. So we can do a tree insert from
-+ 'this' to insert newfrag, and a tree insert
-+ from newfrag to insert newfrag2. */
-+ jffs2_fragtree_insert(newfrag, this);
-+ rb_insert_color(&newfrag->rb, list);
-+
-+ jffs2_fragtree_insert(newfrag2, newfrag);
-+ rb_insert_color(&newfrag2->rb, list);
-+
- return 0;
- }
- /* New node just reduces 'this' frag in size, doesn't split it */
-- this->size = fn->ofs - this->ofs;
-- newfrag->next = this->next;
-- this->next = newfrag;
-- this = newfrag->next;
-+ this->size = newfrag->ofs - this->ofs;
-+
-+ /* Again, we know it lives down here in the tree */
-+ jffs2_fragtree_insert(newfrag, this);
-+ rb_insert_color(&newfrag->rb, list);
- } else {
-- D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this));
-- *prev = newfrag;
-- newfrag->next = this;
-+ /* New frag starts at the same point as 'this' used to. Replace
-+ it in the tree without doing a delete and insertion */
-+ D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
-+ newfrag, newfrag->ofs, newfrag->ofs+newfrag->size,
-+ this, this->ofs, this->ofs+this->size));
-+
-+ rb_replace_node(&this->rb, &newfrag->rb, list);
-+
-+ if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
-+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size));
-+ jffs2_obsolete_node_frag(c, this);
-+ } else {
-+ this->ofs += newfrag->size;
-+ this->size -= newfrag->size;
-+
-+ jffs2_fragtree_insert(this, newfrag);
-+ rb_insert_color(&this->rb, list);
-+ return 0;
- }
-- /* OK, now we have newfrag added in the correct place in the list, but
-- newfrag->next points to a fragment which may be overlapping it
-+ }
-+ /* OK, now we have newfrag added in the correct place in the tree, but
-+ frag_next(newfrag) may be a fragment which is overlapped by it
- */
-- while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-- /* 'this' frag is obsoleted. */
-- old = this;
-- this = old->next;
-- jffs2_obsolete_node_frag(c, old);
-+ while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-+ /* 'this' frag is obsoleted completely. */
-+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size));
-+ rb_erase(&this->rb, list);
-+ jffs2_obsolete_node_frag(c, this);
- }
- /* Now we're pointing at the first frag which isn't totally obsoleted by
- the new frag */
-- newfrag->next = this;
-
- if (!this || newfrag->ofs + newfrag->size == this->ofs) {
- return 0;
- }
-- /* Still some overlap */
-+ /* Still some overlap but we don't need to move it in the tree */
- this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
- this->ofs = newfrag->ofs + newfrag->size;
-+
-+ /* And mark them REF_NORMAL so the GC takes a look at them */
-+ if (this->node)
-+ mark_ref_normal(this->node->raw);
-+ mark_ref_normal(newfrag->node->raw);
-+
- return 0;
- }
-
--void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size)
-+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
- {
-+ struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
-+
- D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
-
-- while (*list) {
-- if ((*list)->ofs >= size) {
-- struct jffs2_node_frag *this = *list;
-- *list = this->next;
-- D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size));
-- jffs2_obsolete_node_frag(c, this);
-- continue;
-- } else if ((*list)->ofs + (*list)->size > size) {
-- D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size));
-- (*list)->size = size - (*list)->ofs;
-- }
-- list = &(*list)->next;
-+ /* We know frag->ofs <= size. That's what lookup does for us */
-+ if (frag && frag->ofs != size) {
-+ if (frag->ofs+frag->size >= size) {
-+ D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-+ frag->size = size - frag->ofs;
-+ }
-+ frag = frag_next(frag);
-+ }
-+ while (frag && frag->ofs >= size) {
-+ struct jffs2_node_frag *next = frag_next(frag);
-+
-+ D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-+ frag_erase(frag, list);
-+ jffs2_obsolete_node_frag(c, frag);
-+ frag = next;
- }
- }
-
- /* Scan the list of all nodes present for this ino, build map of versions, etc. */
-
--void jffs2_read_inode (struct inode *inode)
-+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *latest_node);
-+
-+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ uint32_t ino, struct jffs2_raw_inode *latest_node)
- {
-- struct jffs2_tmp_dnode_info *tn_list, *tn;
-- struct jffs2_full_dirent *fd_list;
-- struct jffs2_inode_info *f;
-- struct jffs2_full_dnode *fn = NULL;
-- struct jffs2_sb_info *c;
-- struct jffs2_raw_inode latest_node;
-- __u32 latest_mctime, mctime_ver;
-- __u32 mdata_ver = 0;
-- int ret;
-- ssize_t retlen;
-+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n"));
-
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
-+ retry_inocache:
-+ spin_lock(&c->inocache_lock);
-+ f->inocache = jffs2_get_ino_cache(c, ino);
-+
-+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache));
-+
-+ if (f->inocache) {
-+ /* Check its state. We may need to wait before we can use it */
-+ switch(f->inocache->state) {
-+ case INO_STATE_UNCHECKED:
-+ case INO_STATE_CHECKEDABSENT:
-+ f->inocache->state = INO_STATE_READING;
-+ break;
-
-- f = JFFS2_INODE_INFO(inode);
-- c = JFFS2_SB_INFO(inode->i_sb);
-+ case INO_STATE_CHECKING:
-+ case INO_STATE_GC:
-+ /* If it's in either of these states, we need
-+ to wait for whoever's got it to finish and
-+ put it back. */
-+ D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n",
-+ ino, f->inocache->state));
-+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-+ goto retry_inocache;
-+
-+ case INO_STATE_READING:
-+ case INO_STATE_PRESENT:
-+ /* Eep. This should never happen. It can
-+ happen if Linux calls read_inode() again
-+ before clear_inode() has finished though. */
-+ printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
-+ /* Fail. That's probably better than allowing it to succeed */
-+ f->inocache = NULL;
-+ break;
-
-- memset(f, 0, sizeof(*f));
-- D2(printk(KERN_DEBUG "getting inocache\n"));
-- init_MUTEX(&f->sem);
-- f->inocache = jffs2_get_ino_cache(c, inode->i_ino);
-- D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache));
-+ default:
-+ BUG();
-+ }
-+ }
-+ spin_unlock(&c->inocache_lock);
-
-- if (!f->inocache && inode->i_ino == 1) {
-+ if (!f->inocache && ino == 1) {
- /* Special case - no root inode on medium */
- f->inocache = jffs2_alloc_inode_cache();
- if (!f->inocache) {
-- printk(KERN_CRIT "jffs2_read_inode(): Cannot allocate inocache for root inode\n");
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n");
-+ return -ENOMEM;
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): Creating inocache for root inode\n"));
-+ D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n"));
- memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
- f->inocache->ino = f->inocache->nlink = 1;
- f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-+ f->inocache->state = INO_STATE_READING;
- jffs2_add_ino_cache(c, f->inocache);
- }
- if (!f->inocache) {
-- printk(KERN_WARNING "jffs2_read_inode() on nonexistent ino %lu\n", (unsigned long)inode->i_ino);
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino);
-+ return -ENOENT;
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode(): ino #%lu nlink is %d\n", (unsigned long)inode->i_ino, f->inocache->nlink));
-- inode->i_nlink = f->inocache->nlink;
-+
-+ return jffs2_do_read_inode_internal(c, f, latest_node);
-+}
-+
-+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-+{
-+ struct jffs2_raw_inode n;
-+ struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
-+ int ret;
-+
-+ if (!f)
-+ return -ENOMEM;
-+
-+ memset(f, 0, sizeof(*f));
-+ init_MUTEX_LOCKED(&f->sem);
-+ f->inocache = ic;
-+
-+ ret = jffs2_do_read_inode_internal(c, f, &n);
-+ if (!ret) {
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ }
-+ kfree (f);
-+ return ret;
-+}
-+
-+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
-+ struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *latest_node)
-+{
-+ struct jffs2_tmp_dnode_info *tn_list, *tn;
-+ struct jffs2_full_dirent *fd_list;
-+ struct jffs2_full_dnode *fn = NULL;
-+ uint32_t crc;
-+ uint32_t latest_mctime, mctime_ver;
-+ uint32_t mdata_ver = 0;
-+ size_t retlen;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink));
-
- /* Grab all nodes relevant to this ino */
-- ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
-+ ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
-
- if (ret) {
-- printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret);
-- make_bad_inode(inode);
-- return;
-+ printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret);
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-+ return ret;
- }
- f->dents = fd_list;
-
-@@ -304,205 +525,169 @@
-
- fn = tn->fn;
-
-- if (f->metadata && tn->version > mdata_ver) {
-- D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3));
-+ if (f->metadata) {
-+ if (likely(tn->version >= mdata_ver)) {
-+ D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
- jffs2_mark_node_obsolete(c, f->metadata->raw);
- jffs2_free_full_dnode(f->metadata);
- f->metadata = NULL;
-
- mdata_ver = 0;
-+ } else {
-+ /* This should never happen. */
-+ printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n",
-+ ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw));
-+ jffs2_mark_node_obsolete(c, fn->raw);
-+ jffs2_free_full_dnode(fn);
-+ /* Fill in latest_node from the metadata, not this one we're about to free... */
-+ fn = f->metadata;
-+ goto next_tn;
-+ }
- }
-
- if (fn->size) {
- jffs2_add_full_dnode_to_inode(c, f, fn);
- } else {
- /* Zero-sized node at end of version list. Just a metadata update */
-- D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version));
-+ D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version));
- f->metadata = fn;
- mdata_ver = tn->version;
- }
-+ next_tn:
- tn_list = tn->next;
- jffs2_free_tmp_dnode_info(tn);
- }
-+ D1(jffs2_sanitycheck_fragtree(f));
-+
- if (!fn) {
- /* No data nodes for this inode. */
-- if (inode->i_ino != 1) {
-- printk(KERN_WARNING "jffs2_read_inode(): No data nodes found for ino #%lu\n", inode->i_ino);
-+ if (f->inocache->ino != 1) {
-+ printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino);
- if (!fd_list) {
-- make_bad_inode(inode);
-- return;
-- }
-- printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n");
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-+ return -EIO;
-+ }
-+ printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n");
-+ }
-+ latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
-+ latest_node->version = cpu_to_je32(0);
-+ latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
-+ latest_node->isize = cpu_to_je32(0);
-+ latest_node->gid = cpu_to_je16(0);
-+ latest_node->uid = cpu_to_je16(0);
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
-+ return 0;
- }
-- inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
-- latest_node.version = 0;
-- inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-- inode->i_nlink = f->inocache->nlink;
-- inode->i_size = 0;
-- } else {
-- __u32 crc;
-
-- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(latest_node), &retlen, (void *)&latest_node);
-- if (ret || retlen != sizeof(latest_node)) {
-- printk(KERN_NOTICE "MTD read in jffs2_read_inode() failed: Returned %d, %ld of %d bytes read\n",
-- ret, (long)retlen, sizeof(latest_node));
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
--
-- crc = crc32(0, &latest_node, sizeof(latest_node)-8);
-- if (crc != latest_node.node_crc) {
-- printk(KERN_NOTICE "CRC failed for read_inode of inode %ld at physical location 0x%x\n", inode->i_ino, fn->raw->flash_offset & ~3);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
--
-- inode->i_mode = latest_node.mode;
-- inode->i_uid = latest_node.uid;
-- inode->i_gid = latest_node.gid;
-- inode->i_size = latest_node.isize;
-- if (S_ISREG(inode->i_mode))
-- jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
-- inode->i_atime = latest_node.atime;
-- inode->i_mtime = latest_node.mtime;
-- inode->i_ctime = latest_node.ctime;
-- }
--
-- /* OK, now the special cases. Certain inode types should
-- have only one data node, and it's kept as the metadata
-- node */
-- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
-- S_ISLNK(inode->i_mode)) {
-- if (f->metadata) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- if (!f->fraglist) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o has no fragments\n", inode->i_ino, inode->i_mode);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- /* ASSERT: f->fraglist != NULL */
-- if (f->fraglist->next) {
-- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode);
-- /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-- }
-- /* OK. We're happy */
-- f->metadata = f->fraglist->node;
-- jffs2_free_node_frag(f->fraglist);
-- f->fraglist = NULL;
-+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
-+ if (ret || retlen != sizeof(*latest_node)) {
-+ printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n",
-+ ret, retlen, sizeof(*latest_node));
-+ /* FIXME: If this fails, there seems to be a memory leak. Find it. */
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return ret?ret:-EIO;
- }
-
-- inode->i_blksize = PAGE_SIZE;
-- inode->i_blocks = (inode->i_size + 511) >> 9;
--
-- switch (inode->i_mode & S_IFMT) {
-- unsigned short rdev;
--
-- case S_IFLNK:
-- inode->i_op = &jffs2_symlink_inode_operations;
-- /* Hack to work around broken isize in old symlink code.
-- Remove this when dwmw2 comes to his senses and stops
-- symlinks from being an entirely gratuitous special
-- case. */
-- if (!inode->i_size)
-- inode->i_size = latest_node.dsize;
-- break;
-+ crc = crc32(0, latest_node, sizeof(*latest_node)-8);
-+ if (crc != je32_to_cpu(latest_node->node_crc)) {
-+ printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
-+ }
-
-+ switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
- case S_IFDIR:
-- if (mctime_ver > latest_node.version) {
-+ if (mctime_ver > je32_to_cpu(latest_node->version)) {
- /* The times in the latest_node are actually older than
- mctime in the latest dirent. Cheat. */
-- inode->i_mtime = inode->i_ctime = inode->i_atime =
-- latest_mctime;
-+ latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime);
- }
-- inode->i_op = &jffs2_dir_inode_operations;
-- inode->i_fop = &jffs2_dir_operations;
- break;
-
-+
- case S_IFREG:
-- inode->i_op = &jffs2_file_inode_operations;
-- inode->i_fop = &jffs2_file_operations;
-- inode->i_mapping->a_ops = &jffs2_file_address_operations;
-- inode->i_mapping->nrpages = 0;
-+ /* If it was a regular file, truncate it to the latest node's isize */
-+ jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize));
- break;
-
-+ case S_IFLNK:
-+ /* Hack to work around broken isize in old symlink code.
-+ Remove this when dwmw2 comes to his senses and stops
-+ symlinks from being an entirely gratuitous special
-+ case. */
-+ if (!je32_to_cpu(latest_node->isize))
-+ latest_node->isize = latest_node->dsize;
-+ /* fall through... */
-+
- case S_IFBLK:
- case S_IFCHR:
-- /* Read the device numbers from the media */
-- D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-- if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
-- /* Eep */
-- printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
-- jffs2_clear_inode(inode);
-- make_bad_inode(inode);
-- return;
-+ /* Certain inode types should have only one data node, and it's
-+ kept as the metadata node */
-+ if (f->metadata) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
- }
--
-- case S_IFSOCK:
-- case S_IFIFO:
-- inode->i_op = &jffs2_file_inode_operations;
-- init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff)));
-+ if (!frag_first(&f->fragtree)) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
-+ }
-+ /* ASSERT: f->fraglist != NULL */
-+ if (frag_next(frag_first(&f->fragtree))) {
-+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n",
-+ f->inocache->ino, jemode_to_cpu(latest_node->mode));
-+ /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
-+ up(&f->sem);
-+ jffs2_do_clear_inode(c, f);
-+ return -EIO;
-+ }
-+ /* OK. We're happy */
-+ f->metadata = frag_first(&f->fragtree)->node;
-+ jffs2_free_node_frag(frag_first(&f->fragtree));
-+ f->fragtree = RB_ROOT;
- break;
--
-- default:
-- printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu", inode->i_mode, (unsigned long)inode->i_ino);
- }
-- D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
-+ if (f->inocache->state == INO_STATE_READING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
-+
-+ return 0;
- }
-
--void jffs2_clear_inode (struct inode *inode)
-+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
- {
-- /* We can forget about this inode for now - drop all
-- * the nodelists associated with it, etc.
-- */
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_node_frag *frag, *frags;
- struct jffs2_full_dirent *fd, *fds;
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- int deleted;
-
-- D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
--
- down(&f->sem);
- deleted = f->inocache && !f->inocache->nlink;
-
-- frags = f->fraglist;
-- fds = f->dents;
- if (f->metadata) {
- if (deleted)
- jffs2_mark_node_obsolete(c, f->metadata->raw);
- jffs2_free_full_dnode(f->metadata);
- }
-
-- while (frags) {
-- frag = frags;
-- frags = frag->next;
-- D2(printk(KERN_DEBUG "jffs2_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0));
-+ jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
-
-- if (frag->node && !(--frag->node->frags)) {
-- /* Not a hole, and it's the final remaining frag of this node. Free the node */
-- if (deleted)
-- jffs2_mark_node_obsolete(c, frag->node->raw);
-+ fds = f->dents;
-
-- jffs2_free_full_dnode(frag->node);
-- }
-- jffs2_free_node_frag(frag);
-- }
- while(fds) {
- fd = fds;
- fds = fd->next;
- jffs2_free_full_dirent(fd);
- }
-
-- up(&f->sem);
--};
-+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
-+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
-
-+ up(&f->sem);
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/scan.c linux/fs/jffs2/scan.c
---- linux-mips-2.4.27/fs/jffs2/scan.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/scan.c 2004-11-19 10:25:12.124165592 +0100
-@@ -1,47 +1,25 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
- #include <linux/kernel.h>
-+#include <linux/sched.h>
- #include <linux/slab.h>
--#include <linux/jffs2.h>
- #include <linux/mtd/mtd.h>
- #include <linux/pagemap.h>
--#include "nodelist.h"
- #include <linux/crc32.h>
-+#include <linux/compiler.h>
-+#include "nodelist.h"
-
-+#define EMPTY_SCAN_SIZE 1024
-
- #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
- c->free_size -= _x; c->dirty_size += _x; \
-@@ -51,6 +29,10 @@
- c->free_size -= _x; c->used_size += _x; \
- jeb->free_size -= _x ; jeb->used_size += _x; \
- }while(0)
-+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
-+ c->free_size -= _x; c->unchecked_size += _x; \
-+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \
-+ }while(0)
-
- #define noisy_printk(noise, args...) do { \
- if (*(noise)) { \
-@@ -63,39 +45,84 @@
- } while(0)
-
- static uint32_t pseudo_random;
--static void jffs2_rotate_lists(struct jffs2_sb_info *c);
-
--static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ unsigned char *buf, uint32_t buf_size);
-
- /* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
- * Returning an error will abort the mount - bad checksums etc. should just mark the space
- * as dirty.
- */
--static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs, int *noise);
--static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs);
--static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs);
-+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_inode *ri, uint32_t ofs);
-+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_dirent *rd, uint32_t ofs);
-+
-+#define BLK_STATE_ALLFF 0
-+#define BLK_STATE_CLEAN 1
-+#define BLK_STATE_PARTDIRTY 2
-+#define BLK_STATE_CLEANMARKER 3
-+#define BLK_STATE_ALLDIRTY 4
-+#define BLK_STATE_BADBLOCK 5
-
-+static inline int min_free(struct jffs2_sb_info *c)
-+{
-+ uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
-+ return c->wbuf_pagesize;
-+#endif
-+ return min;
-
-+}
- int jffs2_scan_medium(struct jffs2_sb_info *c)
- {
- int i, ret;
-- __u32 empty_blocks = 0;
--
-- if (!c->blocks) {
-- printk(KERN_WARNING "EEEK! c->blocks is NULL!\n");
-- return -EINVAL;
-+ uint32_t empty_blocks = 0, bad_blocks = 0;
-+ unsigned char *flashbuf = NULL;
-+ uint32_t buf_size = 0;
-+#ifndef __ECOS
-+ size_t pointlen;
-+
-+ if (c->mtd->point) {
-+ ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
-+ if (!ret && pointlen < c->mtd->size) {
-+ /* Don't muck about if it won't let us point to the whole flash */
-+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
-+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
-+ flashbuf = NULL;
-+ }
-+ if (ret)
-+ D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
-+ }
-+#endif
-+ if (!flashbuf) {
-+ /* For NAND it's quicker to read a whole eraseblock at a time,
-+ apparently */
-+ if (jffs2_cleanmarker_oob(c))
-+ buf_size = c->sector_size;
-+ else
-+ buf_size = PAGE_SIZE;
-+
-+ D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size));
-+ flashbuf = kmalloc(buf_size, GFP_KERNEL);
-+ if (!flashbuf)
-+ return -ENOMEM;
- }
-+
- for (i=0; i<c->nr_blocks; i++) {
- struct jffs2_eraseblock *jeb = &c->blocks[i];
-
-- ret = jffs2_scan_eraseblock(c, jeb);
-+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
-+
- if (ret < 0)
-- return ret;
-+ goto out;
-
- ACCT_PARANOIA_CHECK(jeb);
-
- /* Now decide which list to put it on */
-- if (ret == 1) {
-+ switch(ret) {
-+ case BLK_STATE_ALLFF:
- /*
- * Empty block. Since we can't be sure it
- * was entirely erased, we just queue it for erase
-@@ -103,10 +130,12 @@
- * is complete. Meanwhile we still count it as empty
- * for later checks.
- */
-- list_add(&jeb->list, &c->erase_pending_list);
- empty_blocks++;
-+ list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
-- } else if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && !jeb->first_node->next_in_ino) {
-+ break;
-+
-+ case BLK_STATE_CLEANMARKER:
- /* Only a CLEANMARKER node is valid */
- if (!jeb->dirty_size) {
- /* It's actually free */
-@@ -118,74 +147,227 @@
- list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
- }
-- } else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode))) {
-+ break;
-+
-+ case BLK_STATE_CLEAN:
- /* Full (or almost full) of clean data. Clean list */
- list_add(&jeb->list, &c->clean_list);
-- } else if (jeb->used_size) {
-+ break;
-+
-+ case BLK_STATE_PARTDIRTY:
- /* Some data, but not full. Dirty list. */
- /* Except that we want to remember the block with most free space,
- and stick it in the 'nextblock' position to start writing to it.
- Later when we do snapshots, this must be the most recent block,
- not the one with most free space.
- */
-- if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) &&
-+ if (jeb->free_size > min_free(c) &&
- (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
- /* Better candidate for the next writes to go to */
-- if (c->nextblock)
-+ if (c->nextblock) {
-+ c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
-+ c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
-+ c->free_size -= c->nextblock->free_size;
-+ c->wasted_size -= c->nextblock->wasted_size;
-+ c->nextblock->free_size = c->nextblock->wasted_size = 0;
-+ if (VERYDIRTY(c, c->nextblock->dirty_size)) {
-+ list_add(&c->nextblock->list, &c->very_dirty_list);
-+ } else {
- list_add(&c->nextblock->list, &c->dirty_list);
-+ }
-+ }
- c->nextblock = jeb;
- } else {
-+ jeb->dirty_size += jeb->free_size + jeb->wasted_size;
-+ c->dirty_size += jeb->free_size + jeb->wasted_size;
-+ c->free_size -= jeb->free_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->free_size = jeb->wasted_size = 0;
-+ if (VERYDIRTY(c, jeb->dirty_size)) {
-+ list_add(&jeb->list, &c->very_dirty_list);
-+ } else {
- list_add(&jeb->list, &c->dirty_list);
- }
-- } else {
-+ }
-+ break;
-+
-+ case BLK_STATE_ALLDIRTY:
- /* Nothing valid - not even a clean marker. Needs erasing. */
- /* For now we just put it on the erasing list. We'll start the erases later */
-- printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset);
-+ D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
- list_add(&jeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
-+ break;
-+
-+ case BLK_STATE_BADBLOCK:
-+ D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
-+ list_add(&jeb->list, &c->bad_list);
-+ c->bad_size += c->sector_size;
-+ c->free_size -= c->sector_size;
-+ bad_blocks++;
-+ break;
-+ default:
-+ printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
-+ BUG();
- }
- }
-- /* Rotate the lists by some number to ensure wear levelling */
-- jffs2_rotate_lists(c);
-
-+ /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
-+ if (c->nextblock && (c->nextblock->dirty_size)) {
-+ c->nextblock->wasted_size += c->nextblock->dirty_size;
-+ c->wasted_size += c->nextblock->dirty_size;
-+ c->dirty_size -= c->nextblock->dirty_size;
-+ c->nextblock->dirty_size = 0;
-+ }
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
-+ /* If we're going to start writing into a block which already
-+ contains data, and the end of the data isn't page-aligned,
-+ skip a little and align it. */
-+
-+ uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1);
-+
-+ D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
-+ skip));
-+ c->nextblock->wasted_size += skip;
-+ c->wasted_size += skip;
-+
-+ c->nextblock->free_size -= skip;
-+ c->free_size -= skip;
-+ }
-+#endif
- if (c->nr_erasing_blocks) {
-- if (!c->used_size && empty_blocks != c->nr_blocks) {
-+ if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
- printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
-- return -EIO;
-+ printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
-+ ret = -EIO;
-+ goto out;
- }
- jffs2_erase_pending_trigger(c);
- }
-+ ret = 0;
-+ out:
-+ if (buf_size)
-+ kfree(flashbuf);
-+#ifndef __ECOS
-+ else
-+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
-+#endif
-+ return ret;
-+}
-+
-+static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
-+ uint32_t ofs, uint32_t len)
-+{
-+ int ret;
-+ size_t retlen;
-+
-+ ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
-+ if (ret) {
-+ D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret));
-+ return ret;
-+ }
-+ if (retlen < len) {
-+ D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen));
-+ return -EIO;
-+ }
-+ D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
-+ D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]));
- return 0;
- }
-
--static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-- struct jffs2_unknown_node node;
-- __u32 ofs, prevofs;
-- __u32 hdr_crc, nodetype;
-+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ unsigned char *buf, uint32_t buf_size) {
-+ struct jffs2_unknown_node *node;
-+ struct jffs2_unknown_node crcnode;
-+ uint32_t ofs, prevofs;
-+ uint32_t hdr_crc, buf_ofs, buf_len;
- int err;
- int noise = 0;
-+ int wasempty = 0;
-+ uint32_t empty_start = 0;
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ int cleanmarkerfound = 0;
-+#endif
-
- ofs = jeb->offset;
- prevofs = jeb->offset - 1;
-
- D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
-
-- err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-- if (err) return err;
-- if (ofs == jeb->offset + c->sector_size) {
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ if (jffs2_cleanmarker_oob(c)) {
-+ int ret = jffs2_check_nand_cleanmarker(c, jeb);
-+ D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
-+ /* Even if it's not found, we still scan to see
-+ if the block is empty. We use this information
-+ to decide whether to erase it or not. */
-+ switch (ret) {
-+ case 0: cleanmarkerfound = 1; break;
-+ case 1: break;
-+ case 2: return BLK_STATE_BADBLOCK;
-+ case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
-+ default: return ret;
-+ }
-+ }
-+#endif
-+ buf_ofs = jeb->offset;
-+
-+ if (!buf_size) {
-+ buf_len = c->sector_size;
-+ } else {
-+ buf_len = EMPTY_SCAN_SIZE;
-+ err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
-+ if (err)
-+ return err;
-+ }
-+
-+ /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
-+ ofs = 0;
-+
-+ /* Scan only 4KiB of 0xFF before declaring it's empty */
-+ while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
-+ ofs += 4;
-+
-+ if (ofs == EMPTY_SCAN_SIZE) {
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ if (jffs2_cleanmarker_oob(c)) {
-+ /* scan oob, take care of cleanmarker */
-+ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
-+ D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
-+ switch (ret) {
-+ case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
-+ case 1: return BLK_STATE_ALLDIRTY;
-+ case 2: return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */
-+ case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
-+ default: return ret;
-+ }
-+ }
-+#endif
- D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
-- return 1; /* special return code */
-+ return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
-+ }
-+ if (ofs) {
-+ D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
-+ jeb->offset + ofs));
-+ DIRTY_SPACE(ofs);
- }
-
-+ /* Now ofs is a complete physical flash offset as it always was... */
-+ ofs += jeb->offset;
-+
- noise = 10;
-
- while(ofs < jeb->offset + c->sector_size) {
-- ssize_t retlen;
-- ACCT_PARANOIA_CHECK(jeb);
-+
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ cond_resched();
-
- if (ofs & 3) {
- printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
-- ofs = (ofs+3)&~3;
-+ ofs = PAD(ofs);
- continue;
- }
- if (ofs == prevofs) {
-@@ -196,102 +378,173 @@
- }
- prevofs = ofs;
-
-- if (jeb->offset + c->sector_size < ofs + sizeof(node)) {
-- D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node)));
-+ if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
-+ jeb->offset, c->sector_size, ofs, sizeof(*node)));
- DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
- break;
- }
-
-- err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, (char *)&node);
--
-- if (err) {
-- D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err));
-+ if (buf_ofs + buf_len < ofs + sizeof(*node)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ sizeof(struct jffs2_unknown_node), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
- return err;
-+ buf_ofs = ofs;
- }
-- if (retlen < sizeof(node)) {
-- D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
-- DIRTY_SPACE(retlen);
-- ofs += retlen;
-- continue;
-+
-+ node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
-+
-+ if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
-+ uint32_t inbuf_ofs = ofs - buf_ofs + 4;
-+ uint32_t scanend;
-+
-+ empty_start = ofs;
-+ ofs += 4;
-+
-+ /* If scanning empty space after only a cleanmarker, don't
-+ bother scanning the whole block */
-+ if (unlikely(empty_start == jeb->offset + c->cleanmarker_size &&
-+ jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len))
-+ scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs;
-+ else
-+ scanend = buf_len;
-+
-+ D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
-+ while (inbuf_ofs < scanend) {
-+ if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
-+ goto emptyends;
-+
-+ inbuf_ofs+=4;
-+ ofs += 4;
- }
-+ /* Ran off end. */
-+ D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
-
-- if (node.magic == JFFS2_EMPTY_BITMASK && node.nodetype == JFFS2_EMPTY_BITMASK) {
-- D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs));
-- err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-- if (err) return err;
-+ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
-+ c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size)
-+ return BLK_STATE_CLEANMARKER;
-+ wasempty = 1;
-+ continue;
-+ } else if (wasempty) {
-+ emptyends:
-+ printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
-+ DIRTY_SPACE(ofs-empty_start);
-+ wasempty = 0;
- continue;
- }
-
-- if (ofs == jeb->offset && node.magic == KSAMTIB_CIGAM_2SFFJ) {
-+ if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
- printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic == JFFS2_DIRTY_BITMASK) {
-- D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs));
-+ if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
-+ D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic == JFFS2_OLD_MAGIC_BITMASK) {
-+ if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
- printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
- printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-- if (node.magic != JFFS2_MAGIC_BITMASK) {
-+ if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
- /* OK. We're out of possibilities. Whinge and move on */
-- noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, node.magic);
-+ noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
-+ JFFS2_MAGIC_BITMASK, ofs,
-+ je16_to_cpu(node->magic));
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
- /* We seem to have a node of sorts. Check the CRC */
-- nodetype = node.nodetype;
-- node.nodetype |= JFFS2_NODE_ACCURATE;
-- hdr_crc = crc32(0, &node, sizeof(node)-4);
-- node.nodetype = nodetype;
-- if (hdr_crc != node.hdr_crc) {
-+ crcnode.magic = node->magic;
-+ crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
-+ crcnode.totlen = node->totlen;
-+ hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);
-+
-+ if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
- noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
-- ofs, node.magic, node.nodetype, node.totlen, node.hdr_crc, hdr_crc);
-+ ofs, je16_to_cpu(node->magic),
-+ je16_to_cpu(node->nodetype),
-+ je32_to_cpu(node->totlen),
-+ je32_to_cpu(node->hdr_crc),
-+ hdr_crc);
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-
-- if (ofs + node.totlen > jeb->offset + c->sector_size) {
-+ if (ofs + je32_to_cpu(node->totlen) >
-+ jeb->offset + c->sector_size) {
- /* Eep. Node goes over the end of the erase block. */
- printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
-- ofs, node.totlen);
-+ ofs, je32_to_cpu(node->totlen));
- printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
- DIRTY_SPACE(4);
- ofs += 4;
- continue;
- }
-
-- switch(node.nodetype | JFFS2_NODE_ACCURATE) {
-+ if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
-+ /* Wheee. This is an obsoleted node */
-+ D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
-+ continue;
-+ }
-+
-+ switch(je16_to_cpu(node->nodetype)) {
- case JFFS2_NODETYPE_INODE:
-- err = jffs2_scan_inode_node(c, jeb, &ofs);
-+ if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ sizeof(struct jffs2_raw_inode), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
-+ return err;
-+ buf_ofs = ofs;
-+ node = (void *)buf;
-+ }
-+ err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
- if (err) return err;
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_NODETYPE_DIRENT:
-- err = jffs2_scan_dirent_node(c, jeb, &ofs);
-+ if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
-+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-+ D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
-+ je32_to_cpu(node->totlen), buf_len, ofs));
-+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
-+ if (err)
-+ return err;
-+ buf_ofs = ofs;
-+ node = (void *)buf;
-+ }
-+ err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
- if (err) return err;
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_NODETYPE_CLEANMARKER:
-- if (node.totlen != sizeof(struct jffs2_unknown_node)) {
-+ D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
-+ if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
- printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
-- ofs, node.totlen, sizeof(struct jffs2_unknown_node));
-+ ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
- DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
-+ ofs += PAD(sizeof(struct jffs2_unknown_node));
- } else if (jeb->first_node) {
- printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
- DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
- ofs += PAD(sizeof(struct jffs2_unknown_node));
-- continue;
- } else {
- struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
- if (!marker_ref) {
-@@ -300,98 +553,80 @@
- }
- marker_ref->next_in_ino = NULL;
- marker_ref->next_phys = NULL;
-- marker_ref->flash_offset = ofs;
-- marker_ref->totlen = sizeof(struct jffs2_unknown_node);
-+ marker_ref->flash_offset = ofs | REF_NORMAL;
-+ marker_ref->__totlen = c->cleanmarker_size;
- jeb->first_node = jeb->last_node = marker_ref;
-
-- USED_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
-+ USED_SPACE(PAD(c->cleanmarker_size));
-+ ofs += PAD(c->cleanmarker_size);
- }
-- ofs += PAD(sizeof(struct jffs2_unknown_node));
-+ break;
-+
-+ case JFFS2_NODETYPE_PADDING:
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- default:
-- switch (node.nodetype & JFFS2_COMPAT_MASK) {
-+ switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
- case JFFS2_FEATURE_ROCOMPAT:
-- printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-+ printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
- c->flags |= JFFS2_SB_FLAG_RO;
-- if (!(OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY))
-+ if (!(jffs2_is_readonly(c)))
- return -EROFS;
-- DIRTY_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-- continue;
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
-+ break;
-
- case JFFS2_FEATURE_INCOMPAT:
-- printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-+ printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
- return -EINVAL;
-
- case JFFS2_FEATURE_RWCOMPAT_DELETE:
-- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-- DIRTY_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
-+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
-
- case JFFS2_FEATURE_RWCOMPAT_COPY:
-- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs);
-- USED_SPACE(PAD(node.totlen));
-- ofs += PAD(node.totlen);
-+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
-+ USED_SPACE(PAD(je32_to_cpu(node->totlen)));
-+ ofs += PAD(je32_to_cpu(node->totlen));
- break;
- }
- }
- }
-- D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset,
-- jeb->free_size, jeb->dirty_size, jeb->used_size));
-- return 0;
--}
-
--/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */
--static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *startofs, int *noise)
--{
-- __u32 *buf;
-- __u32 scanlen = (jeb->offset + c->sector_size) - *startofs;
-- __u32 curofs = *startofs;
--
-- buf = kmalloc(min((__u32)PAGE_SIZE, scanlen), GFP_KERNEL);
-- if (!buf) {
-- printk(KERN_WARNING "Scan buffer allocation failed\n");
-- return -ENOMEM;
-- }
-- while(scanlen) {
-- ssize_t retlen;
-- int ret, i;
--
-- ret = c->mtd->read(c->mtd, curofs, min((__u32)PAGE_SIZE, scanlen), &retlen, (char *)buf);
-- if(ret) {
-- D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((__u32)PAGE_SIZE, scanlen), curofs, ret));
-- kfree(buf);
-- return ret;
-- }
-- if (retlen < 4) {
-- D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n"));
-- kfree(buf);
-- return -EIO;
-- }
-- for (i=0; i<(retlen / 4); i++) {
-- if (buf[i] != 0xffffffff) {
-- curofs += i*4;
--
-- noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]);
-- DIRTY_SPACE(curofs - (*startofs));
-- *startofs = curofs;
-- kfree(buf);
-- return 0;
-- }
-- }
-- scanlen -= retlen&~3;
-- curofs += retlen&~3;
-- }
-
-- D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs));
-- kfree(buf);
-- *startofs = curofs;
-- return 0;
-+ D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
-+ jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
-+
-+ /* mark_node_obsolete can add to wasted !! */
-+ if (jeb->wasted_size) {
-+ jeb->dirty_size += jeb->wasted_size;
-+ c->dirty_size += jeb->wasted_size;
-+ c->wasted_size -= jeb->wasted_size;
-+ jeb->wasted_size = 0;
-+ }
-+
-+ if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
-+ && (!jeb->first_node || jeb->first_node->next_in_ino) )
-+ return BLK_STATE_CLEANMARKER;
-+
-+ /* move blocks with max 4 byte dirty space to cleanlist */
-+ else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
-+ c->dirty_size -= jeb->dirty_size;
-+ c->wasted_size += jeb->dirty_size;
-+ jeb->wasted_size += jeb->dirty_size;
-+ jeb->dirty_size = 0;
-+ return BLK_STATE_CLEAN;
-+ } else if (jeb->used_size || jeb->unchecked_size)
-+ return BLK_STATE_PARTDIRTY;
-+ else
-+ return BLK_STATE_ALLDIRTY;
- }
-
--static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, __u32 ino)
-+static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
- {
- struct jffs2_inode_cache *ic;
-
-@@ -399,137 +634,77 @@
- if (ic)
- return ic;
-
-+ if (ino > c->highest_ino)
-+ c->highest_ino = ino;
-+
- ic = jffs2_alloc_inode_cache();
- if (!ic) {
- printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n");
- return NULL;
- }
- memset(ic, 0, sizeof(*ic));
-- ic->scan = kmalloc(sizeof(struct jffs2_scan_info), GFP_KERNEL);
-- if (!ic->scan) {
-- printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed\n");
-- jffs2_free_inode_cache(ic);
-- return NULL;
-- }
-- memset(ic->scan, 0, sizeof(*ic->scan));
-+
- ic->ino = ino;
- ic->nodes = (void *)ic;
- jffs2_add_ino_cache(c, ic);
- if (ino == 1)
-- ic->nlink=1;
-+ ic->nlink = 1;
- return ic;
- }
-
--static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
-+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_inode *ri, uint32_t ofs)
- {
- struct jffs2_raw_node_ref *raw;
-- struct jffs2_full_dnode *fn;
-- struct jffs2_tmp_dnode_info *tn, **tn_list;
- struct jffs2_inode_cache *ic;
-- struct jffs2_raw_inode ri;
-- __u32 crc;
-- __u16 oldnodetype;
-- int ret;
-- ssize_t retlen;
--
-- D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs));
--
-- ret = c->mtd->read(c->mtd, *ofs, sizeof(ri), &retlen, (char *)&ri);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-- return ret;
-- }
-- if (retlen != sizeof(ri)) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs, sizeof(ri));
-- return -EIO;
-- }
-+ uint32_t ino = je32_to_cpu(ri->ino);
-
-- /* We sort of assume that the node was accurate when it was
-- first written to the medium :) */
-- oldnodetype = ri.nodetype;
-- ri.nodetype |= JFFS2_NODE_ACCURATE;
-- crc = crc32(0, &ri, sizeof(ri)-8);
-- ri.nodetype = oldnodetype;
-+ D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
-
-- if(crc != ri.node_crc) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, ri.node_crc, crc);
-- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(4);
-- *ofs += 4;
-- return 0;
-- }
-- /* There was a bug where we wrote hole nodes out with csize/dsize
-- swapped. Deal with it */
-- if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
-- ri.dsize = ri.csize;
-- ri.csize = 0;
-- }
-+ /* We do very little here now. Just check the ino# to which we should attribute
-+ this node; we can do all the CRC checking etc. later. There's a tradeoff here --
-+ we used to scan the flash once only, reading everything we want from it into
-+ memory, then building all our in-core data structures and freeing the extra
-+ information. Now we allow the first part of the mount to complete a lot quicker,
-+ but we have to go _back_ to the flash in order to finish the CRC checking, etc.
-+ Which means that the _full_ amount of time to get to proper write mode with GC
-+ operational may actually be _longer_ than before. Sucks to be me. */
-
-- if (ri.csize) {
-- /* Check data CRC too */
-- unsigned char *dbuf;
-- __u32 crc;
--
-- dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
-- if (!dbuf) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n");
-- return -ENOMEM;
-- }
-- ret = c->mtd->read(c->mtd, *ofs+sizeof(ri), ri.csize, &retlen, dbuf);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret);
-- kfree(dbuf);
-- return ret;
-- }
-- if (retlen != ri.csize) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs+ sizeof(ri), ri.csize);
-- kfree(dbuf);
-- return -EIO;
-- }
-- crc = crc32(0, dbuf, ri.csize);
-- kfree(dbuf);
-- if (crc != ri.data_crc) {
-- printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, ri.data_crc, crc);
-- DIRTY_SPACE(PAD(ri.totlen));
-- *ofs += PAD(ri.totlen);
-- return 0;
-- }
-- }
--
-- /* Wheee. It worked */
- raw = jffs2_alloc_raw_node_ref();
- if (!raw) {
- printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
- return -ENOMEM;
- }
-- tn = jffs2_alloc_tmp_dnode_info();
-- if (!tn) {
-- jffs2_free_raw_node_ref(raw);
-- return -ENOMEM;
-- }
-- fn = jffs2_alloc_full_dnode();
-- if (!fn) {
-- jffs2_free_tmp_dnode_info(tn);
-+
-+ ic = jffs2_get_ino_cache(c, ino);
-+ if (!ic) {
-+ /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
-+ first node we found for this inode. Do a CRC check to protect against the former
-+ case */
-+ uint32_t crc = crc32(0, ri, sizeof(*ri)-8);
-+
-+ if (crc != je32_to_cpu(ri->node_crc)) {
-+ printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-+ ofs, je32_to_cpu(ri->node_crc), crc);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
- jffs2_free_raw_node_ref(raw);
-- return -ENOMEM;
-+ return 0;
- }
-- ic = jffs2_scan_make_ino_cache(c, ri.ino);
-+ ic = jffs2_scan_make_ino_cache(c, ino);
- if (!ic) {
-- jffs2_free_full_dnode(fn);
-- jffs2_free_tmp_dnode_info(tn);
- jffs2_free_raw_node_ref(raw);
- return -ENOMEM;
- }
-+ }
-
-- /* Build the data structures and file them for later */
-- raw->flash_offset = *ofs;
-- raw->totlen = PAD(ri.totlen);
-+ /* Wheee. It worked */
-+
-+ raw->flash_offset = ofs | REF_UNCHECKED;
-+ raw->__totlen = PAD(je32_to_cpu(ri->totlen));
- raw->next_phys = NULL;
- raw->next_in_ino = ic->nodes;
-+
- ic->nodes = raw;
- if (!jeb->first_node)
- jeb->first_node = raw;
-@@ -538,134 +713,56 @@
- jeb->last_node = raw;
-
- D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
-- ri.ino, ri.version, ri.offset, ri.offset+ri.dsize));
--
-- pseudo_random += ri.version;
--
-- for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
-- if ((*tn_list)->version < ri.version)
-- continue;
-- if ((*tn_list)->version > ri.version)
-- break;
-- /* Wheee. We've found another instance of the same version number.
-- We should obsolete one of them.
-- */
-- D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3));
-- if (!jeb->used_size) {
-- D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n",
-- jeb->offset, raw->flash_offset & ~3));
-- ri.nodetype &= ~JFFS2_NODE_ACCURATE;
-- /* Perhaps we could also mark it as such on the medium. Maybe later */
-- }
-- break;
-- }
--
-- if (ri.nodetype & JFFS2_NODE_ACCURATE) {
-- memset(fn,0,sizeof(*fn));
--
-- fn->ofs = ri.offset;
-- fn->size = ri.dsize;
-- fn->frags = 0;
-- fn->raw = raw;
--
-- tn->next = NULL;
-- tn->fn = fn;
-- tn->version = ri.version;
-+ je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
-+ je32_to_cpu(ri->offset),
-+ je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));
-
-- USED_SPACE(PAD(ri.totlen));
-- jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes);
-- /* Make sure the one we just added is the _last_ in the list
-- with this version number, so the older ones get obsoleted */
-- while (tn->next && tn->next->version == tn->version) {
-+ pseudo_random += je32_to_cpu(ri->version);
-
-- D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
-- fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version));
--
-- if(tn->fn != fn)
-- BUG();
-- tn->fn = tn->next->fn;
-- tn->next->fn = fn;
-- tn = tn->next;
-- }
-- } else {
-- jffs2_free_full_dnode(fn);
-- jffs2_free_tmp_dnode_info(tn);
-- raw->flash_offset |= 1;
-- DIRTY_SPACE(PAD(ri.totlen));
-- }
-- *ofs += PAD(ri.totlen);
-+ UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
- return 0;
- }
-
--static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
-+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-+ struct jffs2_raw_dirent *rd, uint32_t ofs)
- {
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
- struct jffs2_inode_cache *ic;
-- struct jffs2_raw_dirent rd;
-- __u16 oldnodetype;
-- int ret;
-- __u32 crc;
-- ssize_t retlen;
--
-- D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs));
-+ uint32_t crc;
-
-- ret = c->mtd->read(c->mtd, *ofs, sizeof(rd), &retlen, (char *)&rd);
-- if (ret) {
-- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-- return ret;
-- }
-- if (retlen != sizeof(rd)) {
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs, sizeof(rd));
-- return -EIO;
-- }
-+ D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
-
-- /* We sort of assume that the node was accurate when it was
-- first written to the medium :) */
-- oldnodetype = rd.nodetype;
-- rd.nodetype |= JFFS2_NODE_ACCURATE;
-- crc = crc32(0, &rd, sizeof(rd)-8);
-- rd.nodetype = oldnodetype;
-+ /* We don't get here unless the node is still valid, so we don't have to
-+ mask in the ACCURATE bit any more. */
-+ crc = crc32(0, rd, sizeof(*rd)-8);
-
-- if (crc != rd.node_crc) {
-+ if (crc != je32_to_cpu(rd->node_crc)) {
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, rd.node_crc, crc);
-- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(4);
-- *ofs += 4;
-+ ofs, je32_to_cpu(rd->node_crc), crc);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
- return 0;
- }
-
-- pseudo_random += rd.version;
-+ pseudo_random += je32_to_cpu(rd->version);
-
-- fd = jffs2_alloc_full_dirent(rd.nsize+1);
-+ fd = jffs2_alloc_full_dirent(rd->nsize+1);
- if (!fd) {
- return -ENOMEM;
--}
-- ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]);
-- if (ret) {
-- jffs2_free_full_dirent(fd);
-- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n",
-- *ofs + sizeof(rd), ret);
-- return ret;
-- }
-- if (retlen != rd.nsize) {
-- jffs2_free_full_dirent(fd);
-- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
-- retlen, *ofs + sizeof(rd), rd.nsize);
-- return -EIO;
- }
-- crc = crc32(0, fd->name, rd.nsize);
-- if (crc != rd.name_crc) {
-+ memcpy(&fd->name, rd->name, rd->nsize);
-+ fd->name[rd->nsize] = 0;
-+
-+ crc = crc32(0, fd->name, rd->nsize);
-+ if (crc != je32_to_cpu(rd->name_crc)) {
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-- *ofs, rd.name_crc, crc);
-- fd->name[rd.nsize]=0;
-- D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino));
-+ ofs, je32_to_cpu(rd->name_crc), crc);
-+ D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
- jffs2_free_full_dirent(fd);
- /* FIXME: Why do we believe totlen? */
-- DIRTY_SPACE(PAD(rd.totlen));
-- *ofs += PAD(rd.totlen);
-+ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
-+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
- return 0;
- }
- raw = jffs2_alloc_raw_node_ref();
-@@ -674,15 +771,15 @@
- printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
- return -ENOMEM;
- }
-- ic = jffs2_scan_make_ino_cache(c, rd.pino);
-+ ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
- if (!ic) {
- jffs2_free_full_dirent(fd);
- jffs2_free_raw_node_ref(raw);
- return -ENOMEM;
- }
-
-- raw->totlen = PAD(rd.totlen);
-- raw->flash_offset = *ofs;
-+ raw->__totlen = PAD(je32_to_cpu(rd->totlen));
-+ raw->flash_offset = ofs | REF_PRISTINE;
- raw->next_phys = NULL;
- raw->next_in_ino = ic->nodes;
- ic->nodes = raw;
-@@ -692,24 +789,15 @@
- jeb->last_node->next_phys = raw;
- jeb->last_node = raw;
-
-- if (rd.nodetype & JFFS2_NODE_ACCURATE) {
- fd->raw = raw;
- fd->next = NULL;
-- fd->version = rd.version;
-- fd->ino = rd.ino;
-- fd->name[rd.nsize]=0;
-- fd->nhash = full_name_hash(fd->name, rd.nsize);
-- fd->type = rd.type;
--
-- USED_SPACE(PAD(rd.totlen));
-- jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
-- } else {
-- raw->flash_offset |= 1;
-- jffs2_free_full_dirent(fd);
-+ fd->version = je32_to_cpu(rd->version);
-+ fd->ino = je32_to_cpu(rd->ino);
-+ fd->nhash = full_name_hash(fd->name, rd->nsize);
-+ fd->type = rd->type;
-+ USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
-+ jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
-
-- DIRTY_SPACE(PAD(rd.totlen));
-- }
-- *ofs += PAD(rd.totlen);
- return 0;
- }
-
-@@ -731,26 +819,90 @@
- struct list_head *n = head->next;
-
- list_del(head);
-- while(count--)
-+ while(count--) {
- n = n->next;
-+ }
- list_add(head, n);
- }
-
--static void jffs2_rotate_lists(struct jffs2_sb_info *c)
-+void jffs2_rotate_lists(struct jffs2_sb_info *c)
- {
- uint32_t x;
-+ uint32_t rotateby;
-
- x = count_list(&c->clean_list);
-- if (x)
-- rotate_list((&c->clean_list), pseudo_random % x);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby));
-+
-+ rotate_list((&c->clean_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n",
-+ list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty clean_list\n"));
-+ }
-+
-+ x = count_list(&c->very_dirty_list);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby));
-+
-+ rotate_list((&c->very_dirty_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n",
-+ list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n"));
-+ }
-
- x = count_list(&c->dirty_list);
-- if (x)
-- rotate_list((&c->dirty_list), pseudo_random % x);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby));
-+
-+ rotate_list((&c->dirty_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n",
-+ list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n"));
-+ }
-+
-+ x = count_list(&c->erasable_list);
-+ if (x) {
-+ rotateby = pseudo_random % x;
-+ D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby));
-
-- if (c->nr_erasing_blocks)
-- rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks);
-+ rotate_list((&c->erasable_list), rotateby);
-
-- if (c->nr_free_blocks) /* Not that it should ever be zero */
-- rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks);
-+ D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n",
-+ list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n"));
-+ }
-+
-+ if (c->nr_erasing_blocks) {
-+ rotateby = pseudo_random % c->nr_erasing_blocks;
-+ D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby));
-+
-+ rotate_list((&c->erase_pending_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n",
-+ list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n"));
-+ }
-+
-+ if (c->nr_free_blocks) {
-+ rotateby = pseudo_random % c->nr_free_blocks;
-+ D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby));
-+
-+ rotate_list((&c->free_list), rotateby);
-+
-+ D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n",
-+ list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset));
-+ } else {
-+ D1(printk(KERN_DEBUG "Not rotating empty free_list\n"));
-+ }
- }
-diff -Nurb linux-mips-2.4.27/fs/jffs2/super-v24.c linux/fs/jffs2/super-v24.c
---- linux-mips-2.4.27/fs/jffs2/super-v24.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/super-v24.c 2004-11-19 10:25:12.126165288 +0100
-@@ -0,0 +1,167 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@redhat.com>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#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/jffs2.h>
-+#include <linux/pagemap.h>
-+#include <linux/mtd/mtd.h>
-+#include "nodelist.h"
-+
-+#ifndef MTD_BLOCK_MAJOR
-+#define MTD_BLOCK_MAJOR 31
-+#endif
-+
-+static void jffs2_put_super (struct super_block *);
-+
-+static struct super_operations jffs2_super_operations =
-+{
-+ .read_inode = jffs2_read_inode,
-+ .put_super = jffs2_put_super,
-+ .write_super = jffs2_write_super,
-+ .statfs = jffs2_statfs,
-+ .remount_fs = jffs2_remount_fs,
-+ .clear_inode = jffs2_clear_inode,
-+ .dirty_inode = jffs2_dirty_inode,
-+};
-+
-+
-+static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent)
-+{
-+ struct jffs2_sb_info *c;
-+ int ret;
-+
-+ D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
-+
-+ if (major(sb->s_dev) != MTD_BLOCK_MAJOR) {
-+ if (!silent)
-+ printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
-+ return NULL;
-+ }
-+
-+ c = JFFS2_SB_INFO(sb);
-+ memset(c, 0, sizeof(*c));
-+
-+ sb->s_op = &jffs2_super_operations;
-+
-+ c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
-+ if (!c->mtd) {
-+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev)));
-+ return NULL;
-+ }
-+
-+ ret = jffs2_do_fill_super(sb, data, silent);
-+ if (ret) {
-+ put_mtd_device(c->mtd);
-+ return NULL;
-+ }
-+
-+ return sb;
-+}
-+
-+static void jffs2_put_super (struct super_block *sb)
-+{
-+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-+
-+ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
-+
-+
-+ if (!(sb->s_flags & MS_RDONLY))
-+ jffs2_stop_garbage_collect_thread(c);
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
-+ jffs2_free_ino_caches(c);
-+ jffs2_free_raw_node_refs(c);
-+ kfree(c->blocks);
-+ jffs2_nand_flash_cleanup(c);
-+ kfree(c->inocache_list);
-+ if (c->mtd->sync)
-+ c->mtd->sync(c->mtd);
-+ put_mtd_device(c->mtd);
-+
-+ D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
-+}
-+
-+static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super);
-+
-+static int __init init_jffs2_fs(void)
-+{
-+ int ret;
-+
-+ printk(KERN_INFO "JFFS2 version 2.2."
-+#ifdef CONFIG_FS_JFFS2_NAND
-+ " (NAND)"
-+#endif
-+ " (C) 2001-2003 Red Hat, Inc.\n");
-+
-+#ifdef JFFS2_OUT_OF_KERNEL
-+ /* sanity checks. Could we do these at compile time? */
-+ if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
-+ printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n",
-+ sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-+ return -EIO;
-+ }
-+
-+ if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-+ printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n",
-+ sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
-+ return -EIO;
-+ }
-+#endif
-+ ret = jffs2_zlib_init();
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
-+ goto out;
-+ }
-+ ret = jffs2_create_slab_caches();
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-+ goto out_zlib;
-+ }
-+ ret = register_filesystem(&jffs2_fs_type);
-+ if (ret) {
-+ printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
-+ goto out_slab;
-+ }
-+ return 0;
-+
-+ out_slab:
-+ jffs2_destroy_slab_caches();
-+ out_zlib:
-+ jffs2_zlib_exit();
-+ out:
-+
-+ return ret;
-+}
-+
-+static void __exit exit_jffs2_fs(void)
-+{
-+ jffs2_destroy_slab_caches();
-+ jffs2_zlib_exit();
-+ unregister_filesystem(&jffs2_fs_type);
-+}
-+
-+module_init(init_jffs2_fs);
-+module_exit(exit_jffs2_fs);
-+
-+MODULE_DESCRIPTION("The Journalling Flash File System, v2");
-+MODULE_AUTHOR("Red Hat, Inc.");
-+MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
-+ // the sake of this tag. It's Free Software.
-diff -Nurb linux-mips-2.4.27/fs/jffs2/super.c linux/fs/jffs2/super.c
---- linux-mips-2.4.27/fs/jffs2/super.c 2003-01-11 18:53:17.000000000 +0100
-+++ linux/fs/jffs2/super.c 2004-11-19 10:25:12.127165136 +0100
-@@ -1,291 +1,257 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #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/mount.h>
- #include <linux/jffs2.h>
- #include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
-+#include <linux/ctype.h>
-+#include <linux/namei.h>
- #include "nodelist.h"
-
--#ifndef MTD_BLOCK_MAJOR
--#define MTD_BLOCK_MAJOR 31
--#endif
-+static void jffs2_put_super(struct super_block *);
-+
-+static kmem_cache_t *jffs2_inode_cachep;
-+
-+static struct inode *jffs2_alloc_inode(struct super_block *sb)
-+{
-+ struct jffs2_inode_info *ei;
-+ ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
-+ if (!ei)
-+ return NULL;
-+ return &ei->vfs_inode;
-+}
-+
-+static void jffs2_destroy_inode(struct inode *inode)
-+{
-+ kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
-+}
-+
-+static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-+{
-+ struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
-
--extern void jffs2_read_inode (struct inode *);
--void jffs2_put_super (struct super_block *);
--void jffs2_write_super (struct super_block *);
--static int jffs2_statfs (struct super_block *, struct statfs *);
--int jffs2_remount_fs (struct super_block *, int *, char *);
--extern void jffs2_clear_inode (struct inode *);
-+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-+ SLAB_CTOR_CONSTRUCTOR) {
-+ init_MUTEX_LOCKED(&ei->sem);
-+ inode_init_once(&ei->vfs_inode);
-+ }
-+}
-
- static struct super_operations jffs2_super_operations =
- {
-- read_inode: jffs2_read_inode,
--// delete_inode: jffs2_delete_inode,
-- put_super: jffs2_put_super,
-- write_super: jffs2_write_super,
-- statfs: jffs2_statfs,
-- remount_fs: jffs2_remount_fs,
-- clear_inode: jffs2_clear_inode
-+ .alloc_inode = jffs2_alloc_inode,
-+ .destroy_inode =jffs2_destroy_inode,
-+ .read_inode = jffs2_read_inode,
-+ .put_super = jffs2_put_super,
-+ .write_super = jffs2_write_super,
-+ .statfs = jffs2_statfs,
-+ .remount_fs = jffs2_remount_fs,
-+ .clear_inode = jffs2_clear_inode,
-+ .dirty_inode = jffs2_dirty_inode,
- };
-
--static int jffs2_statfs(struct super_block *sb, struct statfs *buf)
-+static int jffs2_sb_compare(struct super_block *sb, void *data)
- {
-+ struct jffs2_sb_info *p = data;
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-- unsigned long avail;
-
-- buf->f_type = JFFS2_SUPER_MAGIC;
-- buf->f_bsize = 1 << PAGE_SHIFT;
-- buf->f_blocks = c->flash_size >> PAGE_SHIFT;
-- buf->f_files = 0;
-- buf->f_ffree = 0;
-- buf->f_namelen = JFFS2_MAX_NAME_LEN;
--
-- spin_lock_bh(&c->erase_completion_lock);
--
-- avail = c->dirty_size + c->free_size;
-- if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
-- avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE;
-- else
-- avail = 0;
--
-- buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
--
--#if CONFIG_JFFS2_FS_DEBUG > 0
-- printk(KERN_DEBUG "STATFS:\n");
-- printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-- printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-- printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-- printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-- printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-- printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-- printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
--
-- if (c->nextblock) {
-- printk(KERN_DEBUG "nextblock: 0x%08x\n", c->nextblock->offset);
-- } else {
-- printk(KERN_DEBUG "nextblock: NULL\n");
-- }
-- if (c->gcblock) {
-- printk(KERN_DEBUG "gcblock: 0x%08x\n", c->gcblock->offset);
-+ /* The superblocks are considered to be equivalent if the underlying MTD
-+ device is the same one */
-+ if (c->mtd == p->mtd) {
-+ D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name));
-+ return 1;
- } else {
-- printk(KERN_DEBUG "gcblock: NULL\n");
-+ D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n",
-+ c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name));
-+ return 0;
- }
-- if (list_empty(&c->clean_list)) {
-- printk(KERN_DEBUG "clean_list: empty\n");
-- } else {
-- struct list_head *this;
-+}
-
-- list_for_each(this, &c->clean_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "clean_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->dirty_list)) {
-- printk(KERN_DEBUG "dirty_list: empty\n");
-- } else {
-- struct list_head *this;
-+static int jffs2_sb_set(struct super_block *sb, void *data)
-+{
-+ struct jffs2_sb_info *p = data;
-
-- list_for_each(this, &c->dirty_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "dirty_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->erasing_list)) {
-- printk(KERN_DEBUG "erasing_list: empty\n");
-- } else {
-- struct list_head *this;
-+ /* For persistence of NFS exports etc. we use the same s_dev
-+ each time we mount the device, don't just use an anonymous
-+ device */
-+ sb->s_fs_info = p;
-+ p->os_priv = sb;
-+ sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index);
-
-- list_for_each(this, &c->erasing_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "erasing_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->erase_pending_list)) {
-- printk(KERN_DEBUG "erase_pending_list: empty\n");
-- } else {
-- struct list_head *this;
-+ return 0;
-+}
-
-- list_for_each(this, &c->erase_pending_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "erase_pending_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->free_list)) {
-- printk(KERN_DEBUG "free_list: empty\n");
-- } else {
-- struct list_head *this;
-+static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data, struct mtd_info *mtd)
-+{
-+ struct super_block *sb;
-+ struct jffs2_sb_info *c;
-+ int ret;
-
-- list_for_each(this, &c->free_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "free_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->bad_list)) {
-- printk(KERN_DEBUG "bad_list: empty\n");
-- } else {
-- struct list_head *this;
-+ c = kmalloc(sizeof(*c), GFP_KERNEL);
-+ if (!c)
-+ return ERR_PTR(-ENOMEM);
-+ memset(c, 0, sizeof(*c));
-+ c->mtd = mtd;
-
-- list_for_each(this, &c->bad_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "bad_list: %08x\n", jeb->offset);
-- }
-- }
-- if (list_empty(&c->bad_used_list)) {
-- printk(KERN_DEBUG "bad_used_list: empty\n");
-- } else {
-- struct list_head *this;
-+ sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
-+
-+ if (IS_ERR(sb))
-+ goto out_put;
-
-- list_for_each(this, &c->bad_used_list) {
-- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-- printk(KERN_DEBUG "bad_used_list: %08x\n", jeb->offset);
-+ if (sb->s_root) {
-+ /* New mountpoint for JFFS2 which is already mounted */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n",
-+ mtd->index, mtd->name));
-+ goto out_put;
- }
-+
-+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
-+ mtd->index, mtd->name));
-+
-+ sb->s_op = &jffs2_super_operations;
-+
-+ ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
-+
-+ if (ret) {
-+ /* Failure case... */
-+ up_write(&sb->s_umount);
-+ deactivate_super(sb);
-+ return ERR_PTR(ret);
- }
--#endif /* CONFIG_JFFS2_FS_DEBUG */
-
-- spin_unlock_bh(&c->erase_completion_lock);
-+ sb->s_flags |= MS_ACTIVE;
-+ return sb;
-
-+ out_put:
-+ kfree(c);
-+ put_mtd_device(mtd);
-
-- return 0;
-+ return sb;
- }
-
--static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent)
-+static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data, int mtdnr)
- {
-- struct jffs2_sb_info *c;
-- struct inode *root_i;
-- int i;
--
-- D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
-+ struct mtd_info *mtd;
-
-- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
-- if (!silent)
-- printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
-- return NULL;
-+ mtd = get_mtd_device(NULL, mtdnr);
-+ if (!mtd) {
-+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
-+ return ERR_PTR(-EINVAL);
- }
-
-- c = JFFS2_SB_INFO(sb);
-- memset(c, 0, sizeof(*c));
-+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
-+}
-
-- c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
-- if (!c->mtd) {
-- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
-- return NULL;
-+static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
-+ int flags, const char *dev_name,
-+ void *data)
-+{
-+ int err;
-+ struct nameidata nd;
-+ int mtdnr;
-+
-+ if (!dev_name)
-+ return ERR_PTR(-EINVAL);
-+
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name));
-+
-+ /* The preferred way of mounting in future; especially when
-+ CONFIG_BLK_DEV is implemented - we specify the underlying
-+ MTD device by number or by name, so that we don't require
-+ block device support to be present in the kernel. */
-+
-+ /* FIXME: How to do the root fs this way? */
-+
-+ if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
-+ /* Probably mounting without the blkdev crap */
-+ if (dev_name[3] == ':') {
-+ struct mtd_info *mtd;
-+
-+ /* Mount by MTD device name */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4));
-+ for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
-+ mtd = get_mtd_device(NULL, mtdnr);
-+ if (mtd) {
-+ if (!strcmp(mtd->name, dev_name+4))
-+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
-+ put_mtd_device(mtd);
- }
-- c->sector_size = c->mtd->erasesize;
-- c->free_size = c->flash_size = c->mtd->size;
-- c->nr_blocks = c->mtd->size / c->mtd->erasesize;
-- c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
-- if (!c->blocks)
-- goto out_mtd;
-- for (i=0; i<c->nr_blocks; i++) {
-- INIT_LIST_HEAD(&c->blocks[i].list);
-- c->blocks[i].offset = i * c->sector_size;
-- c->blocks[i].free_size = c->sector_size;
-- c->blocks[i].dirty_size = 0;
-- c->blocks[i].used_size = 0;
-- c->blocks[i].first_node = NULL;
-- c->blocks[i].last_node = NULL;
-- }
--
-- spin_lock_init(&c->nodelist_lock);
-- init_MUTEX(&c->alloc_sem);
-- init_waitqueue_head(&c->erase_wait);
-- spin_lock_init(&c->erase_completion_lock);
-- spin_lock_init(&c->inocache_lock);
--
-- INIT_LIST_HEAD(&c->clean_list);
-- INIT_LIST_HEAD(&c->dirty_list);
-- INIT_LIST_HEAD(&c->erasing_list);
-- INIT_LIST_HEAD(&c->erase_pending_list);
-- INIT_LIST_HEAD(&c->erase_complete_list);
-- INIT_LIST_HEAD(&c->free_list);
-- INIT_LIST_HEAD(&c->bad_list);
-- INIT_LIST_HEAD(&c->bad_used_list);
-- c->highest_ino = 1;
--
-- if (jffs2_build_filesystem(c)) {
-- D1(printk(KERN_DEBUG "build_fs failed\n"));
-- goto out_nodes;
- }
-+ printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4);
-+ } else if (isdigit(dev_name[3])) {
-+ /* Mount by MTD device number name */
-+ char *endptr;
-
-- sb->s_op = &jffs2_super_operations;
-+ mtdnr = simple_strtoul(dev_name+3, &endptr, 0);
-+ if (!*endptr) {
-+ /* It was a valid number */
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr));
-+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
-+ }
-+ }
-+ }
-
-- D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
-- root_i = iget(sb, 1);
-- if (is_bad_inode(root_i)) {
-- D1(printk(KERN_WARNING "get root inode failed\n"));
-- goto out_nodes;
-+ /* Try the old way - the hack where we allowed users to mount
-+ /dev/mtdblock$(n) but didn't actually _use_ the blkdev */
-+
-+ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
-+
-+ D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n",
-+ err, nd.dentry->d_inode));
-+
-+ if (err)
-+ return ERR_PTR(err);
-+
-+ err = -EINVAL;
-+
-+ if (!S_ISBLK(nd.dentry->d_inode->i_mode))
-+ goto out;
-+
-+ if (nd.mnt->mnt_flags & MNT_NODEV) {
-+ err = -EACCES;
-+ goto out;
- }
-
-- D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n"));
-- sb->s_root = d_alloc_root(root_i);
-- if (!sb->s_root)
-- goto out_root_i;
-+ if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) {
-+ if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */
-+ printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n",
-+ dev_name);
-+ goto out;
-+ }
-
--#if LINUX_VERSION_CODE >= 0x20403
-- sb->s_maxbytes = 0xFFFFFFFF;
--#endif
-- sb->s_blocksize = PAGE_CACHE_SIZE;
-- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-- sb->s_magic = JFFS2_SUPER_MAGIC;
-- if (!(sb->s_flags & MS_RDONLY))
-- jffs2_start_garbage_collect_thread(c);
-- return sb;
-+ mtdnr = iminor(nd.dentry->d_inode);
-+ path_release(&nd);
-
-- out_root_i:
-- iput(root_i);
-- out_nodes:
-- jffs2_free_ino_caches(c);
-- jffs2_free_raw_node_refs(c);
-- kfree(c->blocks);
-- out_mtd:
-- put_mtd_device(c->mtd);
-- return NULL;
-+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr);
-+
-+out:
-+ path_release(&nd);
-+ return ERR_PTR(err);
- }
-
--void jffs2_put_super (struct super_block *sb)
-+static void jffs2_put_super (struct super_block *sb)
- {
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-
-@@ -293,74 +259,53 @@
-
- if (!(sb->s_flags & MS_RDONLY))
- jffs2_stop_garbage_collect_thread(c);
-+ down(&c->alloc_sem);
-+ jffs2_flush_wbuf_pad(c);
-+ up(&c->alloc_sem);
- jffs2_free_ino_caches(c);
- jffs2_free_raw_node_refs(c);
- kfree(c->blocks);
-+ jffs2_nand_flash_cleanup(c);
-+ kfree(c->inocache_list);
- if (c->mtd->sync)
- c->mtd->sync(c->mtd);
-- put_mtd_device(c->mtd);
-
- D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
- }
-
--int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
-+static void jffs2_kill_sb(struct super_block *sb)
- {
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
--
-- if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
-- return -EROFS;
--
-- /* We stop if it was running, then restart if it needs to.
-- This also catches the case where it was stopped and this
-- is just a remount to restart it */
-- if (!(sb->s_flags & MS_RDONLY))
-- jffs2_stop_garbage_collect_thread(c);
--
-- if (!(*flags & MS_RDONLY))
-- jffs2_start_garbage_collect_thread(c);
--
-- sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY);
--
-- return 0;
--}
--
--void jffs2_write_super (struct super_block *sb)
--{
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-- sb->s_dirt = 0;
--
-- if (sb->s_flags & MS_RDONLY)
-- return;
--
-- jffs2_garbage_collect_trigger(c);
-- jffs2_erase_pending_blocks(c);
-- jffs2_mark_erased_blocks(c);
-+ generic_shutdown_super(sb);
-+ put_mtd_device(c->mtd);
-+ kfree(c);
- }
-
--
--static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super);
-+static struct file_system_type jffs2_fs_type = {
-+ .owner = THIS_MODULE,
-+ .name = "jffs2",
-+ .get_sb = jffs2_get_sb,
-+ .kill_sb = jffs2_kill_sb,
-+};
-
- static int __init init_jffs2_fs(void)
- {
- int ret;
-
-- printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n");
--
--#ifdef JFFS2_OUT_OF_KERNEL
-- /* sanity checks. Could we do these at compile time? */
-- if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
-- printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n",
-- sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-- return -EIO;
-- }
--
-- if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-- printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n",
-- sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
-- return -EIO;
-- }
-+ printk(KERN_INFO "JFFS2 version 2.2."
-+#ifdef CONFIG_FS_JFFS2_NAND
-+ " (NAND)"
- #endif
-+ " (C) 2001-2003 Red Hat, Inc.\n");
-
-+ jffs2_inode_cachep = kmem_cache_create("jffs2_i",
-+ sizeof(struct jffs2_inode_info),
-+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
-+ jffs2_i_init_once, NULL);
-+ if (!jffs2_inode_cachep) {
-+ printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
-+ return -ENOMEM;
-+ }
- ret = jffs2_zlib_init();
- if (ret) {
- printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
-@@ -388,9 +333,10 @@
-
- static void __exit exit_jffs2_fs(void)
- {
-+ unregister_filesystem(&jffs2_fs_type);
- jffs2_destroy_slab_caches();
- jffs2_zlib_exit();
-- unregister_filesystem(&jffs2_fs_type);
-+ kmem_cache_destroy(jffs2_inode_cachep);
- }
-
- module_init(init_jffs2_fs);
-diff -Nurb linux-mips-2.4.27/fs/jffs2/symlink.c linux/fs/jffs2/symlink.c
---- linux-mips-2.4.27/fs/jffs2/symlink.c 2002-06-27 00:36:20.000000000 +0200
-+++ linux/fs/jffs2/symlink.c 2004-11-19 10:25:12.129164832 +0100
-@@ -3,35 +3,11 @@
- *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
-@@ -39,7 +15,6 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
--#include <linux/jffs2.h>
- #include "nodelist.h"
-
- int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
-@@ -47,45 +22,17 @@
-
- struct inode_operations jffs2_symlink_inode_operations =
- {
-- readlink: jffs2_readlink,
-- follow_link: jffs2_follow_link,
-- setattr: jffs2_setattr
-+ .readlink = jffs2_readlink,
-+ .follow_link = jffs2_follow_link,
-+ .setattr = jffs2_setattr
- };
-
--static char *jffs2_getlink(struct dentry *dentry)
--{
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
-- char *buf;
-- int ret;
--
-- down(&f->sem);
-- if (!f->metadata) {
-- up(&f->sem);
-- printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
-- return ERR_PTR(-EINVAL);
-- }
-- buf = kmalloc(f->metadata->size+1, GFP_USER);
-- if (!buf) {
-- up(&f->sem);
-- return ERR_PTR(-ENOMEM);
-- }
-- buf[f->metadata->size]=0;
--
-- ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
-- up(&f->sem);
-- if (ret) {
-- kfree(buf);
-- return ERR_PTR(ret);
-- }
-- return buf;
--
--}
- int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
- {
- unsigned char *kbuf;
- int ret;
-
-- kbuf = jffs2_getlink(dentry);
-+ kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
- if (IS_ERR(kbuf))
- return PTR_ERR(kbuf);
-
-@@ -99,7 +46,7 @@
- unsigned char *buf;
- int ret;
-
-- buf = jffs2_getlink(dentry);
-+ buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
-
- if (IS_ERR(buf))
- return PTR_ERR(buf);
-diff -Nurb linux-mips-2.4.27/fs/jffs2/wbuf.c linux/fs/jffs2/wbuf.c
---- linux-mips-2.4.27/fs/jffs2/wbuf.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/wbuf.c 2004-11-19 10:25:12.131164528 +0100
-@@ -0,0 +1,1156 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@redhat.com>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/crc32.h>
-+#include <linux/mtd/nand.h>
-+#include "nodelist.h"
-+
-+/* For testing write failures */
-+#undef BREAKME
-+#undef BREAKMEHEADER
-+
-+#ifdef BREAKME
-+static unsigned char *brokenbuf;
-+#endif
-+
-+/* max. erase failures before we mark a block bad */
-+#define MAX_ERASE_FAILURES 5
-+
-+/* two seconds timeout for timed wbuf-flushing */
-+#define WBUF_FLUSH_TIMEOUT 2 * HZ
-+
-+struct jffs2_inodirty {
-+ uint32_t ino;
-+ struct jffs2_inodirty *next;
-+};
-+
-+static struct jffs2_inodirty inodirty_nomem;
-+
-+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ struct jffs2_inodirty *this = c->wbuf_inodes;
-+
-+ /* If a malloc failed, consider _everything_ dirty */
-+ if (this == &inodirty_nomem)
-+ return 1;
-+
-+ /* If ino == 0, _any_ non-GC writes mean 'yes' */
-+ if (this && !ino)
-+ return 1;
-+
-+ /* Look to see if the inode in question is pending in the wbuf */
-+ while (this) {
-+ if (this->ino == ino)
-+ return 1;
-+ this = this->next;
-+ }
-+ return 0;
-+}
-+
-+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
-+{
-+ struct jffs2_inodirty *this;
-+
-+ this = c->wbuf_inodes;
-+
-+ if (this != &inodirty_nomem) {
-+ while (this) {
-+ struct jffs2_inodirty *next = this->next;
-+ kfree(this);
-+ this = next;
-+ }
-+ }
-+ c->wbuf_inodes = NULL;
-+}
-+
-+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ struct jffs2_inodirty *new;
-+
-+ /* Mark the superblock dirty so that kupdated will flush... */
-+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
-+
-+ if (jffs2_wbuf_pending_for_ino(c, ino))
-+ return;
-+
-+ new = kmalloc(sizeof(*new), GFP_KERNEL);
-+ if (!new) {
-+ D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
-+ jffs2_clear_wbuf_ino_list(c);
-+ c->wbuf_inodes = &inodirty_nomem;
-+ return;
-+ }
-+ new->ino = ino;
-+ new->next = c->wbuf_inodes;
-+ c->wbuf_inodes = new;
-+ return;
-+}
-+
-+static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
-+{
-+ struct list_head *this, *next;
-+ static int n;
-+
-+ if (list_empty(&c->erasable_pending_wbuf_list))
-+ return;
-+
-+ list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
-+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-+
-+ D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
-+ list_del(this);
-+ if ((jiffies + (n++)) & 127) {
-+ /* Most of the time, we just erase it immediately. Otherwise we
-+ spend ages scanning it on mount, etc. */
-+ D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
-+ list_add_tail(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ } else {
-+ /* Sometimes, however, we leave it elsewhere so it doesn't get
-+ immediately reused, and we spread the load a bit. */
-+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
-+ list_add_tail(&jeb->list, &c->erasable_list);
-+ }
-+ }
-+}
-+
-+/* Recover from failure to write wbuf. Recover the nodes up to the
-+ * wbuf, not the one which we were starting to try to write. */
-+
-+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
-+{
-+ struct jffs2_eraseblock *jeb, *new_jeb;
-+ struct jffs2_raw_node_ref **first_raw, **raw;
-+ size_t retlen;
-+ int ret;
-+ unsigned char *buf;
-+ uint32_t start, end, ofs, len;
-+
-+ spin_lock(&c->erase_completion_lock);
-+
-+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
-+
-+ D1(printk("About to refile bad block at %08x\n", jeb->offset));
-+
-+ D2(jffs2_dump_block_lists(c));
-+ /* File the existing block on the bad_used_list.... */
-+ if (c->nextblock == jeb)
-+ c->nextblock = NULL;
-+ else /* Not sure this should ever happen... need more coffee */
-+ list_del(&jeb->list);
-+ if (jeb->first_node) {
-+ D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
-+ list_add(&jeb->list, &c->bad_used_list);
-+ } else {
-+ BUG();
-+ /* It has to have had some nodes or we couldn't be here */
-+ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
-+ list_add(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ }
-+ D2(jffs2_dump_block_lists(c));
-+
-+ /* Adjust its size counts accordingly */
-+ c->wasted_size += jeb->free_size;
-+ c->free_size -= jeb->free_size;
-+ jeb->wasted_size += jeb->free_size;
-+ jeb->free_size = 0;
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ /* Find the first node to be recovered, by skipping over every
-+ node which ends before the wbuf starts, or which is obsolete. */
-+ first_raw = &jeb->first_node;
-+ while (*first_raw &&
-+ (ref_obsolete(*first_raw) ||
-+ (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
-+ D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
-+ ref_offset(*first_raw), ref_flags(*first_raw),
-+ (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)),
-+ c->wbuf_ofs));
-+ first_raw = &(*first_raw)->next_phys;
-+ }
-+
-+ if (!*first_raw) {
-+ /* All nodes were obsolete. Nothing to recover. */
-+ D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
-+ spin_unlock(&c->erase_completion_lock);
-+ return;
-+ }
-+
-+ start = ref_offset(*first_raw);
-+ end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw);
-+
-+ /* Find the last node to be recovered */
-+ raw = first_raw;
-+ while ((*raw)) {
-+ if (!ref_obsolete(*raw))
-+ end = ref_offset(*raw) + ref_totlen(c, jeb, *raw);
-+
-+ raw = &(*raw)->next_phys;
-+ }
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end));
-+
-+ buf = NULL;
-+ if (start < c->wbuf_ofs) {
-+ /* First affected node was already partially written.
-+ * Attempt to reread the old data into our buffer. */
-+
-+ buf = kmalloc(end - start, GFP_KERNEL);
-+ if (!buf) {
-+ printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
-+
-+ goto read_failed;
-+ }
-+
-+ /* Do the read... */
-+ ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
-+ if (ret == -EIO && retlen == c->wbuf_ofs - start) {
-+ /* ECC recovered */
-+ ret = 0;
-+ }
-+ if (ret || retlen != c->wbuf_ofs - start) {
-+ printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
-+
-+ kfree(buf);
-+ buf = NULL;
-+ read_failed:
-+ first_raw = &(*first_raw)->next_phys;
-+ /* If this was the only node to be recovered, give up */
-+ if (!(*first_raw))
-+ return;
-+
-+ /* It wasn't. Go on and try to recover nodes complete in the wbuf */
-+ start = ref_offset(*first_raw);
-+ } else {
-+ /* Read succeeded. Copy the remaining data from the wbuf */
-+ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
-+ }
-+ }
-+ /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
-+ Either 'buf' contains the data, or we find it in the wbuf */
-+
-+
-+ /* ... and get an allocation of space from a shiny new block instead */
-+ ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
-+ if (ret) {
-+ printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
-+ if (buf)
-+ kfree(buf);
-+ return;
-+ }
-+ if (end-start >= c->wbuf_pagesize) {
-+ /* Need to do another write immediately. This, btw,
-+ means that we'll be writing from 'buf' and not from
-+ the wbuf. Since if we're writing from the wbuf there
-+ won't be more than a wbuf full of data, now will
-+ there? :) */
-+
-+ uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
-+
-+ D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
-+ towrite, ofs));
-+
-+#ifdef BREAKMEHEADER
-+ static int breakme;
-+ if (breakme++ == 20) {
-+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
-+ breakme = 0;
-+ c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-+ brokenbuf, NULL, c->oobinfo);
-+ ret = -EIO;
-+ } else
-+#endif
-+ ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-+ buf, NULL, c->oobinfo);
-+
-+ if (ret || retlen != towrite) {
-+ /* Argh. We tried. Really we did. */
-+ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
-+ kfree(buf);
-+
-+ if (retlen) {
-+ struct jffs2_raw_node_ref *raw2;
-+
-+ raw2 = jffs2_alloc_raw_node_ref();
-+ if (!raw2)
-+ return;
-+
-+ raw2->flash_offset = ofs | REF_OBSOLETE;
-+ raw2->__totlen = ref_totlen(c, jeb, *first_raw);
-+ raw2->next_phys = NULL;
-+ raw2->next_in_ino = NULL;
-+
-+ jffs2_add_physical_node_ref(c, raw2);
-+ }
-+ return;
-+ }
-+ printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
-+
-+ c->wbuf_len = (end - start) - towrite;
-+ c->wbuf_ofs = ofs + towrite;
-+ memcpy(c->wbuf, buf + towrite, c->wbuf_len);
-+ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
-+
-+ kfree(buf);
-+ } else {
-+ /* OK, now we're left with the dregs in whichever buffer we're using */
-+ if (buf) {
-+ memcpy(c->wbuf, buf, end-start);
-+ kfree(buf);
-+ } else {
-+ memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
-+ }
-+ c->wbuf_ofs = ofs;
-+ c->wbuf_len = end - start;
-+ }
-+
-+ /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
-+ new_jeb = &c->blocks[ofs / c->sector_size];
-+
-+ spin_lock(&c->erase_completion_lock);
-+ if (new_jeb->first_node) {
-+ /* Odd, but possible with ST flash later maybe */
-+ new_jeb->last_node->next_phys = *first_raw;
-+ } else {
-+ new_jeb->first_node = *first_raw;
-+ }
-+
-+ raw = first_raw;
-+ while (*raw) {
-+ uint32_t rawlen = ref_totlen(c, jeb, *raw);
-+
-+ D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
-+ rawlen, ref_offset(*raw), ref_flags(*raw), ofs));
-+
-+ if (ref_obsolete(*raw)) {
-+ /* Shouldn't really happen much */
-+ new_jeb->dirty_size += rawlen;
-+ new_jeb->free_size -= rawlen;
-+ c->dirty_size += rawlen;
-+ } else {
-+ new_jeb->used_size += rawlen;
-+ new_jeb->free_size -= rawlen;
-+ jeb->dirty_size += rawlen;
-+ jeb->used_size -= rawlen;
-+ c->dirty_size += rawlen;
-+ }
-+ c->free_size -= rawlen;
-+ (*raw)->flash_offset = ofs | ref_flags(*raw);
-+ ofs += rawlen;
-+ new_jeb->last_node = *raw;
-+
-+ raw = &(*raw)->next_phys;
-+ }
-+
-+ /* Fix up the original jeb now it's on the bad_list */
-+ *first_raw = NULL;
-+ if (first_raw == &jeb->first_node) {
-+ jeb->last_node = NULL;
-+ D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
-+ list_del(&jeb->list);
-+ list_add(&jeb->list, &c->erase_pending_list);
-+ c->nr_erasing_blocks++;
-+ jffs2_erase_pending_trigger(c);
-+ }
-+ else
-+ jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ ACCT_SANITY_CHECK(c,new_jeb);
-+ D1(ACCT_PARANOIA_CHECK(new_jeb));
-+
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));
-+}
-+
-+/* Meaning of pad argument:
-+ 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
-+ 1: Pad, do not adjust nextblock free_size
-+ 2: Pad, adjust nextblock free_size
-+*/
-+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
-+{
-+ int ret;
-+ size_t retlen;
-+
-+ /* Nothing to do if not NAND flash. In particular, we shouldn't
-+ del_timer() the timer we never initialised. */
-+ if (jffs2_can_mark_obsolete(c))
-+ return 0;
-+
-+ if (!down_trylock(&c->alloc_sem)) {
-+ up(&c->alloc_sem);
-+ printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
-+ BUG();
-+ }
-+
-+ if(!c->wbuf || !c->wbuf_len)
-+ return 0;
-+
-+ /* claim remaining space on the page
-+ this happens, if we have a change to a new block,
-+ or if fsync forces us to flush the writebuffer.
-+ if we have a switch to next page, we will not have
-+ enough remaining space for this.
-+ */
-+ if (pad) {
-+ c->wbuf_len = PAD(c->wbuf_len);
-+
-+ if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
-+ struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
-+ padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
-+ padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
-+ padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
-+ }
-+ }
-+ /* else jffs2_flash_writev has actually filled in the rest of the
-+ buffer for us, and will deal with the node refs etc. later. */
-+
-+#ifdef BREAKME
-+ static int breakme;
-+ if (breakme++ == 20) {
-+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
-+ breakme = 0;
-+ c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
-+ &retlen, brokenbuf, NULL, c->oobinfo);
-+ ret = -EIO;
-+ } else
-+#endif
-+ ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
-+
-+
-+ if (ret || retlen != c->wbuf_pagesize) {
-+ if (ret)
-+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
-+ else {
-+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
-+ retlen, c->wbuf_pagesize);
-+ ret = -EIO;
-+ }
-+
-+ jffs2_wbuf_recover(c);
-+
-+ return ret;
-+ }
-+
-+ /* Adjusting free size of next block only, if it's called from fsync ! */
-+ if (pad == 2) {
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n"));
-+ spin_lock(&c->erase_completion_lock);
-+ if (!c->nextblock)
-+ BUG();
-+ /* wbuf_pagesize - wbuf_len is the amount of space that's to be
-+ padded. If there is less free space in the block than that,
-+ something screwed up */
-+ if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
-+ printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
-+ c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
-+ printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
-+ c->nextblock->offset, c->nextblock->free_size);
-+ BUG();
-+ }
-+ c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len);
-+ c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
-+ c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-+ c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-+ spin_unlock(&c->erase_completion_lock);
-+ }
-+
-+ /* Stick any now-obsoleted blocks on the erase_pending_list */
-+ spin_lock(&c->erase_completion_lock);
-+ jffs2_refile_wbuf_blocks(c);
-+ jffs2_clear_wbuf_ino_list(c);
-+ spin_unlock(&c->erase_completion_lock);
-+
-+ memset(c->wbuf,0xff,c->wbuf_pagesize);
-+ /* adjust write buffer offset, else we get a non contiguous write bug */
-+ c->wbuf_ofs += c->wbuf_pagesize;
-+ c->wbuf_len = 0;
-+ return 0;
-+}
-+
-+/* Trigger garbage collection to flush the write-buffer.
-+ If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
-+ outstanding. If ino arg non-zero, do it only if a write for the
-+ given inode is outstanding. */
-+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
-+{
-+ uint32_t old_wbuf_ofs;
-+ uint32_t old_wbuf_len;
-+ int ret = 0;
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
-+
-+ down(&c->alloc_sem);
-+ if (!jffs2_wbuf_pending_for_ino(c, ino)) {
-+ D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
-+ up(&c->alloc_sem);
-+ return 0;
-+ }
-+
-+ old_wbuf_ofs = c->wbuf_ofs;
-+ old_wbuf_len = c->wbuf_len;
-+
-+ if (c->unchecked_size) {
-+ /* GC won't make any progress for a while */
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
-+ ret = __jffs2_flush_wbuf(c, 2);
-+ } else while (old_wbuf_len &&
-+ old_wbuf_ofs == c->wbuf_ofs) {
-+
-+ up(&c->alloc_sem);
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
-+
-+ ret = jffs2_garbage_collect_pass(c);
-+ if (ret) {
-+ /* GC failed. Flush it with padding instead */
-+ down(&c->alloc_sem);
-+ ret = __jffs2_flush_wbuf(c, 2);
-+ break;
-+ }
-+ down(&c->alloc_sem);
-+ }
-+
-+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
-+
-+ up(&c->alloc_sem);
-+ return ret;
-+}
-+
-+/* Pad write-buffer to end and write it, wasting space. */
-+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
-+{
-+ return __jffs2_flush_wbuf(c, 1);
-+}
-+
-+
-+#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
-+#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
-+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
-+{
-+ struct iovec outvecs[3];
-+ uint32_t totlen = 0;
-+ uint32_t split_ofs = 0;
-+ uint32_t old_totlen;
-+ int ret, splitvec = -1;
-+ int invec, outvec;
-+ size_t wbuf_retlen;
-+ unsigned char *wbuf_ptr;
-+ size_t donelen = 0;
-+ uint32_t outvec_to = to;
-+
-+ /* If not NAND flash, don't bother */
-+ if (!c->wbuf)
-+ return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
-+
-+ /* If wbuf_ofs is not initialized, set it to target address */
-+ if (c->wbuf_ofs == 0xFFFFFFFF) {
-+ c->wbuf_ofs = PAGE_DIV(to);
-+ c->wbuf_len = PAGE_MOD(to);
-+ memset(c->wbuf,0xff,c->wbuf_pagesize);
-+ }
-+
-+ /* Sanity checks on target address.
-+ It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs),
-+ and it's permitted to write at the beginning of a new
-+ erase block. Anything else, and you die.
-+ New block starts at xxx000c (0-b = block header)
-+ */
-+ if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
-+ /* It's a write to a new block */
-+ if (c->wbuf_len) {
-+ D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
-+ ret = jffs2_flush_wbuf_pad(c);
-+ if (ret) {
-+ /* the underlying layer has to check wbuf_len to do the cleanup */
-+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
-+ *retlen = 0;
-+ return ret;
-+ }
-+ }
-+ /* set pointer to new block */
-+ c->wbuf_ofs = PAGE_DIV(to);
-+ c->wbuf_len = PAGE_MOD(to);
-+ }
-+
-+ if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
-+ /* We're not writing immediately after the writebuffer. Bad. */
-+ printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to);
-+ if (c->wbuf_len)
-+ printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
-+ c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
-+ BUG();
-+ }
-+
-+ /* Note outvecs[3] above. We know count is never greater than 2 */
-+ if (count > 2) {
-+ printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count);
-+ BUG();
-+ }
-+
-+ invec = 0;
-+ outvec = 0;
-+
-+
-+ /* Fill writebuffer first, if already in use */
-+ if (c->wbuf_len) {
-+ uint32_t invec_ofs = 0;
-+
-+ /* adjust alignment offset */
-+ if (c->wbuf_len != PAGE_MOD(to)) {
-+ c->wbuf_len = PAGE_MOD(to);
-+ /* take care of alignment to next page */
-+ if (!c->wbuf_len)
-+ c->wbuf_len = c->wbuf_pagesize;
-+ }
-+
-+ while(c->wbuf_len < c->wbuf_pagesize) {
-+ uint32_t thislen;
-+
-+ if (invec == count)
-+ goto alldone;
-+
-+ thislen = c->wbuf_pagesize - c->wbuf_len;
-+
-+ if (thislen >= invecs[invec].iov_len)
-+ thislen = invecs[invec].iov_len;
-+
-+ invec_ofs = thislen;
-+
-+ memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
-+ c->wbuf_len += thislen;
-+ donelen += thislen;
-+ /* Get next invec, if actual did not fill the buffer */
-+ if (c->wbuf_len < c->wbuf_pagesize)
-+ invec++;
-+ }
-+
-+ /* write buffer is full, flush buffer */
-+ ret = __jffs2_flush_wbuf(c, 0);
-+ if (ret) {
-+ /* the underlying layer has to check wbuf_len to do the cleanup */
-+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
-+ /* Retlen zero to make sure our caller doesn't mark the space dirty.
-+ We've already done everything that's necessary */
-+ *retlen = 0;
-+ return ret;
-+ }
-+ outvec_to += donelen;
-+ c->wbuf_ofs = outvec_to;
-+
-+ /* All invecs done ? */
-+ if (invec == count)
-+ goto alldone;
-+
-+ /* Set up the first outvec, containing the remainder of the
-+ invec we partially used */
-+ if (invecs[invec].iov_len > invec_ofs) {
-+ outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;
-+ totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;
-+ if (totlen > c->wbuf_pagesize) {
-+ splitvec = outvec;
-+ split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);
-+ }
-+ outvec++;
-+ }
-+ invec++;
-+ }
-+
-+ /* OK, now we've flushed the wbuf and the start of the bits
-+ we have been asked to write, now to write the rest.... */
-+
-+ /* totlen holds the amount of data still to be written */
-+ old_totlen = totlen;
-+ for ( ; invec < count; invec++,outvec++ ) {
-+ outvecs[outvec].iov_base = invecs[invec].iov_base;
-+ totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;
-+ if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {
-+ splitvec = outvec;
-+ split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);
-+ old_totlen = totlen;
-+ }
-+ }
-+
-+ /* Now the outvecs array holds all the remaining data to write */
-+ /* Up to splitvec,split_ofs is to be written immediately. The rest
-+ goes into the (now-empty) wbuf */
-+
-+ if (splitvec != -1) {
-+ uint32_t remainder;
-+ int ret;
-+
-+ remainder = outvecs[splitvec].iov_len - split_ofs;
-+ outvecs[splitvec].iov_len = split_ofs;
-+
-+ /* We did cross a page boundary, so we write some now */
-+ ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
-+ if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
-+ /* At this point we have no problem,
-+ c->wbuf is empty.
-+ */
-+ *retlen = donelen;
-+ return ret;
-+ }
-+
-+ donelen += wbuf_retlen;
-+ c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
-+
-+ if (remainder) {
-+ outvecs[splitvec].iov_base += split_ofs;
-+ outvecs[splitvec].iov_len = remainder;
-+ } else {
-+ splitvec++;
-+ }
-+
-+ } else {
-+ splitvec = 0;
-+ }
-+
-+ /* Now splitvec points to the start of the bits we have to copy
-+ into the wbuf */
-+ wbuf_ptr = c->wbuf;
-+
-+ for ( ; splitvec < outvec; splitvec++) {
-+ /* Don't copy the wbuf into itself */
-+ if (outvecs[splitvec].iov_base == c->wbuf)
-+ continue;
-+ memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len);
-+ wbuf_ptr += outvecs[splitvec].iov_len;
-+ donelen += outvecs[splitvec].iov_len;
-+ }
-+ c->wbuf_len = wbuf_ptr - c->wbuf;
-+
-+ /* If there's a remainder in the wbuf and it's a non-GC write,
-+ remember that the wbuf affects this ino */
-+alldone:
-+ *retlen = donelen;
-+
-+ if (c->wbuf_len && ino)
-+ jffs2_wbuf_dirties_inode(c, ino);
-+
-+ return 0;
-+}
-+
-+/*
-+ * This is the entry for flash write.
-+ * Check, if we work on NAND FLASH, if so build an iovec and write it via vritev
-+*/
-+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
-+{
-+ struct iovec vecs[1];
-+
-+ if (jffs2_can_mark_obsolete(c))
-+ return c->mtd->write(c->mtd, ofs, len, retlen, buf);
-+
-+ vecs[0].iov_base = (unsigned char *) buf;
-+ vecs[0].iov_len = len;
-+ return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
-+}
-+
-+/*
-+ Handle readback from writebuffer and ECC failure return
-+*/
-+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
-+{
-+ loff_t orbf = 0, owbf = 0, lwbf = 0;
-+ int ret;
-+
-+ /* Read flash */
-+ if (!jffs2_can_mark_obsolete(c)) {
-+ ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
-+
-+ if ( (ret == -EIO) && (*retlen == len) ) {
-+ printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
-+ len, ofs);
-+ /*
-+ * We have the raw data without ECC correction in the buffer, maybe
-+ * we are lucky and all data or parts are correct. We check the node.
-+ * If data are corrupted node check will sort it out.
-+ * We keep this block, it will fail on write or erase and the we
-+ * mark it bad. Or should we do that now? But we should give him a chance.
-+ * Maybe we had a system crash or power loss before the ecc write or
-+ * a erase was completed.
-+ * So we return success. :)
-+ */
-+ ret = 0;
-+ }
-+ } else
-+ return c->mtd->read(c->mtd, ofs, len, retlen, buf);
-+
-+ /* if no writebuffer available or write buffer empty, return */
-+ if (!c->wbuf_pagesize || !c->wbuf_len)
-+ return ret;
-+
-+ /* if we read in a different block, return */
-+ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
-+ return ret;
-+
-+ if (ofs >= c->wbuf_ofs) {
-+ owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
-+ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */
-+ return ret;
-+ lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
-+ if (lwbf > len)
-+ lwbf = len;
-+ } else {
-+ orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
-+ if (orbf > len) /* is write beyond write buffer ? */
-+ return ret;
-+ lwbf = len - orbf; /* number of bytes to copy */
-+ if (lwbf > c->wbuf_len)
-+ lwbf = c->wbuf_len;
-+ }
-+ if (lwbf > 0)
-+ memcpy(buf+orbf,c->wbuf+owbf,lwbf);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Check, if the out of band area is empty
-+ */
-+int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode)
-+{
-+ unsigned char *buf;
-+ int ret = 0;
-+ int i,len,page;
-+ size_t retlen;
-+ int oob_size;
-+
-+ oob_size = c->mtd->oobsize;
-+
-+ /* allocate a buffer for all oob data in this sector */
-+ len = 4 * oob_size;
-+ buf = kmalloc(len, GFP_KERNEL);
-+ if (!buf) {
-+ printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
-+ return -ENOMEM;
-+ }
-+ /*
-+ * if mode = 0, we scan for a total empty oob area, else we have
-+ * to take care of the cleanmarker in the first page of the block
-+ */
-+ ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf);
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-+ goto out;
-+ }
-+
-+ if (retlen < len) {
-+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
-+ "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ /* Special check for first two pages */
-+ for (page = 0; page < 2 * oob_size; page += oob_size) {
-+ /* Check for bad block marker */
-+ if (buf[page+c->badblock_pos] != 0xff) {
-+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
-+ /* Return 2 for bad and 3 for failed block
-+ bad goes to list_bad and failed to list_erase */
-+ ret = (!page) ? 2 : 3;
-+ goto out;
-+ }
-+ for(i = 0; i < oob_size ; i++) {
-+ /* Yeah, we know about the cleanmarker. */
-+ if (mode && i >= c->fsdata_pos &&
-+ i < c->fsdata_pos+c->fsdata_len)
-+ continue;
-+
-+ if (buf[page+i] != 0xFF) {
-+ D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-+ buf[page+i], page+i, jeb->offset));
-+ ret = 1;
-+ goto out;
-+ }
-+ }
-+ /* only the first page can contain a cleanmarker !*/
-+ mode = 0;
-+ }
-+
-+ /* we know, we are aligned :) */
-+ for (; page < len; page += sizeof(long)) {
-+ unsigned long dat = *(unsigned long *)(&buf[page]);
-+ if(dat != -1) {
-+ ret = 1;
-+ goto out;
-+ }
-+ }
-+
-+out:
-+ kfree(buf);
-+
-+ return ret;
-+}
-+
-+/*
-+* Scan for a valid cleanmarker and for bad blocks
-+* For virtual blocks (concatenated physical blocks) check the cleanmarker
-+* only in the first page of the first physical block, but scan for bad blocks in all
-+* physical blocks
-+*/
-+int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_unknown_node n;
-+ unsigned char buf[32];
-+ unsigned char *p;
-+ int ret, i, cnt, retval = 0;
-+ size_t retlen, offset;
-+ int oob_size;
-+
-+ offset = jeb->offset;
-+ oob_size = c->mtd->oobsize;
-+
-+ /* Loop through the physical blocks */
-+ for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
-+ /*
-+ * We read oob data from page 0 and 1 of the block.
-+ * page 0 contains cleanmarker and badblock info
-+ * page 1 contains failure count of this block
-+ */
-+ ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf);
-+
-+ if (ret) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-+ return ret;
-+ }
-+ if (retlen < (oob_size << 1)) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset));
-+ return -EIO;
-+ }
-+
-+ /* Check for bad block marker */
-+ if (buf[c->badblock_pos] != 0xff) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n",
-+ jeb->offset, buf[c->badblock_pos], buf[c->badblock_pos + oob_size], c->badblock_pos));
-+ return 2;
-+ }
-+
-+ /* Check for failure counter in the second page */
-+ if (buf[c->badblock_pos + oob_size] != 0xff) {
-+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size]));
-+ return 3;
-+ }
-+
-+ /* Check cleanmarker only on the first physical block */
-+ if (!cnt) {
-+ n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
-+ n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
-+ n.totlen = cpu_to_je32 (8);
-+ p = (unsigned char *) &n;
-+
-+ for (i = 0; i < c->fsdata_len; i++) {
-+ if (buf[c->fsdata_pos + i] != p[i]) {
-+ retval = 1;
-+ }
-+ }
-+ D1(if (retval == 1) {
-+ printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
-+ printk(KERN_WARNING "OOB at %08x was ", offset);
-+ for (i=0; i < oob_size; i++) {
-+ printk("%02x ", buf[i]);
-+ }
-+ printk("\n");
-+ })
-+ }
-+ offset += c->mtd->erasesize;
-+ }
-+ return retval;
-+}
-+
-+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ struct jffs2_unknown_node n;
-+ int ret;
-+ size_t retlen;
-+
-+ n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-+ n.totlen = cpu_to_je32(8);
-+
-+ ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
-+
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
-+ return ret;
-+ }
-+ if (retlen != c->fsdata_len) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len));
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * We try to get the failure count of this block.
-+ */
-+int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-+
-+ unsigned char buf[16];
-+ int ret;
-+ size_t retlen;
-+ int oob_size;
-+
-+ oob_size = c->mtd->oobsize;
-+
-+ ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf);
-+
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-+ return ret;
-+ }
-+
-+ if (retlen < oob_size) {
-+ D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset));
-+ return -EIO;
-+ }
-+
-+ jeb->bad_count = buf[c->badblock_pos];
-+ return 0;
-+}
-+
-+/*
-+ * On NAND we try to mark this block bad. We try to write how often
-+ * the block was erased and mark it finaly bad, if the count
-+ * is > MAX_ERASE_FAILURES. We read this information on mount !
-+ * jeb->bad_count contains the count before this erase.
-+ * Don't care about failures. This block remains on the erase-pending
-+ * or badblock list as long as nobody manipulates the flash with
-+ * a bootloader or something like that.
-+ */
-+
-+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
-+{
-+ unsigned char buf = 0x0;
-+ int ret;
-+ size_t retlen;
-+
-+ /* if the count is < max, we try to write the counter to the 2nd page oob area */
-+ if( ++jeb->bad_count < MAX_ERASE_FAILURES) {
-+ buf = (unsigned char)jeb->bad_count;
-+ c->badblock_pos += c->mtd->oobblock;
-+ }
-+
-+ ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf);
-+
-+ if (ret) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
-+ return ret;
-+ }
-+ if (retlen != 1) {
-+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen));
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+#define JFFS2_OOB_ECCPOS0 0
-+#define JFFS2_OOB_ECCPOS1 1
-+#define JFFS2_OOB_ECCPOS2 2
-+#define JFFS2_OOB_ECCPOS3 3
-+#define JFFS2_OOB_ECCPOS4 6
-+#define JFFS2_OOB_ECCPOS5 7
-+
-+#define NAND_JFFS2_OOB8_FSDAPOS 6
-+#define NAND_JFFS2_OOB16_FSDAPOS 8
-+#define NAND_JFFS2_OOB8_FSDALEN 2
-+#define NAND_JFFS2_OOB16_FSDALEN 8
-+
-+static struct nand_oobinfo jffs2_oobinfo_swecc = {
-+ .useecc = 1,
-+ .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2,
-+ JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
-+};
-+
-+static struct nand_oobinfo jffs2_oobinfo_docecc = {
-+ .useecc = 1,
-+ .eccpos = {0,1,2,3,4,5}
-+};
-+
-+
-+
-+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
-+{
-+ /* Cleanmarker is out-of-band, so inline size zero */
-+ c->cleanmarker_size = 0;
-+
-+ /* Initialise write buffer */
-+ c->wbuf_pagesize = c->mtd->oobblock;
-+ c->wbuf_ofs = 0xFFFFFFFF;
-+
-+ /* FIXME: If we had a generic way of describing the hardware's
-+ use of OOB area, we could perhaps make this generic too. */
-+ switch(c->mtd->ecctype) {
-+ case MTD_ECC_SW:
-+ D1(printk(KERN_DEBUG "JFFS2 using software ECC\n"));
-+ c->oobinfo = &jffs2_oobinfo_swecc;
-+ if (c->mtd->oobsize == 8) {
-+ c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS;
-+ c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN;
-+ } else {
-+ c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS;
-+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
-+ }
-+ c->badblock_pos = NAND_BADBLOCK_POS;
-+ break;
-+
-+ case MTD_ECC_RS_DiskOnChip:
-+ D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n"));
-+ c->oobinfo = &jffs2_oobinfo_docecc;
-+ c->fsdata_pos = 6;
-+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
-+ c->badblock_pos = 15;
-+ break;
-+
-+ default:
-+ printk("JFFS2 doesn't yet know how to handle ECC type %d\n",
-+ c->mtd->ecctype);
-+ return -EINVAL;
-+ }
-+
-+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!c->wbuf)
-+ return -ENOMEM;
-+
-+#ifdef BREAKME
-+ if (!brokenbuf)
-+ brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-+ if (!brokenbuf) {
-+ kfree(c->wbuf);
-+ return -ENOMEM;
-+ }
-+ memset(brokenbuf, 0xdb, c->wbuf_pagesize);
-+#endif
-+ return 0;
-+}
-+
-+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
-+{
-+ kfree(c->wbuf);
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/write.c linux/fs/jffs2/write.c
---- linux-mips-2.4.27/fs/jffs2/write.c 2003-11-17 02:07:44.000000000 +0100
-+++ linux/fs/jffs2/write.c 2004-11-19 10:25:12.132164376 +0100
-@@ -1,154 +1,70 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in this directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/fs.h>
--#include <linux/jffs2.h>
-+#include <linux/crc32.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
- #include <linux/mtd/mtd.h>
- #include "nodelist.h"
--#include <linux/crc32.h>
-
--/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
-- fill in the raw_inode while you're at it. */
--struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
-+
-+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
- {
-- struct inode *inode;
-- struct super_block *sb = dir_i->i_sb;
- struct jffs2_inode_cache *ic;
-- struct jffs2_sb_info *c;
-- struct jffs2_inode_info *f;
--
-- D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
--
-- c = JFFS2_SB_INFO(sb);
-- memset(ri, 0, sizeof(*ri));
-
- ic = jffs2_alloc_inode_cache();
- if (!ic) {
-- return ERR_PTR(-ENOMEM);
-+ return -ENOMEM;
- }
-- memset(ic, 0, sizeof(*ic));
--
-- inode = new_inode(sb);
-
-- if (!inode) {
-- jffs2_free_inode_cache(ic);
-- return ERR_PTR(-ENOMEM);
-- }
--
-- /* Alloc jffs2_inode_info when that's split in 2.5 */
-+ memset(ic, 0, sizeof(*ic));
-
-- f = JFFS2_INODE_INFO(inode);
-- memset(f, 0, sizeof(*f));
- init_MUTEX_LOCKED(&f->sem);
- f->inocache = ic;
-- inode->i_nlink = f->inocache->nlink = 1;
-+ f->inocache->nlink = 1;
- f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-- f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino;
-- D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino));
-- jffs2_add_ino_cache(c, f->inocache);
-+ f->inocache->ino = ++c->highest_ino;
-+ f->inocache->state = INO_STATE_PRESENT;
-
-- ri->magic = JFFS2_MAGIC_BITMASK;
-- ri->nodetype = JFFS2_NODETYPE_INODE;
-- ri->totlen = PAD(sizeof(*ri));
-- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
-- ri->mode = mode;
-- f->highest_version = ri->version = 1;
-- ri->uid = current->fsuid;
-- if (dir_i->i_mode & S_ISGID) {
-- ri->gid = dir_i->i_gid;
-- if (S_ISDIR(mode))
-- ri->mode |= S_ISGID;
-- } else {
-- ri->gid = current->fsgid;
-- }
-- inode->i_mode = ri->mode;
-- inode->i_gid = ri->gid;
-- inode->i_uid = ri->uid;
-- inode->i_atime = inode->i_ctime = inode->i_mtime =
-- ri->atime = ri->mtime = ri->ctime = CURRENT_TIME;
-- inode->i_blksize = PAGE_SIZE;
-- inode->i_blocks = 0;
-- inode->i_size = 0;
-+ ri->ino = cpu_to_je32(f->inocache->ino);
-
-- insert_inode_hash(inode);
-+ D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
-+ jffs2_add_ino_cache(c, f->inocache);
-
-- return inode;
--}
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+ ri->mode = cpu_to_jemode(mode);
-
--/* This ought to be in core MTD code. All registered MTD devices
-- without writev should have this put in place. Bug the MTD
-- maintainer */
--static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
--{
-- unsigned long i;
-- size_t totlen = 0, thislen;
-- int ret = 0;
-+ f->highest_version = 1;
-+ ri->version = cpu_to_je32(f->highest_version);
-
-- for (i=0; i<count; i++) {
-- ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
-- totlen += thislen;
-- if (ret || thislen != vecs[i].iov_len)
-- break;
-- to += vecs[i].iov_len;
-- }
-- if (retlen)
-- *retlen = totlen;
-- return ret;
--}
--
--
--static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
--{
-- if (mtd->writev)
-- return mtd->writev(mtd,vecs,count,to,retlen);
-- else
-- return mtd_fake_writev(mtd, vecs, count, to, retlen);
-+ return 0;
- }
-
--static void writecheck(struct mtd_info *mtd, __u32 ofs)
-+#if CONFIG_JFFS2_FS_DEBUG > 0
-+static void writecheck(struct jffs2_sb_info *c, uint32_t ofs)
- {
- unsigned char buf[16];
-- ssize_t retlen;
-+ size_t retlen;
- int ret, i;
-
-- ret = mtd->read(mtd, ofs, 16, &retlen, buf);
-- if (ret && retlen != 16) {
-- D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen));
-+ ret = jffs2_flash_read(c, ofs, 16, &retlen, buf);
-+ if (ret || (retlen != 16)) {
-+ D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen));
- return;
- }
- ret = 0;
-@@ -157,32 +73,31 @@
- ret = 1;
- }
- if (ret) {
-- printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs);
-+ printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs);
- printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ofs,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
- buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
- }
- }
--
--
-+#endif
-
-
- /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
- write it to the flash, link it into the existing inode/fragment list */
-
--struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen)
-+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode)
-
- {
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dnode *fn;
-- ssize_t retlen;
-+ size_t retlen;
- struct iovec vecs[2];
- int ret;
-+ int retried = 0;
-+ unsigned long cnt = 2;
-
-- D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
-+ D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
- printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
- BUG();
- }
-@@ -192,10 +107,10 @@
- vecs[1].iov_base = (unsigned char *)data;
- vecs[1].iov_len = datalen;
-
-- writecheck(c->mtd, flash_ofs);
-+ D1(writecheck(c, flash_ofs));
-
-- if (ri->totlen != sizeof(*ri) + datalen) {
-- printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen);
-+ if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
-+ printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
- }
- raw = jffs2_alloc_raw_node_ref();
- if (!raw)
-@@ -206,19 +121,28 @@
- jffs2_free_raw_node_ref(raw);
- return ERR_PTR(-ENOMEM);
- }
-- raw->flash_offset = flash_ofs;
-- raw->totlen = PAD(ri->totlen);
-- raw->next_phys = NULL;
-
-- fn->ofs = ri->offset;
-- fn->size = ri->dsize;
-+ fn->ofs = je32_to_cpu(ri->offset);
-+ fn->size = je32_to_cpu(ri->dsize);
- fn->frags = 0;
-+
-+ /* check number of valid vecs */
-+ if (!datalen || !data)
-+ cnt = 1;
-+ retry:
- fn->raw = raw;
-
-- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
-+ raw->flash_offset = flash_ofs;
-+ raw->__totlen = PAD(sizeof(*ri)+datalen);
-+ raw->next_phys = NULL;
-+
-+ ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
-+ (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
-+
- if (ret || (retlen != sizeof(*ri) + datalen)) {
-- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
-+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
- sizeof(*ri)+datalen, flash_ofs, ret, retlen);
-+
- /* Mark the space as dirtied */
- if (retlen) {
- /* Doesn't belong to any inode */
-@@ -229,48 +153,96 @@
- seem corrupted, in which case the scan would skip over
- any node we write before the original intended end of
- this node */
-- jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1);
-+ raw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, raw);
- jffs2_mark_node_obsolete(c, raw);
- } else {
- printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
- jffs2_free_raw_node_ref(raw);
- }
-+ if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
-+
-+ retried = 1;
-+
-+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ if (alloc_mode == ALLOC_GC) {
-+ ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
-+ } else {
-+ /* Locking pain */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
-+ down(&f->sem);
-+ }
-+
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(raw);
-+ }
- /* Release the full_dnode which is now useless, and return */
- jffs2_free_full_dnode(fn);
-- if (writelen)
-- *writelen = retlen;
- return ERR_PTR(ret?ret:-EIO);
- }
- /* Mark the space used */
-- jffs2_add_physical_node_ref(c, raw, retlen, 0);
-+ /* If node covers at least a whole page, or if it starts at the
-+ beginning of a page and runs to the end of the file, or if
-+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
-+ */
-+ if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
-+ ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
-+ (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) {
-+ raw->flash_offset |= REF_PRISTINE;
-+ } else {
-+ raw->flash_offset |= REF_NORMAL;
-+ }
-+ jffs2_add_physical_node_ref(c, raw);
-
- /* Link into per-inode list */
- raw->next_in_ino = f->inocache->nodes;
- f->inocache->nodes = raw;
-
-- D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen));
-- if (writelen)
-- *writelen = retlen;
-+ D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
-+ flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize),
-+ je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
-+ je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
-+
-+ if (retried) {
-+ ACCT_SANITY_CHECK(c,NULL);
-+ }
-
-- f->inocache->nodes = raw;
- return fn;
- }
-
--struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen)
-+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode)
- {
-- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_raw_node_ref *raw;
- struct jffs2_full_dirent *fd;
-- ssize_t retlen;
-+ size_t retlen;
- struct iovec vecs[2];
-+ int retried = 0;
- int ret;
-
-- D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc));
-- writecheck(c->mtd, flash_ofs);
-+ D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
-+ je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
-+ je32_to_cpu(rd->name_crc)));
-+ D1(writecheck(c, flash_ofs));
-
-- D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
-+ D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
- printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
- BUG();
- }
-@@ -291,44 +263,414 @@
- jffs2_free_raw_node_ref(raw);
- return ERR_PTR(-ENOMEM);
- }
-- raw->flash_offset = flash_ofs;
-- raw->totlen = PAD(rd->totlen);
-- raw->next_in_ino = f->inocache->nodes;
-- f->inocache->nodes = raw;
-- raw->next_phys = NULL;
-
-- fd->version = rd->version;
-- fd->ino = rd->ino;
-+ fd->version = je32_to_cpu(rd->version);
-+ fd->ino = je32_to_cpu(rd->ino);
- fd->nhash = full_name_hash(name, strlen(name));
- fd->type = rd->type;
- memcpy(fd->name, name, namelen);
- fd->name[namelen]=0;
-+
-+ retry:
- fd->raw = raw;
-
-- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
-+ raw->flash_offset = flash_ofs;
-+ raw->__totlen = PAD(sizeof(*rd)+namelen);
-+ raw->next_phys = NULL;
-+
-+ ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
-+ (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
- if (ret || (retlen != sizeof(*rd) + namelen)) {
-- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
-+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
- sizeof(*rd)+namelen, flash_ofs, ret, retlen);
- /* Mark the space as dirtied */
- if (retlen) {
-- jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1);
-+ raw->next_in_ino = NULL;
-+ raw->flash_offset |= REF_OBSOLETE;
-+ jffs2_add_physical_node_ref(c, raw);
- jffs2_mark_node_obsolete(c, raw);
- } else {
- printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
- jffs2_free_raw_node_ref(raw);
- }
-+ if (!retried && (raw = jffs2_alloc_raw_node_ref())) {
-+ /* Try to reallocate space and retry */
-+ uint32_t dummy;
-+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
-+
-+ retried = 1;
-+
-+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
-+
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+
-+ if (alloc_mode == ALLOC_GC) {
-+ ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
-+ } else {
-+ /* Locking pain */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
-+ down(&f->sem);
-+ }
-
-+ if (!ret) {
-+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
-+ ACCT_SANITY_CHECK(c,jeb);
-+ D1(ACCT_PARANOIA_CHECK(jeb));
-+ goto retry;
-+ }
-+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
-+ jffs2_free_raw_node_ref(raw);
-+ }
- /* Release the full_dnode which is now useless, and return */
- jffs2_free_full_dirent(fd);
-- if (writelen)
-- *writelen = retlen;
- return ERR_PTR(ret?ret:-EIO);
- }
- /* Mark the space used */
-- jffs2_add_physical_node_ref(c, raw, retlen, 0);
-- if (writelen)
-- *writelen = retlen;
-+ raw->flash_offset |= REF_PRISTINE;
-+ jffs2_add_physical_node_ref(c, raw);
-
-+ raw->next_in_ino = f->inocache->nodes;
- f->inocache->nodes = raw;
-+
-+ if (retried) {
-+ ACCT_SANITY_CHECK(c,NULL);
-+ }
-+
- return fd;
- }
-+
-+/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that
-+ we don't have to go digging in struct inode or its equivalent. It should set:
-+ mode, uid, gid, (starting)isize, atime, ctime, mtime */
-+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-+ struct jffs2_raw_inode *ri, unsigned char *buf,
-+ uint32_t offset, uint32_t writelen, uint32_t *retlen)
-+{
-+ int ret = 0;
-+ uint32_t writtenlen = 0;
-+
-+ D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
-+ f->inocache->ino, offset, writelen));
-+
-+ while(writelen) {
-+ struct jffs2_full_dnode *fn;
-+ unsigned char *comprbuf = NULL;
-+ unsigned char comprtype = JFFS2_COMPR_NONE;
-+ uint32_t phys_ofs, alloclen;
-+ uint32_t datalen, cdatalen;
-+ int retried = 0;
-+
-+ retry:
-+ D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
-+
-+ ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
-+ break;
-+ }
-+ down(&f->sem);
-+ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
-+ cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
-+
-+ comprtype = jffs2_compress(buf, &comprbuf, &datalen, &cdatalen);
-+
-+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-+ ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
-+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-+
-+ ri->ino = cpu_to_je32(f->inocache->ino);
-+ ri->version = cpu_to_je32(++f->highest_version);
-+ ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
-+ ri->offset = cpu_to_je32(offset);
-+ ri->csize = cpu_to_je32(cdatalen);
-+ ri->dsize = cpu_to_je32(datalen);
-+ ri->compr = comprtype;
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+ ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
-+
-+ fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
-+
-+ jffs2_free_comprbuf(comprbuf, buf);
-+
-+ if (IS_ERR(fn)) {
-+ ret = PTR_ERR(fn);
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ if (!retried) {
-+ /* Write error to be retried */
-+ retried = 1;
-+ D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
-+ goto retry;
-+ }
-+ break;
-+ }
-+ ret = jffs2_add_full_dnode_to_inode(c, f, fn);
-+ if (f->metadata) {
-+ jffs2_mark_node_obsolete(c, f->metadata->raw);
-+ jffs2_free_full_dnode(f->metadata);
-+ f->metadata = NULL;
-+ }
-+ if (ret) {
-+ /* Eep */
-+ D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
-+ jffs2_mark_node_obsolete(c, fn->raw);
-+ jffs2_free_full_dnode(fn);
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ break;
-+ }
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ if (!datalen) {
-+ printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
-+ ret = -EIO;
-+ break;
-+ }
-+ D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
-+ writtenlen += datalen;
-+ offset += datalen;
-+ writelen -= datalen;
-+ buf += datalen;
-+ }
-+ *retlen = writtenlen;
-+ return ret;
-+}
-+
-+int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dnode *fn;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ /* Try to reserve enough space for both node and dirent.
-+ * Just the node will do for now, though
-+ */
-+ ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
-+ if (ret) {
-+ up(&f->sem);
-+ return ret;
-+ }
-+
-+ ri->data_crc = cpu_to_je32(0);
-+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-+
-+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
-+
-+ D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
-+ jemode_to_cpu(ri->mode)));
-+
-+ if (IS_ERR(fn)) {
-+ D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
-+ /* Eeek. Wave bye bye */
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ return PTR_ERR(fn);
-+ }
-+ /* No data here. Only a metadata node, which will be
-+ obsoleted by the first data write
-+ */
-+ f->metadata = fn;
-+
-+ up(&f->sem);
-+ jffs2_complete_reservation(c);
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+
-+ if (ret) {
-+ /* Eep. */
-+ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
-+ return ret;
-+ }
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd) {
-+ /* Argh. Now we treat it like a normal delete */
-+ jffs2_complete_reservation(c);
-+ return -ENOMEM;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = ri->ino;
-+ rd->mctime = ri->ctime;
-+ rd->nsize = namelen;
-+ rd->type = DT_REG;
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ /* dirent failed to write. Delete the inode normally
-+ as if it were the final unlink() */
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* Link the fd into the inode's list, obsoleting an old
-+ one if necessary. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+
-+ return 0;
-+}
-+
-+
-+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
-+ const char *name, int namelen, struct jffs2_inode_info *dead_f)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
-+ if (ret) {
-+ jffs2_free_raw_dirent(rd);
-+ return ret;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ /* Build a deletion node */
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(0);
-+ rd->mctime = cpu_to_je32(get_seconds());
-+ rd->nsize = namelen;
-+ rd->type = DT_UNKNOWN;
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* File it. This will mark the old one obsolete. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
-+ up(&dir_f->sem);
-+
-+ /* dead_f is NULL if this was a rename not a real unlink */
-+ /* Also catch the !f->inocache case, where there was a dirent
-+ pointing to an inode which didn't exist. */
-+ if (dead_f && dead_f->inocache) {
-+
-+ down(&dead_f->sem);
-+
-+ while (dead_f->dents) {
-+ /* There can be only deleted ones */
-+ fd = dead_f->dents;
-+
-+ dead_f->dents = fd->next;
-+
-+ if (fd->ino) {
-+ printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-+ dead_f->inocache->ino, fd->name, fd->ino);
-+ } else {
-+ D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino));
-+ }
-+ jffs2_mark_node_obsolete(c, fd->raw);
-+ jffs2_free_full_dirent(fd);
-+ }
-+
-+ dead_f->inocache->nlink--;
-+ /* NB: Caller must set inode nlink if appropriate */
-+ up(&dead_f->sem);
-+ }
-+
-+ jffs2_complete_reservation(c);
-+
-+ return 0;
-+}
-+
-+
-+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen)
-+{
-+ struct jffs2_raw_dirent *rd;
-+ struct jffs2_full_dirent *fd;
-+ uint32_t alloclen, phys_ofs;
-+ int ret;
-+
-+ rd = jffs2_alloc_raw_dirent();
-+ if (!rd)
-+ return -ENOMEM;
-+
-+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-+ if (ret) {
-+ jffs2_free_raw_dirent(rd);
-+ return ret;
-+ }
-+
-+ down(&dir_f->sem);
-+
-+ /* Build a deletion node */
-+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-+
-+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
-+ rd->version = cpu_to_je32(++dir_f->highest_version);
-+ rd->ino = cpu_to_je32(ino);
-+ rd->mctime = cpu_to_je32(get_seconds());
-+ rd->nsize = namelen;
-+
-+ rd->type = type;
-+
-+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-+
-+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
-+
-+ jffs2_free_raw_dirent(rd);
-+
-+ if (IS_ERR(fd)) {
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+ return PTR_ERR(fd);
-+ }
-+
-+ /* File it. This will mark the old one obsolete. */
-+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-+
-+ jffs2_complete_reservation(c);
-+ up(&dir_f->sem);
-+
-+ return 0;
-+}
-diff -Nurb linux-mips-2.4.27/fs/jffs2/writev.c linux/fs/jffs2/writev.c
---- linux-mips-2.4.27/fs/jffs2/writev.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/jffs2/writev.c 2004-11-19 10:25:12.134164072 +0100
-@@ -0,0 +1,50 @@
-+/*
-+ * JFFS2 -- Journalling Flash File System, Version 2.
-+ *
-+ * Copyright (C) 2001, 2002 Red Hat, Inc.
-+ *
-+ * Created by David Woodhouse <dwmw2@redhat.com>
-+ *
-+ * For licensing information, see the file 'LICENCE' in this directory.
-+ *
-+ * $Id$
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/mtd/mtd.h>
-+#include "nodelist.h"
-+
-+/* This ought to be in core MTD code. All registered MTD devices
-+ without writev should have this put in place. Bug the MTD
-+ maintainer */
-+static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen)
-+{
-+ unsigned long i;
-+ size_t totlen = 0, thislen;
-+ int ret = 0;
-+
-+ for (i=0; i<count; i++) {
-+ if (!vecs[i].iov_len)
-+ continue;
-+ ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
-+ totlen += thislen;
-+ if (ret || thislen != vecs[i].iov_len)
-+ break;
-+ to += vecs[i].iov_len;
-+ }
-+ if (retlen)
-+ *retlen = totlen;
-+ return ret;
-+}
-+
-+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
-+ unsigned long count, loff_t to, size_t *retlen)
-+{
-+ if (c->mtd->writev)
-+ return c->mtd->writev(c->mtd, vecs, count, to, retlen);
-+ else
-+ return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
-+}
-+
-diff -Nurb linux-mips-2.4.27/include/linux/jffs2.h linux/include/linux/jffs2.h
---- linux-mips-2.4.27/include/linux/jffs2.h 2002-06-27 00:36:46.000000000 +0200
-+++ linux/include/linux/jffs2.h 2004-11-19 10:25:12.139163312 +0100
-@@ -1,50 +1,30 @@
- /*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
-- * Copyright (C) 2001 Red Hat, Inc.
-+ * Copyright (C) 2001-2003 Red Hat, Inc.
- *
-- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
-+ * Created by David Woodhouse <dwmw2@redhat.com>
- *
-- * The original JFFS, from which the design for JFFS2 was derived,
-- * was designed and implemented by Axis Communications AB.
-+ * For licensing information, see the file 'LICENCE' in the
-+ * jffs2 directory.
- *
-- * The contents of this file are subject to the Red Hat eCos Public
-- * License Version 1.1 (the "Licence"); you may not use this file
-- * except in compliance with the Licence. You may obtain a copy of
-- * the Licence at http://www.redhat.com/
-- *
-- * Software distributed under the Licence is distributed on an "AS IS"
-- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
-- * See the Licence for the specific language governing rights and
-- * limitations under the Licence.
-- *
-- * The Original Code is JFFS2 - Journalling Flash File System, version 2
-- *
-- * Alternatively, the contents of this file may be used under the
-- * terms of the GNU General Public License version 2 (the "GPL"), in
-- * which case the provisions of the GPL are applicable instead of the
-- * above. If you wish to allow the use of your version of this file
-- * only under the terms of the GPL and not to allow others to use your
-- * version of this file under the RHEPL, indicate your decision by
-- * deleting the provisions above and replace them with the notice and
-- * other provisions required by the GPL. If you do not delete the
-- * provisions above, a recipient may use your version of this file
-- * under either the RHEPL or the GPL.
-- *
-- * $Id$
-+ * $Id$
- *
- */
-
- #ifndef __LINUX_JFFS2_H__
- #define __LINUX_JFFS2_H__
-
--#include <asm/types.h>
-+/* You must include something which defines the C99 uintXX_t types.
-+ We don't do it from here because this file is used in too many
-+ different environments. */
-+
- #define JFFS2_SUPER_MAGIC 0x72b6
-
- /* Values we may expect to find in the 'magic' field */
- #define JFFS2_OLD_MAGIC_BITMASK 0x1984
- #define JFFS2_MAGIC_BITMASK 0x1985
--#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */
-+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
- #define JFFS2_EMPTY_BITMASK 0xffff
- #define JFFS2_DIRTY_BITMASK 0x0000
-
-@@ -78,16 +58,12 @@
- #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
- #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
- #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
-+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
-
- // Maybe later...
- //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
- //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
-
--/* Same as the non_ECC versions, but with extra space for real
-- * ECC instead of just the checksum. For use on NAND flash
-- */
--//#define JFFS2_NODETYPE_DIRENT_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5)
--//#define JFFS2_NODETYPE_INODE_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 6)
-
- #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
- mount time, don't wait for it to
-@@ -96,31 +72,79 @@
- compression type */
-
-
-+/* These can go once we've made sure we've caught all uses without
-+ byteswapping */
-+
-+typedef struct {
-+ uint32_t v32;
-+} __attribute__((packed)) jint32_t;
-+
-+typedef struct {
-+ uint32_t m;
-+} __attribute__((packed)) jmode_t;
-+
-+typedef struct {
-+ uint16_t v16;
-+} __attribute__((packed)) jint16_t;
-+
-+#define JFFS2_NATIVE_ENDIAN
-+
-+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
-+ whatever OS we're actually running on here too. */
-+
-+#if defined(JFFS2_NATIVE_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){x})
-+#define cpu_to_je32(x) ((jint32_t){x})
-+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
-+
-+#define je16_to_cpu(x) ((x).v16)
-+#define je32_to_cpu(x) ((x).v32)
-+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
-+#elif defined(JFFS2_BIG_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
-+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
-+
-+#define je16_to_cpu(x) (be16_to_cpu(x.v16))
-+#define je32_to_cpu(x) (be32_to_cpu(x.v32))
-+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
-+#elif defined(JFFS2_LITTLE_ENDIAN)
-+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
-+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
-+
-+#define je16_to_cpu(x) (le16_to_cpu(x.v16))
-+#define je32_to_cpu(x) (le32_to_cpu(x.v32))
-+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-+#else
-+#error wibble
-+#endif
-+
- struct jffs2_unknown_node
- {
- /* All start like this */
-- __u16 magic;
-- __u16 nodetype;
-- __u32 totlen; /* So we can skip over nodes we don't grok */
-- __u32 hdr_crc;
-+ jint16_t magic;
-+ jint16_t nodetype;
-+ jint32_t totlen; /* So we can skip over nodes we don't grok */
-+ jint32_t hdr_crc;
- } __attribute__((packed));
-
- struct jffs2_raw_dirent
- {
-- __u16 magic;
-- __u16 nodetype; /* == JFFS_NODETYPE_DIRENT */
-- __u32 totlen;
-- __u32 hdr_crc;
-- __u32 pino;
-- __u32 version;
-- __u32 ino; /* == zero for unlink */
-- __u32 mctime;
-- __u8 nsize;
-- __u8 type;
-- __u8 unused[2];
-- __u32 node_crc;
-- __u32 name_crc;
-- __u8 name[0];
-+ jint16_t magic;
-+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
-+ jint32_t totlen;
-+ jint32_t hdr_crc;
-+ jint32_t pino;
-+ jint32_t version;
-+ jint32_t ino; /* == zero for unlink */
-+ jint32_t mctime;
-+ uint8_t nsize;
-+ uint8_t type;
-+ uint8_t unused[2];
-+ jint32_t node_crc;
-+ jint32_t name_crc;
-+ uint8_t name[0];
- } __attribute__((packed));
-
- /* The JFFS2 raw inode structure: Used for storage on physical media. */
-@@ -131,28 +155,28 @@
- */
- struct jffs2_raw_inode
- {
-- __u16 magic; /* A constant magic number. */
-- __u16 nodetype; /* == JFFS_NODETYPE_INODE */
-- __u32 totlen; /* Total length of this node (inc data, etc.) */
-- __u32 hdr_crc;
-- __u32 ino; /* Inode number. */
-- __u32 version; /* Version number. */
-- __u32 mode; /* The file's type or mode. */
-- __u16 uid; /* The file's owner. */
-- __u16 gid; /* The file's group. */
-- __u32 isize; /* Total resultant size of this inode (used for truncations) */
-- __u32 atime; /* Last access time. */
-- __u32 mtime; /* Last modification time. */
-- __u32 ctime; /* Change time. */
-- __u32 offset; /* Where to begin to write. */
-- __u32 csize; /* (Compressed) data size */
-- __u32 dsize; /* Size of the node's data. (after decompression) */
-- __u8 compr; /* Compression algorithm used */
-- __u8 usercompr; /* Compression algorithm requested by the user */
-- __u16 flags; /* See JFFS2_INO_FLAG_* */
-- __u32 data_crc; /* CRC for the (compressed) data. */
-- __u32 node_crc; /* CRC for the raw inode (excluding data) */
--// __u8 data[dsize];
-+ jint16_t magic; /* A constant magic number. */
-+ jint16_t nodetype; /* == JFFS_NODETYPE_INODE */
-+ jint32_t totlen; /* Total length of this node (inc data, etc.) */
-+ jint32_t hdr_crc;
-+ jint32_t ino; /* Inode number. */
-+ jint32_t version; /* Version number. */
-+ jmode_t mode; /* The file's type or mode. */
-+ jint16_t uid; /* The file's owner. */
-+ jint16_t gid; /* The file's group. */
-+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
-+ jint32_t atime; /* Last access time. */
-+ jint32_t mtime; /* Last modification time. */
-+ jint32_t ctime; /* Change time. */
-+ jint32_t offset; /* Where to begin to write. */
-+ jint32_t csize; /* (Compressed) data size */
-+ jint32_t dsize; /* Size of the node's data. (after decompression) */
-+ uint8_t compr; /* Compression algorithm used */
-+ uint8_t usercompr; /* Compression algorithm requested by the user */
-+ jint16_t flags; /* See JFFS2_INO_FLAG_* */
-+ jint32_t data_crc; /* CRC for the (compressed) data. */
-+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
-+ uint8_t data[0];
- } __attribute__((packed));
-
- union jffs2_node_union {
-diff -Nurb linux-mips-2.4.27/include/linux/jffs2_fs_i.h linux/include/linux/jffs2_fs_i.h
---- linux-mips-2.4.27/include/linux/jffs2_fs_i.h 2001-10-19 03:25:03.000000000 +0200
-+++ linux/include/linux/jffs2_fs_i.h 2004-11-19 10:25:12.141163008 +0100
-@@ -1,22 +1,12 @@
--/* $Id$ */
-+/* $Id$ */
-
- #ifndef _JFFS2_FS_I
- #define _JFFS2_FS_I
-
--/* Include the pipe_inode_info at the beginning so that we can still
-- use the storage space in the inode when we have a pipe inode.
-- This sucks.
--*/
--
--#undef THISSUCKS /* Only for 2.2 */
--#ifdef THISSUCKS
--#include <linux/pipe_fs_i.h>
--#endif
-+#include <linux/version.h>
-+#include <linux/rbtree.h>
-
- struct jffs2_inode_info {
--#ifdef THISSUCKS
-- struct pipe_inode_info pipecrap;
--#endif
- /* We need an internal semaphore similar to inode->i_sem.
- Unfortunately, we can't used the existing one, because
- either the GC would deadlock, or we'd have to release it
-@@ -26,10 +16,10 @@
- struct semaphore sem;
-
- /* The highest (datanode) version number used for this ino */
-- __u32 highest_version;
-+ uint32_t highest_version;
-
- /* List of data fragments which make up the file */
-- struct jffs2_node_frag *fraglist;
-+ struct rb_root fragtree;
-
- /* There may be one datanode which isn't referenced by any of the
- above fragments, if it contains a metadata update but no actual
-@@ -44,19 +34,13 @@
- /* Some stuff we just have to keep in-core at all times, for each inode. */
- struct jffs2_inode_cache *inocache;
-
-- /* Keep a pointer to the last physical node in the list. We don't
-- use the doubly-linked lists because we don't want to increase
-- the memory usage that much. This is simpler */
-- // struct jffs2_raw_node_ref *lastnode;
-- __u16 flags;
-- __u8 usercompr;
--};
--
--#ifdef JFFS2_OUT_OF_KERNEL
--#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
--#else
--#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
-+ uint16_t flags;
-+ uint8_t usercompr;
-+#if !defined (__ECOS)
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
-+ struct inode vfs_inode;
- #endif
-+#endif
-+};
-
- #endif /* _JFFS2_FS_I */
--
-diff -Nurb linux-mips-2.4.27/include/linux/jffs2_fs_sb.h linux/include/linux/jffs2_fs_sb.h
---- linux-mips-2.4.27/include/linux/jffs2_fs_sb.h 2002-06-27 00:36:46.000000000 +0200
-+++ linux/include/linux/jffs2_fs_sb.h 2004-11-19 10:25:12.142162856 +0100
-@@ -1,19 +1,22 @@
--/* $Id$ */
-+/* $Id$ */
-
- #ifndef _JFFS2_FS_SB
- #define _JFFS2_FS_SB
-
- #include <linux/types.h>
- #include <linux/spinlock.h>
-+#include <linux/workqueue.h>
- #include <linux/completion.h>
- #include <asm/semaphore.h>
-+#include <linux/timer.h>
-+#include <linux/wait.h>
- #include <linux/list.h>
-
--#define INOCACHE_HASHSIZE 1
--
- #define JFFS2_SB_FLAG_RO 1
- #define JFFS2_SB_FLAG_MOUNTING 2
-
-+struct jffs2_inodirty;
-+
- /* A struct for the overall file system control. Pointers to
- jffs2_sb_info structs are named `c' in the source code.
- Nee jffs_control
-@@ -21,36 +24,46 @@
- struct jffs2_sb_info {
- struct mtd_info *mtd;
-
-- __u32 highest_ino;
-+ uint32_t highest_ino;
-+ uint32_t checked_ino;
-+
- unsigned int flags;
-- spinlock_t nodelist_lock;
-
-- // pid_t thread_pid; /* GC thread's PID */
- struct task_struct *gc_task; /* GC task struct */
- struct semaphore gc_thread_start; /* GC thread start mutex */
- struct completion gc_thread_exit; /* GC thread exit completion port */
-- // __u32 gc_minfree_threshold; /* GC trigger thresholds */
-- // __u32 gc_maxdirty_threshold;
-
- struct semaphore alloc_sem; /* Used to protect all the following
- fields, and also to protect against
- out-of-order writing of nodes.
- And GC.
- */
-- __u32 flash_size;
-- __u32 used_size;
-- __u32 dirty_size;
-- __u32 free_size;
-- __u32 erasing_size;
-- __u32 bad_size;
-- __u32 sector_size;
-- // __u32 min_free_size;
-- // __u32 max_chunk_size;
-+ uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER
-+ (i.e. zero for OOB CLEANMARKER */
-+
-+ uint32_t flash_size;
-+ uint32_t used_size;
-+ uint32_t dirty_size;
-+ uint32_t wasted_size;
-+ uint32_t free_size;
-+ uint32_t erasing_size;
-+ uint32_t bad_size;
-+ uint32_t sector_size;
-+ uint32_t unchecked_size;
-+
-+ uint32_t nr_free_blocks;
-+ uint32_t nr_erasing_blocks;
-+
-+ /* Number of free blocks there must be before we... */
-+ uint8_t resv_blocks_write; /* ... allow a normal filesystem write */
-+ uint8_t resv_blocks_deletion; /* ... allow a normal filesystem deletion */
-+ uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */
-+ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */
-+ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */
-
-- __u32 nr_free_blocks;
-- __u32 nr_erasing_blocks;
-+ uint32_t nospc_dirty_size;
-
-- __u32 nr_blocks;
-+ uint32_t nr_blocks;
- struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks
- * from the offset (blocks[ofs / sector_size]) */
- struct jffs2_eraseblock *nextblock; /* The block we're currently filling */
-@@ -58,9 +71,12 @@
- struct jffs2_eraseblock *gcblock; /* The block we're currently garbage-collecting */
-
- struct list_head clean_list; /* Blocks 100% full of clean data */
-+ struct list_head very_dirty_list; /* Blocks with lots of dirty space */
- struct list_head dirty_list; /* Blocks with some dirty space */
-+ struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */
-+ struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */
- struct list_head erasing_list; /* Blocks which are currently erasing */
-- struct list_head erase_pending_list; /* Blocks which need erasing */
-+ struct list_head erase_pending_list; /* Blocks which need erasing now */
- struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */
- struct list_head free_list; /* Blocks which are free and ready to be used */
- struct list_head bad_list; /* Bad blocks. */
-@@ -69,16 +85,33 @@
- spinlock_t erase_completion_lock; /* Protect free_list and erasing_list
- against erase completion handler */
- wait_queue_head_t erase_wait; /* For waiting for erases to complete */
-- struct jffs2_inode_cache *inocache_list[INOCACHE_HASHSIZE];
-+
-+ wait_queue_head_t inocache_wq;
-+ struct jffs2_inode_cache **inocache_list;
- spinlock_t inocache_lock;
--};
-
--#ifdef JFFS2_OUT_OF_KERNEL
--#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
--#else
--#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-+ /* Sem to allow jffs2_garbage_collect_deletion_dirent to
-+ drop the erase_completion_lock while it's holding a pointer
-+ to an obsoleted node. I don't like this. Alternatives welcomed. */
-+ struct semaphore erase_free_sem;
-+
-+#ifdef CONFIG_JFFS2_FS_NAND
-+ /* Write-behind buffer for NAND flash */
-+ unsigned char *wbuf;
-+ uint32_t wbuf_ofs;
-+ uint32_t wbuf_len;
-+ uint32_t wbuf_pagesize;
-+ struct jffs2_inodirty *wbuf_inodes;
-+
-+ /* Information about out-of-band area usage... */
-+ struct nand_oobinfo *oobinfo;
-+ uint32_t badblock_pos;
-+ uint32_t fsdata_pos;
-+ uint32_t fsdata_len;
- #endif
-
--#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-+ /* OS-private pointer for getting back to master superblock info */
-+ void *os_priv;
-+};
-
- #endif /* _JFFS2_FB_SB */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/blktrans.h linux/include/linux/mtd/blktrans.h
---- linux-mips-2.4.27/include/linux/mtd/blktrans.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/mtd/blktrans.h 2004-11-19 10:25:12.037178816 +0100
-@@ -0,0 +1,72 @@
-+/*
-+ * $Id$
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#ifndef __MTD_TRANS_H__
-+#define __MTD_TRANS_H__
-+
-+#include <asm/semaphore.h>
-+
-+struct hd_geometry;
-+struct mtd_info;
-+struct mtd_blktrans_ops;
-+struct file;
-+struct inode;
-+
-+struct mtd_blktrans_dev {
-+ struct mtd_blktrans_ops *tr;
-+ struct list_head list;
-+ struct mtd_info *mtd;
-+ struct semaphore sem;
-+ int devnum;
-+ int blksize;
-+ unsigned long size;
-+ int readonly;
-+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
-+};
-+
-+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */
-+
-+struct mtd_blktrans_ops {
-+ char *name;
-+ int major;
-+ int part_bits;
-+
-+ /* Access functions */
-+ int (*readsect)(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buffer);
-+ int (*writesect)(struct mtd_blktrans_dev *dev,
-+ unsigned long block, char *buffer);
-+
-+ /* Block layer ioctls */
-+ int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
-+ int (*flush)(struct mtd_blktrans_dev *dev);
-+
-+ /* Called with mtd_table_mutex held; no race with add/remove */
-+ int (*open)(struct mtd_blktrans_dev *dev);
-+ int (*release)(struct mtd_blktrans_dev *dev);
-+
-+ /* Called on {de,}registration and on subsequent addition/removal
-+ of devices, with mtd_table_mutex held. */
-+ void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd);
-+ void (*remove_dev)(struct mtd_blktrans_dev *dev);
-+
-+ struct list_head devs;
-+ struct list_head list;
-+ struct module *owner;
-+
-+ struct mtd_blkcore_priv *blkcore_priv;
-+};
-+
-+extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
-+extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
-+extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
-+extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
-+
-+
-+#endif /* __MTD_TRANS_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
---- linux-mips-2.4.27/include/linux/mtd/cfi.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/cfi.h 2004-11-19 10:25:12.038178664 +0100
-@@ -1,13 +1,14 @@
-
- /* Common Flash Interface structures
- * See http://support.intel.com/design/flash/technote/index.htm
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __MTD_CFI_H__
- #define __MTD_CFI_H__
-
- #include <linux/config.h>
-+#include <linux/version.h>
- #include <linux/delay.h>
- #include <linux/types.h>
- #include <linux/interrupt.h>
-@@ -260,7 +261,8 @@
- __u8 pri[3];
- __u8 MajorVersion;
- __u8 MinorVersion;
-- __u32 FeatureSupport;
-+ __u32 FeatureSupport; /* if bit 31 is set then an additional __u32 feature
-+ block follows - FIXME - not currently supported */
- __u8 SuspendCmdSupport;
- __u16 BlkStatusRegMask;
- __u8 VccOptimal;
-@@ -271,6 +273,25 @@
- __u8 UserProtRegSize;
- } __attribute__((packed));
-
-+/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
-+
-+struct cfi_pri_amdstd {
-+ __u8 pri[3];
-+ __u8 MajorVersion;
-+ __u8 MinorVersion;
-+ __u8 SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
-+ __u8 EraseSuspend;
-+ __u8 BlkProt;
-+ __u8 TmpBlkUnprotect;
-+ __u8 BlkProtUnprot;
-+ __u8 SimultaneousOps;
-+ __u8 BurstMode;
-+ __u8 PageMode;
-+ __u8 VppMin;
-+ __u8 VppMax;
-+ __u8 TopBottom;
-+} __attribute__((packed));
-+
- struct cfi_pri_query {
- __u8 NumFields;
- __u32 ProtField[1]; /* Not host ordered */
-@@ -314,8 +335,6 @@
- struct flchip chips[0]; /* per-chip data structure for each chip */
- };
-
--#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
--
- /*
- * Returns the command address according to the given geometry.
- */
-@@ -387,13 +406,13 @@
- static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
- {
- if (cfi_buswidth_is_1()) {
-- return map->read8(map, addr);
-+ return map_read8(map, addr);
- } else if (cfi_buswidth_is_2()) {
-- return map->read16(map, addr);
-+ return map_read16(map, addr);
- } else if (cfi_buswidth_is_4()) {
-- return map->read32(map, addr);
-+ return map_read32(map, addr);
- } else if (cfi_buswidth_is_8()) {
-- return map->read64(map, addr);
-+ return map_read64(map, addr);
- } else {
- return 0;
- }
-@@ -406,13 +425,13 @@
- static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
- {
- if (cfi_buswidth_is_1()) {
-- map->write8(map, val, addr);
-+ map_write8(map, val, addr);
- } else if (cfi_buswidth_is_2()) {
-- map->write16(map, val, addr);
-+ map_write16(map, val, addr);
- } else if (cfi_buswidth_is_4()) {
-- map->write32(map, val, addr);
-+ map_write32(map, val, addr);
- } else if (cfi_buswidth_is_8()) {
-- map->write64(map, val, addr);
-+ map_write64(map, val, addr);
- }
- }
-
-@@ -443,13 +462,13 @@
- static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
- {
- if (cfi_buswidth_is_1()) {
-- return map->read8(map, addr);
-+ return map_read8(map, addr);
- } else if (cfi_buswidth_is_2()) {
-- return cfi16_to_cpu(map->read16(map, addr));
-+ return cfi16_to_cpu(map_read16(map, addr));
- } else if (cfi_buswidth_is_4()) {
-- return cfi32_to_cpu(map->read32(map, addr));
-+ return cfi32_to_cpu(map_read32(map, addr));
- } else if (cfi_buswidth_is_8()) {
-- return cfi64_to_cpu(map->read64(map, addr));
-+ return cfi64_to_cpu(map_read64(map, addr));
- } else {
- return 0;
- }
-@@ -479,5 +498,19 @@
- spin_unlock_bh(mutex);
- }
-
-+struct cfi_extquery *cfi_read_pri(struct map_info *map, __u16 adr, __u16 size,
-+ const char* name);
-+
-+struct cfi_fixup {
-+ __u16 mfr;
-+ __u16 id;
-+ void (*fixup)(struct map_info *map, void* param);
-+ void* param;
-+};
-+
-+#define CFI_MFR_ANY 0xffff
-+#define CFI_ID_ANY 0xffff
-+
-+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups);
-
- #endif /* __MTD_CFI_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/compatmac.h linux/include/linux/mtd/compatmac.h
---- linux-mips-2.4.27/include/linux/mtd/compatmac.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/compatmac.h 2004-11-19 10:25:12.041178208 +0100
-@@ -1,573 +1,152 @@
--
- /*
-- * mtd/include/compatmac.h
-- *
-- * $Id$
-+ * $Id$
- *
- * Extensions and omissions from the normal 'linux/compatmac.h'
- * files. hopefully this will end up empty as the 'real' one
- * becomes fully-featured.
- */
-
--
--/* First, include the parts which the kernel is good enough to provide
-- * to us
-- */
--
- #ifndef __LINUX_MTD_COMPATMAC_H__
- #define __LINUX_MTD_COMPATMAC_H__
-
--#include <linux/config.h>
--#include <linux/module.h>
--#ifndef LINUX_VERSION_CODE
- #include <linux/version.h>
--#endif
--
--#ifndef VERSION_CODE
--# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
--#endif
--#ifndef KERNEL_VERSION
--# define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c)
--#endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
--# error "This kernel is too old: not supported by this file"
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
--#include <linux/types.h> /* used later in this header */
--
--#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
--#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
--
--typedef struct wait_queue * wait_queue_head_t;
--
--#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL}
--#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
--#define init_waitqueue_head init_waitqueue
--#define DECLARE_MUTEX(x) struct semaphore x = MUTEX
--#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED
--
--/* from sysdep-2.1.h */
--# include <asm/segment.h>
--# define access_ok(t,a,sz) (verify_area((t),(a),(sz)) ? 0 : 1)
--# define verify_area_20 verify_area
--# define copy_to_user(t,f,n) (memcpy_tofs(t,f,n), 0)
--# define __copy_to_user(t,f,n) copy_to_user((t),(f),(n))
--# define copy_to_user_ret(t,f,n,r) copy_to_user((t),(f),(n))
--# define copy_from_user(t,f,n) (memcpy_fromfs((t),(f),(n)), 0)
--# define __copy_from_user(t,f,n) copy_from_user((t),(f),(n))
--# define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n))
--//xxx # define PUT_USER(val,add) (put_user((val),(add)), 0)
--# define Put_user(val,add) (put_user((val),(add)), 0)
--# define __PUT_USER(val,add) PUT_USER((val),(add))
--# define PUT_USER_RET(val,add,ret) PUT_USER((val),(add))
--# define GET_USER(dest,add) ((dest)=get_user((add)), 0)
--# define __GET_USER(dest,add) GET_USER((dest),(add))
--# define GET_USER_RET(dest,add,ret) GET_USER((dest),(add))
--
--#define ioremap(offset,size) vremap(offset,size)
--#define iounmap(adr) /* */
--
--#define EXPORT_SYMBOL(s) /* */
--#define EXPORT_SYMBOL_NOVERS(s) /* */
--
--/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */
--
--#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10)
--
--# include <asm/byteorder.h>
--# ifdef __LITTLE_ENDIAN
--# define cpu_to_le16(x) (x)
--# define cpu_to_le32(x) (x)
--# define cpu_to_be16(x) htons((x))
--# define cpu_to_be32(x) htonl((x))
--# else
--# define cpu_to_be16(x) (x)
--# define cpu_to_be32(x) (x)
-- extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);}
-- extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) |
-- ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));}
--# endif
--
--# define le16_to_cpu(x) cpu_to_le16(x)
--# define le32_to_cpu(x) cpu_to_le32(x)
--# define be16_to_cpu(x) cpu_to_be16(x)
--# define be32_to_cpu(x) cpu_to_be32(x)
--
--#endif
--
--#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43)
--# define cpu_to_le16p(addr) (cpu_to_le16(*(addr)))
--# define cpu_to_le32p(addr) (cpu_to_le32(*(addr)))
--# define cpu_to_be16p(addr) (cpu_to_be16(*(addr)))
--# define cpu_to_be32p(addr) (cpu_to_be32(*(addr)))
--
-- extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);}
-- extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);}
-- extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);}
-- extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);}
--
--# define le16_to_cpup(x) cpu_to_le16p(x)
--# define le32_to_cpup(x) cpu_to_le32p(x)
--# define be16_to_cpup(x) cpu_to_be16p(x)
--# define be32_to_cpup(x) cpu_to_be32p(x)
--
--# define le16_to_cpus(x) cpu_to_le16s(x)
--# define le32_to_cpus(x) cpu_to_le32s(x)
--# define be16_to_cpus(x) cpu_to_be16s(x)
--# define be32_to_cpus(x) cpu_to_be32s(x)
--#endif
--
--// from 2.2, linux/types.h
--#ifndef __BIT_TYPES_DEFINED__
--#define __BIT_TYPES_DEFINED__
--
--typedef __u8 u_int8_t;
--typedef __s8 int8_t;
--typedef __u16 u_int16_t;
--typedef __s16 int16_t;
--typedef __u32 u_int32_t;
--typedef __s32 int32_t;
--
--#endif /* !(__BIT_TYPES_DEFINED__) */
--
--#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-- typedef struct { } spinlock_t;
-- #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
--#else
-- typedef struct { int gcc_is_buggy; } spinlock_t;
-- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
--#endif
--
--#define spin_lock_init(lock) do { } while(0)
--#define spin_lock(lock) (void)(lock) /* Not "unused variable". */
--#define spin_trylock(lock) (1)
--#define spin_unlock_wait(lock) do { } while(0)
--#define spin_unlock(lock) do { } while(0)
--#define spin_lock_irq(lock) cli()
--#define spin_unlock_irq(lock) sti()
--
--#define spin_lock_irqsave(lock, flags) \
-- do { save_flags(flags); cli(); } while (0)
--#define spin_unlock_irqrestore(lock, flags) \
-- restore_flags(flags)
--
--// Doesn't work when tqueue.h is included.
--// #define queue_task queue_task_irq_off
--#define tty_flip_buffer_push(tty) queue_task_irq_off(&tty->flip.tqueue, &tq_timer)
--#define signal_pending(current) (current->signal & ~current->blocked)
--#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0)
--#define time_after(t1,t2) (((long)t1-t2) > 0)
--
--#else
-- #include <linux/compatmac.h>
--#endif // LINUX_VERSION_CODE < 0x020100
--
--
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
--#include <linux/vmalloc.h>
--#endif
--
--/* Modularization issues */
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)
--# define __USE_OLD_SYMTAB__
--# define EXPORT_NO_SYMBOLS register_symtab(NULL);
--# define REGISTER_SYMTAB(tab) register_symtab(tab)
--#else
--# define REGISTER_SYMTAB(tab) /* nothing */
--#endif
--
--#ifdef __USE_OLD_SYMTAB__
--# define __MODULE_STRING(s) /* nothing */
--# define MODULE_PARM(v,t) /* nothing */
--# define MODULE_PARM_DESC(v,t) /* nothing */
--# define MODULE_AUTHOR(n) /* nothing */
--# define MODULE_DESCRIPTION(d) /* nothing */
--# define MODULE_SUPPORTED_DEVICE(n) /* nothing */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-+#error "This kernel is too old: not supported by this file"
- #endif
-
--/*
-- * "select" changed in 2.1.23. The implementation is twin, but this
-- * header is new
-- */
--#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22)
--# include <linux/poll.h>
--#else
--# define __USE_OLD_SELECT__
--#endif
-+ /* O(1) scheduler stuff. */
-
--/* Other change in the fops are solved using pseudo-types */
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
--# define lseek_t long long
--# define lseek_off_t long long
--#else
--# define lseek_t int
--# define lseek_off_t off_t
--#endif
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__)
-+#include <linux/sched.h>
-+static inline void __recalc_sigpending(void)
-+{
-+ recalc_sigpending(current);
-+}
-+#undef recalc_sigpending
-+#define recalc_sigpending() __recalc_sigpending ()
-
--/* changed the prototype of read/write */
-+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
-
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__)
--# define count_t unsigned long
--# define read_write_t long
--#else
--# define count_t int
--# define read_write_t int
- #endif
-
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31)
--# define release_t void
--# define release_return(x) return
--#else
--# define release_t int
--# define release_return(x) return (x)
--#endif
--
--#if LINUX_VERSION_CODE < 0x20300
--#define __exit
--#endif
--#if LINUX_VERSION_CODE < 0x20200
--#define __init
--#else
--#include <linux/init.h>
--#endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
--#define init_MUTEX(x) do {*(x) = MUTEX;} while (0)
--#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0)
--#endif
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
--#define RQFUNC_ARG void
--#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
--#else
--#define RQFUNC_ARG request_queue_t *q
-+#ifndef yield
-+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32)
--#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0)
--#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn)
--#define blk_init_queue(q, rq) do {q = rq;} while(0)
-+#ifndef minor
-+#define major(d) (MAJOR(to_kdev_t(d)))
-+#define minor(d) (MINOR(to_kdev_t(d)))
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
--#ifdef CONFIG_MODULES
--#define __MOD_INC_USE_COUNT(mod) \
-- (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
--#define __MOD_DEC_USE_COUNT(mod) \
-- (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
--#else
--#define __MOD_INC_USE_COUNT(mod)
--#define __MOD_DEC_USE_COUNT(mod)
--#endif
-+#ifndef mk_kdev
-+#define mk_kdev(ma,mi) MKDEV(ma,mi)
-+#define kdev_t_to_nr(x) (x)
- #endif
-
-+#define need_resched() (current->need_resched)
-+#define cond_resched() do { if need_resched() { yield(); } } while(0)
-
--#ifndef HAVE_INTER_MODULE
--static inline void *inter_module_get(char *x) {return NULL;}
--static inline void *inter_module_get_request(char *x, char *y) {return NULL;}
--static inline void inter_module_put(const char *x) {}
--static inline void inter_module_register(const char *x, struct module *y, const void *z) {}
--static inline void inter_module_unregister(const char *x) {}
-+#endif /* < 2.4.20 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-+#define iminor(i) minor((i)->i_rdev)
-+#define imajor(i) major((i)->i_rdev)
-+#define old_encode_dev(d) ( (major(d)<<8) | minor(d) )
-+#define old_decode_dev(rdev) (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff)))
-+#define old_valid_dev(d) (1)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
-
--#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
--#define init_waitqueue_head init_waitqueue
-+#include <linux/sched.h>
-
-+#ifdef __rh_config_h__
-+#define sigmask_lock sighand->siglock
-+#define sig sighand
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
--
--static inline int try_inc_mod_count(struct module *mod)
-+static inline void __daemonize_modvers(void)
- {
--#ifdef CONFIG_MODULES
-- if (mod)
-- __MOD_INC_USE_COUNT(mod);
--#endif
-- return 1;
--}
--#endif
-+ daemonize();
-
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sigmask_lock);
-+}
-+#undef daemonize
-+#define daemonize(fmt, ...) do { \
-+ snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__); \
-+ __daemonize_modvers(); \
-+ } while(0)
-
--/* Yes, I'm aware that it's a fairly ugly hack.
-- Until the __constant_* macros appear in Linus' own kernels, this is
-- the way it has to be done.
-- DW 19/1/00
-- */
--
--#include <asm/byteorder.h>
--
--#ifndef __constant_cpu_to_le16
--
--#ifdef __BIG_ENDIAN
--#define __constant_cpu_to_le64(x) ___swab64((x))
--#define __constant_le64_to_cpu(x) ___swab64((x))
--#define __constant_cpu_to_le32(x) ___swab32((x))
--#define __constant_le32_to_cpu(x) ___swab32((x))
--#define __constant_cpu_to_le16(x) ___swab16((x))
--#define __constant_le16_to_cpu(x) ___swab16((x))
--#define __constant_cpu_to_be64(x) ((__u64)(x))
--#define __constant_be64_to_cpu(x) ((__u64)(x))
--#define __constant_cpu_to_be32(x) ((__u32)(x))
--#define __constant_be32_to_cpu(x) ((__u32)(x))
--#define __constant_cpu_to_be16(x) ((__u16)(x))
--#define __constant_be16_to_cpu(x) ((__u16)(x))
--#else
--#ifdef __LITTLE_ENDIAN
--#define __constant_cpu_to_le64(x) ((__u64)(x))
--#define __constant_le64_to_cpu(x) ((__u64)(x))
--#define __constant_cpu_to_le32(x) ((__u32)(x))
--#define __constant_le32_to_cpu(x) ((__u32)(x))
--#define __constant_cpu_to_le16(x) ((__u16)(x))
--#define __constant_le16_to_cpu(x) ((__u16)(x))
--#define __constant_cpu_to_be64(x) ___swab64((x))
--#define __constant_be64_to_cpu(x) ___swab64((x))
--#define __constant_cpu_to_be32(x) ___swab32((x))
--#define __constant_be32_to_cpu(x) ___swab32((x))
--#define __constant_cpu_to_be16(x) ___swab16((x))
--#define __constant_be16_to_cpu(x) ___swab16((x))
--#else
--#error No (recognised) endianness defined (unless it,s PDP)
--#endif /* __LITTLE_ENDIAN */
--#endif /* __BIG_ENDIAN */
--
--#endif /* ifndef __constant_cpu_to_le16 */
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-- #define mod_init_t int __init
-- #define mod_exit_t void
--#else
-- #define mod_init_t static int __init
-- #define mod_exit_t static void __exit
--#endif
--
--#ifndef THIS_MODULE
--#ifdef MODULE
--#define THIS_MODULE (&__this_module)
--#else
--#define THIS_MODULE (NULL)
--#endif
--#endif
--
--#if LINUX_VERSION_CODE < 0x20300
--#include <linux/interrupt.h>
--#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0)
--#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0)
--#else
--#include <asm/softirq.h>
--#include <linux/spinlock.h>
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
--#define set_current_state(state_value) \
-- do { current->state = (state_value); } while (0)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
--static inline int invalidate_device(kdev_t dev, int do_sync) {
-+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
-+{
-+ unsigned long flags;
-+ unsigned long ret;
-
-- if (do_sync)
-- fsync_dev(dev);
-+ spin_lock_irqsave(&current->sigmask_lock, flags);
-+ ret = dequeue_signal(mask, info);
-+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
-
-- invalidate_buffers(dev);
-- return 0;
-+ return ret;
- }
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5)
--static inline int invalidate_device(kdev_t dev, int do_sync) {
-- struct super_block *sb = get_super(dev);
-- int res = 0;
-
-- if (do_sync)
-- fsync_dev(dev);
--
-- if (sb)
-- res = invalidate_inodes(sb);
-+static inline int allow_signal(int sig)
-+{
-+ if (sig < 1 || sig > _NSIG)
-+ return -EINVAL;
-
-- invalidate_buffers(dev);
-- return res;
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigdelset(&current->blocked, sig);
-+ recalc_sigpending();
-+ /* Make sure the kernel neither eats it now converts to SIGKILL */
-+ current->sig->action[sig-1].sa.sa_handler = (void *)2;
-+ spin_unlock_irq(&current->sigmask_lock);
-+ return 0;
- }
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
--#undef min
--#undef max
--#undef min_t
--#undef max_t
--/*
-- * min()/max() macros that also do
-- * strict type-checking.. See the
-- * "unnecessary" pointer comparison.
-- */
--#define min(x,y) ({ \
-- const typeof(x) _x = (x); \
-- const typeof(y) _y = (y); \
-- (void) (&_x == &_y); \
-- _x < _y ? _x : _y; })
--
--#define max(x,y) ({ \
-- const typeof(x) _x = (x); \
-- const typeof(y) _y = (y); \
-- (void) (&_x == &_y); \
-- _x > _y ? _x : _y; })
--
--/*
-- * ..and if you can't take the strict
-- * types, you can specify one yourself.
-- *
-- * Or not use min/max at all, of course.
-- */
--#define min_t(type,x,y) \
-- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
--#define max_t(type,x,y) \
-- ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
--struct completion {
-- struct semaphore s;
--};
--
--#define complete(c) up(&(c)->s)
--#define wait_for_completion(c) down(&(c)->s)
--#define init_completion(c) init_MUTEX_LOCKED(&(c)->s);
--
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
--/* This came later */
--#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
-- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
-+static inline int disallow_signal(int sig)
-+{
-+ if (sig < 1 || sig > _NSIG)
-+ return -EINVAL;
-
--#include <linux/genhd.h>
-+ spin_lock_irq(&current->sigmask_lock);
-+ sigaddset(&current->blocked, sig);
-+ recalc_sigpending();
-
--static inline void add_gendisk(struct gendisk *gp)
--{
-- gp->next = gendisk_head;
-- gendisk_head = gp;
-+ current->sig->action[sig-1].sa.sa_handler = SIG_DFL;
-+ spin_unlock_irq(&current->sigmask_lock);
-+ return 0;
- }
-
--static inline void del_gendisk(struct gendisk *gp)
--{
-- struct gendisk *gd, **gdp;
-+#undef sighand
-+#undef sigmask_lock
-
-- for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-- if (*gdp == gp) {
-- gd = *gdp; *gdp = gd->next;
-- break;
-- }
--}
-+#define PF_FREEZE 0
-+#define refrigerator(x) do { ; } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE)
-+ /* Module bits */
-
--#define module_init(func) \
--mod_init_t init_module(void) { \
-- return func(); \
--}
-
--#define module_exit(func) \
--mod_exit_t cleanup_module(void) { \
-- return func(); \
--}
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
-+#define try_module_get(m) try_inc_mod_count(m)
-+#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0)
-+#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0)
-+#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
-- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
--#define MODULE_LICENSE(x) /* */
--#endif
-
--/* Removed for 2.4.21 kernel. This really should have been renamed
-- when it was changed -- this is a PITA */
--#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
--#include <linux/sched.h>
--static inline void __recalc_sigpending(void)
--{
-- recalc_sigpending(current);
--}
--#undef recalc_sigpending
--#define recalc_sigpending() __recalc_sigpending ()
--#endif
-+ /* Random filesystem stuff, only for JFFS2 really */
-
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
- #define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3)
--#define need_resched() (current->need_resched)
--#define cond_resched() do { if need_resched() schedule(); } while(0)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
--#ifndef yield
--#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
--#endif
--#ifndef minor
--#define major(d) (MAJOR(to_kdev_t(d)))
--#define minor(d) (MINOR(to_kdev_t(d)))
--#endif
--#ifndef mk_kdev
--#define mk_kdev(ma,mi) MKDEV(ma,mi)
--#define kdev_t_to_nr(x) (x)
--#endif
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-- /* Is this right? */
--#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0)
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL)
--#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
--#define rq_data_dir(x) ((x)->cmd)
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
--
--#define IS_REQ_CMD(req) (1)
--
--#define QUEUE_LOCK(q) (&io_request_lock)
--
--#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req))
--
--#else /* > 2.5.0 */
--
--#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD)
--
--#define QUEUE_LOCK(q) ((q)->queue_lock)
--
--#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock))
--
--#endif
--
--/* Removed cos it broke stuff. Where is this required anyway?
-- * #ifndef QUEUE_EMPTY
-- * #define QUEUE_EMPTY (!CURRENT)
-- * #endif
-- */
--#if LINUX_VERSION_CODE < 0x20300
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
--#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si)
--#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
--#else
--#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE))
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
--#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
--#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
--#else
--#define BLK_INC_USE_COUNT do {} while(0)
--#define BLK_DEC_USE_COUNT do {} while(0)
--#endif
--
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
- #define PageUptodate(x) Page_Uptodate(x)
- #endif
-@@ -580,4 +159,31 @@
- #define generic_file_readonly_mmap generic_file_mmap
- #endif
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70)
-+
-+#include <linux/kmod.h>
-+#include <linux/string.h>
-+
-+static inline char *strlcpy(char *dest, const char *src, int len)
-+{
-+ dest[len-1] = 0;
-+ return strncpy(dest, src, len-1);
-+}
-+
-+static inline int do_old_request_module(const char *mod)
-+{
-+ return request_module(mod);
-+}
-+#undef request_module
-+#define request_module(fmt, ...) \
-+ ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); })
-+
-+#endif /* 2.5.70 */
-+
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({ \
-+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-+ (type *)( (char *)__mptr - offsetof(type,member) );})
-+#endif
-+
- #endif /* __LINUX_MTD_COMPATMAC_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/doc2000.h linux/include/linux/mtd/doc2000.h
---- linux-mips-2.4.27/include/linux/mtd/doc2000.h 2001-11-05 21:16:30.000000000 +0100
-+++ linux/include/linux/mtd/doc2000.h 2004-11-19 10:25:12.044177752 +0100
-@@ -1,13 +1,21 @@
--
--/* Linux driver for Disk-On-Chip 2000 */
--/* (c) 1999 Machine Vision Holdings, Inc. */
--/* Author: David Woodhouse <dwmw2@mvhi.com> */
--/* $Id$ */
-+/*
-+ * Linux driver for Disk-On-Chip devices
-+ *
-+ * Copyright (C) 1999 Machine Vision Holdings, Inc.
-+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
-+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
-+ * Copyright (C) 2002-2003 SnapGear Inc
-+ *
-+ * $Id$
-+ *
-+ * Released under GPL
-+ */
-
- #ifndef __MTD_DOC2000_H__
- #define __MTD_DOC2000_H__
-
- #include <linux/mtd/mtd.h>
-+#include <asm/semaphore.h>
-
- #define DoC_Sig1 0
- #define DoC_Sig2 1
-@@ -38,18 +46,47 @@
- #define DoC_Mil_CDSN_IO 0x0800
- #define DoC_2k_CDSN_IO 0x1800
-
-+#define DoC_Mplus_NOP 0x1002
-+#define DoC_Mplus_AliasResolution 0x1004
-+#define DoC_Mplus_DOCControl 0x1006
-+#define DoC_Mplus_AccessStatus 0x1008
-+#define DoC_Mplus_DeviceSelect 0x1008
-+#define DoC_Mplus_Configuration 0x100a
-+#define DoC_Mplus_OutputControl 0x100c
-+#define DoC_Mplus_FlashControl 0x1020
-+#define DoC_Mplus_FlashSelect 0x1022
-+#define DoC_Mplus_FlashCmd 0x1024
-+#define DoC_Mplus_FlashAddress 0x1026
-+#define DoC_Mplus_FlashData0 0x1028
-+#define DoC_Mplus_FlashData1 0x1029
-+#define DoC_Mplus_ReadPipeInit 0x102a
-+#define DoC_Mplus_LastDataRead 0x102c
-+#define DoC_Mplus_LastDataRead1 0x102d
-+#define DoC_Mplus_WritePipeTerm 0x102e
-+#define DoC_Mplus_ECCSyndrome0 0x1040
-+#define DoC_Mplus_ECCSyndrome1 0x1041
-+#define DoC_Mplus_ECCSyndrome2 0x1042
-+#define DoC_Mplus_ECCSyndrome3 0x1043
-+#define DoC_Mplus_ECCSyndrome4 0x1044
-+#define DoC_Mplus_ECCSyndrome5 0x1045
-+#define DoC_Mplus_ECCConf 0x1046
-+#define DoC_Mplus_Toggle 0x1046
-+#define DoC_Mplus_DownloadStatus 0x1074
-+#define DoC_Mplus_CtrlConfirm 0x1076
-+#define DoC_Mplus_Power 0x1fff
-+
- /* How to access the device?
- * On ARM, it'll be mmap'd directly with 32-bit wide accesses.
- * On PPC, it's mmap'd and 16-bit wide.
- * Others use readb/writeb
- */
- #if defined(__arm__)
--#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
--#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
-+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
-+#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
- #define DOC_IOREMAP_LEN 0x8000
- #elif defined(__ppc__)
--#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
--#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
-+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
-+#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
- #define DOC_IOREMAP_LEN 0x4000
- #else
- #define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg))
-@@ -71,13 +108,21 @@
- #define DOC_MODE_RESERVED1 2
- #define DOC_MODE_RESERVED2 3
-
--#define DOC_MODE_MDWREN 4
- #define DOC_MODE_CLR_ERR 0x80
-+#define DOC_MODE_RST_LAT 0x10
-+#define DOC_MODE_BDECT 0x08
-+#define DOC_MODE_MDWREN 0x04
-
- #define DOC_ChipID_Doc2k 0x20
-+#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */
- #define DOC_ChipID_DocMil 0x30
-+#define DOC_ChipID_DocMilPlus32 0x40
-+#define DOC_ChipID_DocMilPlus16 0x41
-
- #define CDSN_CTRL_FR_B 0x80
-+#define CDSN_CTRL_FR_B0 0x40
-+#define CDSN_CTRL_FR_B1 0x80
-+
- #define CDSN_CTRL_ECC_IO 0x20
- #define CDSN_CTRL_FLASH_IO 0x10
- #define CDSN_CTRL_WP 0x08
-@@ -93,6 +138,10 @@
- #define DOC_ECC_RESV 0x02
- #define DOC_ECC_IGNORE 0x01
-
-+#define DOC_FLASH_CE 0x80
-+#define DOC_FLASH_WP 0x40
-+#define DOC_FLASH_BANK 0x02
-+
- /* We have to also set the reserved bit 1 for enable */
- #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
- #define DOC_ECC_DIS (DOC_ECC_RESV)
-@@ -107,9 +156,12 @@
- #define MAX_FLOORS 4
- #define MAX_CHIPS 4
-
--#define MAX_FLOORS_MIL 4
-+#define MAX_FLOORS_MIL 1
- #define MAX_CHIPS_MIL 1
-
-+#define MAX_FLOORS_MPLUS 2
-+#define MAX_CHIPS_MPLUS 1
-+
- #define ADDR_COLUMN 1
- #define ADDR_PAGE 2
- #define ADDR_COLUMN_PAGE 3
-@@ -118,7 +170,7 @@
- unsigned long physadr;
- unsigned long virtadr;
- unsigned long totlen;
-- char ChipID; /* Type of DiskOnChip */
-+ unsigned char ChipID; /* Type of DiskOnChip */
- int ioreg;
-
- unsigned long mfr; /* Flash IDs - only one type of flash per device */
-@@ -126,6 +178,7 @@
- int chipshift;
- char page256;
- char pageadrlen;
-+ char interleave; /* Internal interleaving - Millennium Plus style */
- unsigned long erasesize;
-
- int curfloor;
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/flashchip.h linux/include/linux/mtd/flashchip.h
---- linux-mips-2.4.27/include/linux/mtd/flashchip.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/flashchip.h 2004-11-19 10:25:12.045177600 +0100
-@@ -6,7 +6,7 @@
- *
- * (C) 2000 Red Hat. GPLd.
- *
-- * $Id$
-+ * $Id$
- *
- */
-
-@@ -58,6 +58,11 @@
- int ref_point_counter;
- flstate_t state;
- flstate_t oldstate;
-+
-+ int write_suspended:1;
-+ int erase_suspended:1;
-+ unsigned long in_progress_block_addr;
-+
- spinlock_t *mutex;
- spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */
- wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/gen_probe.h linux/include/linux/mtd/gen_probe.h
---- linux-mips-2.4.27/include/linux/mtd/gen_probe.h 2001-11-05 21:16:30.000000000 +0100
-+++ linux/include/linux/mtd/gen_probe.h 2004-11-19 10:25:12.048177144 +0100
-@@ -1,7 +1,7 @@
- /*
- * (C) 2001, 2001 Red Hat, Inc.
- * GPL'd
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __LINUX_MTD_GEN_PROBE_H__
-@@ -10,12 +10,12 @@
- #include <linux/mtd/flashchip.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/cfi.h>
-+#include <asm/bitops.h>
-
- struct chip_probe {
- char *name;
- int (*probe_chip)(struct map_info *map, __u32 base,
-- struct flchip *chips, struct cfi_private *cfi);
--
-+ unsigned long *chip_map, struct cfi_private *cfi);
- };
-
- struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp);
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/inftl.h linux/include/linux/mtd/inftl.h
---- linux-mips-2.4.27/include/linux/mtd/inftl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/mtd/inftl.h 2004-11-19 10:25:12.051176688 +0100
-@@ -0,0 +1,129 @@
-+/*
-+ * inftl.h -- defines to support the Inverse NAND Flash Translation Layer
-+ *
-+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * $Id$
-+ */
-+
-+#ifndef __MTD_INFTL_H__
-+#define __MTD_INFTL_H__
-+
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nftl.h>
-+
-+#define OSAK_VERSION 0x5120
-+#define PERCENTUSED 98
-+
-+#define SECTORSIZE 512
-+
-+#ifndef INFTL_MAJOR
-+#define INFTL_MAJOR 94
-+#endif
-+#define INFTL_PARTN_BITS 4
-+
-+/* Block Control Information */
-+
-+struct inftl_bci {
-+ __u8 ECCsig[6];
-+ __u8 Status;
-+ __u8 Status1;
-+} __attribute__((packed));
-+
-+struct inftl_unithead1 {
-+ __u16 virtualUnitNo;
-+ __u16 prevUnitNo;
-+ __u8 ANAC;
-+ __u8 NACs;
-+ __u8 parityPerField;
-+ __u8 discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unithead2 {
-+ __u8 parityPerField;
-+ __u8 ANAC;
-+ __u16 prevUnitNo;
-+ __u16 virtualUnitNo;
-+ __u8 NACs;
-+ __u8 discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unittail {
-+ __u8 Reserved[4];
-+ __u16 EraseMark;
-+ __u16 EraseMark1;
-+} __attribute__((packed));
-+
-+union inftl_uci {
-+ struct inftl_unithead1 a;
-+ struct inftl_unithead2 b;
-+ struct inftl_unittail c;
-+};
-+
-+struct inftl_oob {
-+ struct inftl_bci b;
-+ union inftl_uci u;
-+};
-+
-+
-+/* INFTL Media Header */
-+
-+struct INFTLPartition {
-+ __u32 virtualUnits;
-+ __u32 firstUnit;
-+ __u32 lastUnit;
-+ __u32 flags;
-+ __u32 spareUnits;
-+ __u32 Reserved0;
-+ __u32 Reserved1;
-+} __attribute__((packed));
-+
-+struct INFTLMediaHeader {
-+ char bootRecordID[8];
-+ __u32 NoOfBootImageBlocks;
-+ __u32 NoOfBinaryPartitions;
-+ __u32 NoOfBDTLPartitions;
-+ __u32 BlockMultiplierBits;
-+ __u32 FormatFlags;
-+ __u32 OsakVersion;
-+ __u32 PercentUsed;
-+ struct INFTLPartition Partitions[4];
-+} __attribute__((packed));
-+
-+/* Partition flag types */
-+#define INFTL_BINARY 0x20000000
-+#define INFTL_BDTL 0x40000000
-+#define INFTL_LAST 0x80000000
-+
-+
-+#ifdef __KERNEL__
-+
-+struct INFTLrecord {
-+ struct mtd_blktrans_dev mbd;
-+ __u16 MediaUnit, SpareMediaUnit;
-+ __u32 EraseSize;
-+ struct INFTLMediaHeader MediaHdr;
-+ int usecount;
-+ unsigned char heads;
-+ unsigned char sectors;
-+ unsigned short cylinders;
-+ __u16 numvunits;
-+ __u16 firstEUN;
-+ __u16 lastEUN;
-+ __u16 numfreeEUNs;
-+ __u16 LastFreeEUN; /* To speed up finding a free EUN */
-+ int head,sect,cyl;
-+ __u16 *PUtable; /* Physical Unit Table */
-+ __u16 *VUtable; /* Virtual Unit Table */
-+ unsigned int nb_blocks; /* number of physical blocks */
-+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
-+ struct erase_info instr;
-+};
-+
-+int INFTL_mount(struct INFTLrecord *s);
-+int INFTL_formatblock(struct INFTLrecord *s, int block);
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* __MTD_INFTL_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/jedec.h linux/include/linux/mtd/jedec.h
---- linux-mips-2.4.27/include/linux/mtd/jedec.h 2001-12-02 12:35:00.000000000 +0100
-+++ linux/include/linux/mtd/jedec.h 2004-11-19 10:25:12.052176536 +0100
-@@ -7,14 +7,13 @@
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
-- * $Id$
-+ * $Id$
- */
-
- #ifndef __LINUX_MTD_JEDEC_H__
- #define __LINUX_MTD_JEDEC_H__
-
- #include <linux/types.h>
--#include <linux/mtd/map.h>
-
- #define MAX_JEDEC_CHIPS 16
-
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/map.h linux/include/linux/mtd/map.h
---- linux-mips-2.4.27/include/linux/mtd/map.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/map.h 2004-11-19 10:25:12.054176232 +0100
-@@ -1,14 +1,15 @@
-
- /* Overhauled routines for dealing with different mmap regions of flash */
--/* $Id$ */
-+/* $Id$ */
-
- #ifndef __LINUX_MTD_MAP_H__
- #define __LINUX_MTD_MAP_H__
-
- #include <linux/config.h>
- #include <linux/types.h>
--#include <linux/mtd/mtd.h>
--#include <linux/slab.h>
-+#include <linux/list.h>
-+#include <asm/system.h>
-+#include <asm/io.h>
-
- /* The map stuff is very simple. You fill in your struct map_info with
- a handful of routines for accessing the device, making sure they handle
-@@ -29,39 +30,44 @@
- struct map_info {
- char *name;
- unsigned long size;
-+ unsigned long phys;
-+#define NO_XIP (-1UL)
-+
-+ unsigned long virt;
-+ void *cached;
-+
- int buswidth; /* in octets */
-- __u8 (*read8)(struct map_info *, unsigned long);
-- __u16 (*read16)(struct map_info *, unsigned long);
-- __u32 (*read32)(struct map_info *, unsigned long);
-- __u64 (*read64)(struct map_info *, unsigned long);
-+
-+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-+ u8 (*read8)(struct map_info *, unsigned long);
-+ u16 (*read16)(struct map_info *, unsigned long);
-+ u32 (*read32)(struct map_info *, unsigned long);
-+ u64 (*read64)(struct map_info *, unsigned long);
- /* If it returned a 'long' I'd call it readl.
- * It doesn't.
- * I won't.
- * dwmw2 */
-
- void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
-- void (*write8)(struct map_info *, __u8, unsigned long);
-- void (*write16)(struct map_info *, __u16, unsigned long);
-- void (*write32)(struct map_info *, __u32, unsigned long);
-- void (*write64)(struct map_info *, __u64, unsigned long);
-+ void (*write8)(struct map_info *, u8, unsigned long);
-+ void (*write16)(struct map_info *, u16, unsigned long);
-+ void (*write32)(struct map_info *, u32, unsigned long);
-+ void (*write64)(struct map_info *, u64, unsigned long);
- void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
-
-- u_char * (*point) (struct map_info *, loff_t, size_t);
-- void (*unpoint) (struct map_info *, u_char *, loff_t, size_t);
--
-+ /* We can perhaps put in 'point' and 'unpoint' methods, if we really
-+ want to enable XIP for non-linear mappings. Not yet though. */
-+#endif
-+ /* set_vpp() must handle being reentered -- enable, enable, disable
-+ must leave it enabled. */
- void (*set_vpp)(struct map_info *, int);
-- /* We put these two here rather than a single void *map_priv,
-- because we want mappers to be able to have quickly-accessible
-- cache for the 'currently-mapped page' without the _extra_
-- redirection that would be necessary. If you need more than
-- two longs, turn the second into a pointer. dwmw2 */
-+
- unsigned long map_priv_1;
- unsigned long map_priv_2;
- void *fldrv_priv;
- struct mtd_chip_driver *fldrv;
- };
-
--
- struct mtd_chip_driver {
- struct mtd_info *(*probe)(struct map_info *map);
- void (*destroy)(struct mtd_info *);
-@@ -74,26 +80,93 @@
- void unregister_mtd_chip_driver(struct mtd_chip_driver *);
-
- struct mtd_info *do_map_probe(const char *name, struct map_info *map);
-+void map_destroy(struct mtd_info *mtd);
-+
-+#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
-+#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
-+
-+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-+#define map_read8(map, ofs) (map)->read8(map, ofs)
-+#define map_read16(map, ofs) (map)->read16(map, ofs)
-+#define map_read32(map, ofs) (map)->read32(map, ofs)
-+#define map_read64(map, ofs) (map)->read64(map, ofs)
-+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
-+#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs)
-+#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs)
-+#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs)
-+#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs)
-+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
-
-+extern void simple_map_init(struct map_info *);
-+#define map_is_linear(map) (map->phys != NO_XIP)
-
--/*
-- * Destroy an MTD device which was created for a map device.
-- * Make sure the MTD device is already unregistered before calling this
-- */
--static inline void map_destroy(struct mtd_info *mtd)
--{
-- struct map_info *map = mtd->priv;
--
-- if (map->fldrv->destroy)
-- map->fldrv->destroy(mtd);
--#ifdef CONFIG_MODULES
-- if (map->fldrv->module)
-- __MOD_DEC_USE_COUNT(map->fldrv->module);
-+#else
-+static inline u8 map_read8(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readb(map->virt + ofs);
-+}
-+
-+static inline u16 map_read16(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readw(map->virt + ofs);
-+}
-+
-+static inline u32 map_read32(struct map_info *map, unsigned long ofs)
-+{
-+ return __raw_readl(map->virt + ofs);
-+}
-+
-+static inline u64 map_read64(struct map_info *map, unsigned long ofs)
-+{
-+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-+ BUG();
-+ return 0;
-+#else
-+ return __raw_readll(map->virt + ofs);
- #endif
-- kfree(mtd);
- }
-
--#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
--#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
-+static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs)
-+{
-+ __raw_writeb(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs)
-+{
-+ __raw_writew(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs)
-+{
-+ __raw_writel(datum, map->virt + ofs);
-+ mb();
-+}
-+
-+static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs)
-+{
-+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-+ BUG();
-+#else
-+ __raw_writell(datum, map->virt + ofs);
-+ mb();
-+#endif /* CFI_B8 */
-+}
-+
-+static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+ memcpy_fromio(to, map->virt + from, len);
-+}
-+
-+static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-+{
-+ memcpy_toio(map->virt + to, from, len);
-+}
-+
-+#define simple_map_init(map) do { } while (0)
-+#define map_is_linear(map) (1)
-+
-+#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
-
- #endif /* __LINUX_MTD_MAP_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/mtd.h linux/include/linux/mtd/mtd.h
---- linux-mips-2.4.27/include/linux/mtd/mtd.h 2003-08-13 19:19:29.000000000 +0200
-+++ linux/include/linux/mtd/mtd.h 2004-11-19 10:25:12.055176080 +0100
-@@ -1,5 +1,10 @@
--
--/* $Id$ */
-+/*
-+ * $Id$
-+ *
-+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
-+ *
-+ * Released under GPL
-+ */
-
- #ifndef __MTD_MTD_H__
- #define __MTD_MTD_H__
-@@ -9,7 +14,6 @@
- #include <linux/config.h>
- #include <linux/version.h>
- #include <linux/types.h>
--#include <linux/mtd/compatmac.h>
- #include <linux/module.h>
- #include <linux/uio.h>
-
-@@ -26,7 +30,6 @@
- unsigned char *ptr;
- };
-
--
- #define MTD_CHAR_MAJOR 90
- #define MTD_BLOCK_MAJOR 31
- #define MAX_MTD_DEVICES 16
-@@ -93,18 +96,23 @@
- #define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
- #define MEMGETREGIONCOUNT _IOR('M', 7, int)
- #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
--#define MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf)
--#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf)
-+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
-+
-+struct nand_oobinfo {
-+ int useecc;
-+ int eccpos[6];
-+};
-+
-
- #ifndef __KERNEL__
-
- typedef struct mtd_info_user mtd_info_t;
- typedef struct erase_info_user erase_info_t;
- typedef struct region_info_user region_info_t;
-+typedef struct nand_oobinfo nand_oobinfo_t;
-
- /* User-space ioctl definitions */
-
--
- #else /* __KERNEL__ */
-
-
-@@ -150,10 +158,14 @@
- u_int32_t ecctype;
- u_int32_t eccsize;
-
-+
- // Kernel-only stuff starts here.
- char *name;
- int index;
-
-+ // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO)
-+ struct nand_oobinfo oobinfo;
-+
- /* Data for variable erase regions. If numeraseregions is zero,
- * it means that the whole device has erasesize as given above.
- */
-@@ -163,7 +175,6 @@
- /* This really shouldn't be here. It can go away in 2.5 */
- u_int32_t bank_size;
-
-- struct module *module;
- int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-
- /* This stuff for eXecute-In-Place */
-@@ -176,8 +187,8 @@
- 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 oobsel);
-- int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-+ int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-+ int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-
- int (*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);
-@@ -201,10 +212,10 @@
- */
- int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
- int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from,
-- size_t *retlen, u_char *eccbuf, int oobsel);
-+ size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
- int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
- int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to,
-- size_t *retlen, u_char *eccbuf, int oobsel);
-+ size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
-
- /* Sync */
- void (*sync) (struct mtd_info *mtd);
-@@ -218,6 +229,9 @@
- void (*resume) (struct mtd_info *mtd);
-
- void *priv;
-+
-+ struct module *owner;
-+ int usecount;
- };
-
-
-@@ -226,31 +240,15 @@
- extern int add_mtd_device(struct mtd_info *mtd);
- extern int del_mtd_device (struct mtd_info *mtd);
-
--extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num);
--
--static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
--{
-- struct mtd_info *ret;
-+extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
-
-- ret = __get_mtd_device(mtd, num);
--
-- if (ret && ret->module && !try_inc_mod_count(ret->module))
-- return NULL;
--
-- return ret;
--}
--
--static inline void put_mtd_device(struct mtd_info *mtd)
--{
-- if (mtd->module)
-- __MOD_DEC_USE_COUNT(mtd->module);
--}
-+extern void put_mtd_device(struct mtd_info *mtd);
-
-
- struct mtd_notifier {
- void (*add)(struct mtd_info *mtd);
- void (*remove)(struct mtd_info *mtd);
-- struct mtd_notifier *next;
-+ struct list_head list;
- };
-
-
-@@ -263,7 +261,6 @@
- int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
- unsigned long count, loff_t from, size_t *retlen);
-
--#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)
-@@ -276,7 +273,6 @@
- #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 */
-
- /*
- * Debugging macro and defines
-@@ -293,7 +289,8 @@
- printk(KERN_INFO args); \
- } while(0)
- #else /* CONFIG_MTD_DEBUG */
--#define DEBUG(n, args...)
-+#define DEBUG(n, args...) do { } while(0)
-+
- #endif /* CONFIG_MTD_DEBUG */
-
- #endif /* __KERNEL__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/nand.h linux/include/linux/mtd/nand.h
---- linux-mips-2.4.27/include/linux/mtd/nand.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/nand.h 2004-11-19 10:25:12.057175776 +0100
-@@ -2,10 +2,10 @@
- * linux/include/linux/mtd/nand.h
- *
- * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
-- * Steven J. Hill <sjhill@cotw.com>
-+ * Steven J. Hill <sjhill@realitydiluted.com>
- * Thomas Gleixner <tglx@linutronix.de>
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -49,12 +49,14 @@
- #define __LINUX_MTD_NAND_H
-
- #include <linux/config.h>
--#include <linux/sched.h>
-+#include <linux/wait.h>
-+#include <linux/spinlock.h>
-
-+struct mtd_info;
- /*
- * Searches for a NAND device
- */
--extern int nand_scan (struct mtd_info *mtd);
-+extern int nand_scan (struct mtd_info *mtd, int max_chips);
-
- /*
- * Constants for hardware specific CLE/ALE/NCE function
-@@ -65,6 +67,8 @@
- #define NAND_CTL_CLRCLE 4
- #define NAND_CTL_SETALE 5
- #define NAND_CTL_CLRALE 6
-+#define NAND_CTL_SETWP 7
-+#define NAND_CTL_CLRWP 8
-
- /*
- * Standard NAND flash commands
-@@ -160,24 +164,33 @@
- struct nand_chip {
- unsigned long IO_ADDR_R;
- unsigned long IO_ADDR_W;
-- void (*hwcontrol)(int cmd);
-- int (*dev_ready)(void);
-+
-+ u_char (*read_byte)(struct mtd_info *mtd);
-+ void (*write_byte)(struct mtd_info *mtd, u_char byte);
-+
-+ void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
-+ void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
-+ int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
-+ void (*select_chip)(struct mtd_info *mtd, int chip);
-+ int (*block_bad)(struct mtd_info *mtd, unsigned long pos);
-+ void (*hwcontrol)(struct mtd_info *mtd, int cmd);
-+ int (*dev_ready)(struct mtd_info *mtd);
- void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
- int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
-- void (*calculate_ecc)(const u_char *dat, u_char *ecc_code);
-- int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-- void (*enable_hwecc)(int mode);
-+ void (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
-+ int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+ void (*enable_hwecc)(struct mtd_info *mtd, int mode);
- int eccmode;
- int eccsize;
- int chip_delay;
-+ int chipshift;
- spinlock_t chip_lock;
- wait_queue_head_t wq;
- nand_state_t state;
- int page_shift;
- u_char *data_buf;
- u_char *data_poi;
-- u_char *data_cache;
-- int cache_page;
-+ void *priv;
- };
-
- /*
-@@ -241,34 +254,4 @@
- */
- #define NAND_BADBLOCK_POS 5
-
--#define NAND_NONE_OOB 0
--#define NAND_JFFS2_OOB 1
--#define NAND_YAFFS_OOB 2
--
--#define NAND_NOOB_ECCPOS0 0
--#define NAND_NOOB_ECCPOS1 1
--#define NAND_NOOB_ECCPOS2 2
--#define NAND_NOOB_ECCPOS3 3
--#define NAND_NOOB_ECCPOS4 6
--#define NAND_NOOB_ECCPOS5 7
--
--#define NAND_JFFS2_OOB_ECCPOS0 0
--#define NAND_JFFS2_OOB_ECCPOS1 1
--#define NAND_JFFS2_OOB_ECCPOS2 2
--#define NAND_JFFS2_OOB_ECCPOS3 3
--#define NAND_JFFS2_OOB_ECCPOS4 6
--#define NAND_JFFS2_OOB_ECCPOS5 7
--
--#define NAND_YAFFS_OOB_ECCPOS0 8
--#define NAND_YAFFS_OOB_ECCPOS1 9
--#define NAND_YAFFS_OOB_ECCPOS2 10
--#define NAND_YAFFS_OOB_ECCPOS3 13
--#define NAND_YAFFS_OOB_ECCPOS4 14
--#define NAND_YAFFS_OOB_ECCPOS5 15
--
--#define NAND_JFFS2_OOB8_FSDAPOS 6
--#define NAND_JFFS2_OOB16_FSDAPOS 8
--#define NAND_JFFS2_OOB8_FSDALEN 2
--#define NAND_JFFS2_OOB16_FSDALEN 8
--
- #endif /* __LINUX_MTD_NAND_H */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/nand_ecc.h linux/include/linux/mtd/nand_ecc.h
---- linux-mips-2.4.27/include/linux/mtd/nand_ecc.h 2001-08-22 05:25:12.000000000 +0200
-+++ linux/include/linux/mtd/nand_ecc.h 2004-11-19 10:25:12.058175624 +0100
-@@ -1,9 +1,9 @@
- /*
- * drivers/mtd/nand_ecc.h
- *
-- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *
-- * $Id$
-+ * $Id$
- *
- * 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
-@@ -12,17 +12,19 @@
- * This file is the header for the ECC algorithm.
- */
-
--/*
-- * Creates non-inverted ECC code from line parity
-- */
--void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code);
-+#ifndef __MTD_NAND_ECC_H__
-+#define __MTD_NAND_ECC_H__
-+
-+struct mtd_info;
-
- /*
- * Calculate 3 byte ECC code for 256 byte block
- */
--void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
-+void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
-
- /*
- * Detect and correct a 1 bit error for 256 byte block
- */
--int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+
-+#endif /* __MTD_NAND_ECC_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/nftl.h linux/include/linux/mtd/nftl.h
---- linux-mips-2.4.27/include/linux/mtd/nftl.h 2003-02-26 01:53:51.000000000 +0100
-+++ linux/include/linux/mtd/nftl.h 2004-11-19 10:25:12.060175320 +0100
-@@ -1,15 +1,14 @@
--
--/* Defines for NAND Flash Translation Layer */
--/* (c) 1999 Machine Vision Holdings, Inc. */
--/* Author: David Woodhouse <dwmw2@mvhi.com> */
--/* $Id$ */
-+/*
-+ * $Id$
-+ *
-+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
-+ */
-
- #ifndef __MTD_NFTL_H__
- #define __MTD_NFTL_H__
-
--#ifndef __BOOT__
- #include <linux/mtd/mtd.h>
--#endif
-+#include <linux/mtd/blktrans.h>
-
- /* Block Control Information */
-
-@@ -84,8 +83,7 @@
- #define BLOCK_RESERVED 0xfffc /* bios block or bad block */
-
- struct NFTLrecord {
-- struct mtd_info *mtd;
-- struct semaphore mutex;
-+ struct mtd_blktrans_dev mbd;
- __u16 MediaUnit, SpareMediaUnit;
- __u32 EraseSize;
- struct NFTLMediaHeader MediaHdr;
-@@ -97,7 +95,6 @@
- __u16 lastEUN; /* should be suppressed */
- __u16 numfreeEUNs;
- __u16 LastFreeEUN; /* To speed up finding a free EUN */
-- __u32 nr_sects;
- int head,sect,cyl;
- __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */
- __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */
-@@ -114,7 +111,7 @@
- #endif
-
- #define MAX_NFTLS 16
--#define MAX_SECTORS_PER_UNIT 32
-+#define MAX_SECTORS_PER_UNIT 64
- #define NFTL_PARTN_BITS 4
-
- #endif /* __KERNEL__ */
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/partitions.h linux/include/linux/mtd/partitions.h
---- linux-mips-2.4.27/include/linux/mtd/partitions.h 2002-06-27 00:36:47.000000000 +0200
-+++ linux/include/linux/mtd/partitions.h 2004-11-19 10:25:12.061175168 +0100
-@@ -5,7 +5,7 @@
- *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- */
-
- #ifndef MTD_PARTITIONS_H
-@@ -41,6 +41,7 @@
- u_int32_t size; /* partition size */
- u_int32_t offset; /* offset within the master MTD space */
- u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
-+ struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/
- struct mtd_info **mtdp; /* pointer to store the MTD object */
- };
-
-@@ -49,8 +50,27 @@
- #define MTDPART_SIZ_FULL (0)
-
-
--int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
-+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
- int del_mtd_partitions(struct mtd_info *);
-
-+/*
-+ * Functions dealing with the various ways of partitioning the space
-+ */
-+
-+struct mtd_part_parser {
-+ struct list_head list;
-+ struct module *owner;
-+ const char *name;
-+ int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long);
-+};
-+
-+extern struct mtd_part_parser *get_partition_parser(const char *name);
-+extern int register_mtd_parser(struct mtd_part_parser *parser);
-+extern int deregister_mtd_parser(struct mtd_part_parser *parser);
-+extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
-+ struct mtd_partition **pparts, unsigned long origin);
-+
-+#define put_partition_parser(p) do { module_put((p)->owner); } while(0)
-+
- #endif
-
-diff -Nurb linux-mips-2.4.27/include/linux/mtd/physmap.h linux/include/linux/mtd/physmap.h
---- linux-mips-2.4.27/include/linux/mtd/physmap.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/mtd/physmap.h 2004-11-19 10:25:12.062175016 +0100
-@@ -0,0 +1,59 @@
-+/*
-+ * For boards with physically mapped flash and using
-+ * drivers/mtd/maps/physmap.c mapping driver.
-+ *
-+ * Copyright (C) 2003 MontaVista Software Inc.
-+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ */
-+
-+#ifndef __LINUX_MTD_PHYSMAP__
-+
-+#include <linux/config.h>
-+
-+#if defined(CONFIG_MTD_PHYSMAP)
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+/*
-+ * The map_info for physmap. Board can override size, buswidth, phys,
-+ * (*set_vpp)(), etc in their initial setup routine.
-+ */
-+extern struct map_info physmap_map;
-+
-+/*
-+ * Board needs to specify the exact mapping during their setup time.
-+ */
-+static inline void physmap_configure(unsigned long addr, unsigned long size, int buswidth, void (*set_vpp)(struct map_info *, int) )
-+{
-+ physmap_map.phys = addr;
-+ physmap_map.size = size;
-+ physmap_map.buswidth = buswidth;
-+ physmap_map.set_vpp = set_vpp;
-+}
-+
-+#if defined(CONFIG_MTD_PARTITIONS)
-+
-+/*
-+ * Machines that wish to do flash partition may want to call this function in
-+ * their setup routine.
-+ *
-+ * physmap_set_partitions(mypartitions, num_parts);
-+ *
-+ * Note that one can always override this hard-coded partition with
-+ * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS).
-+ */
-+void physmap_set_partitions(struct mtd_partition *parts, int num_parts);
-+
-+#endif /* defined(CONFIG_MTD_PARTITIONS) */
-+#endif /* defined(CONFIG_MTD) */
-+
-+#endif /* __LINUX_MTD_PHYSMAP__ */
-+
-diff -Nurb linux-mips-2.4.27/include/linux/rbtree-24.h linux/include/linux/rbtree-24.h
---- linux-mips-2.4.27/include/linux/rbtree-24.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/rbtree-24.h 2004-11-19 10:25:12.143162704 +0100
-@@ -0,0 +1,133 @@
-+/*
-+ Red Black Trees
-+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+ linux/include/linux/rbtree.h
-+
-+ To use rbtrees you'll have to implement your own insert and search cores.
-+ This will avoid us to use callbacks and to drop drammatically performances.
-+ I know it's not the cleaner way, but in C (not in C++) to get
-+ performances and genericity...
-+
-+ Some example of insert and search follows here. The search is a plain
-+ normal search over an ordered tree. The insert instead must be implemented
-+ int two steps: as first thing the code must insert the element in
-+ order as a red leaf in the tree, then the support library function
-+ rb_insert_color() must be called. Such function will do the
-+ not trivial work to rebalance the rbtree if necessary.
-+
-+-----------------------------------------------------------------------
-+static inline struct page * rb_search_page_cache(struct inode * inode,
-+ unsigned long offset)
-+{
-+ rb_node_t * n = inode->i_rb_page_cache.rb_node;
-+ struct page * page;
-+
-+ while (n)
-+ {
-+ page = rb_entry(n, struct page, rb_page_cache);
-+
-+ if (offset < page->offset)
-+ n = n->rb_left;
-+ else if (offset > page->offset)
-+ n = n->rb_right;
-+ else
-+ return page;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct page * __rb_insert_page_cache(struct inode * inode,
-+ unsigned long offset,
-+ rb_node_t * node)
-+{
-+ rb_node_t ** p = &inode->i_rb_page_cache.rb_node;
-+ rb_node_t * parent = NULL;
-+ struct page * page;
-+
-+ while (*p)
-+ {
-+ parent = *p;
-+ page = rb_entry(parent, struct page, rb_page_cache);
-+
-+ if (offset < page->offset)
-+ p = &(*p)->rb_left;
-+ else if (offset > page->offset)
-+ p = &(*p)->rb_right;
-+ else
-+ return page;
-+ }
-+
-+ rb_link_node(node, parent, p);
-+
-+ return NULL;
-+}
-+
-+static inline struct page * rb_insert_page_cache(struct inode * inode,
-+ unsigned long offset,
-+ rb_node_t * node)
-+{
-+ struct page * ret;
-+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
-+ goto out;
-+ rb_insert_color(node, &inode->i_rb_page_cache);
-+ out:
-+ return ret;
-+}
-+-----------------------------------------------------------------------
-+*/
-+
-+#ifndef _LINUX_RBTREE_H
-+#define _LINUX_RBTREE_H
-+
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+
-+typedef struct rb_node_s
-+{
-+ struct rb_node_s * rb_parent;
-+ int rb_color;
-+#define RB_RED 0
-+#define RB_BLACK 1
-+ struct rb_node_s * rb_right;
-+ struct rb_node_s * rb_left;
-+}
-+rb_node_t;
-+
-+typedef struct rb_root_s
-+{
-+ struct rb_node_s * rb_node;
-+}
-+rb_root_t;
-+
-+#define RB_ROOT (rb_root_t) { NULL, }
-+#define rb_entry(ptr, type, member) \
-+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-+
-+extern void rb_insert_color(rb_node_t *, rb_root_t *);
-+extern void rb_erase(rb_node_t *, rb_root_t *);
-+
-+static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link)
-+{
-+ node->rb_parent = parent;
-+ node->rb_color = RB_RED;
-+ node->rb_left = node->rb_right = NULL;
-+
-+ *rb_link = node;
-+}
-+
-+#endif /* _LINUX_RBTREE_H */
-diff -Nurb linux-mips-2.4.27/include/linux/rbtree.h linux/include/linux/rbtree.h
---- linux-mips-2.4.27/include/linux/rbtree.h 2001-10-19 03:25:03.000000000 +0200
-+++ linux/include/linux/rbtree.h 2004-11-19 10:25:12.148161944 +0100
-@@ -1,133 +1,25 @@
- /*
-- Red Black Trees
-- (C) 1999 Andrea Arcangeli <andrea@suse.de>
-+ * 2.5 compatibility
-+ * $Id$
-+ */
-+
-+#ifndef __MTD_COMPAT_RBTREE_H__
-+#define __MTD_COMPAT_RBTREE_H__
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
-+#include_next <linux/rbtree.h>
-+#else
-+#define rb_node_s rb_node
-+#define rb_root_s rb_root
-+
-+#include <linux/rbtree-24.h>
-+
-+/* Find logical next and previous nodes in a tree */
-+extern struct rb_node *rb_next(struct rb_node *);
-+extern struct rb_node *rb_prev(struct rb_node *);
-+extern struct rb_node *rb_first(struct rb_root *);
-+#endif
-
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--
-- linux/include/linux/rbtree.h
--
-- To use rbtrees you'll have to implement your own insert and search cores.
-- This will avoid us to use callbacks and to drop drammatically performances.
-- I know it's not the cleaner way, but in C (not in C++) to get
-- performances and genericity...
--
-- Some example of insert and search follows here. The search is a plain
-- normal search over an ordered tree. The insert instead must be implemented
-- int two steps: as first thing the code must insert the element in
-- order as a red leaf in the tree, then the support library function
-- rb_insert_color() must be called. Such function will do the
-- not trivial work to rebalance the rbtree if necessary.
--
-------------------------------------------------------------------------
--static inline struct page * rb_search_page_cache(struct inode * inode,
-- unsigned long offset)
--{
-- rb_node_t * n = inode->i_rb_page_cache.rb_node;
-- struct page * page;
--
-- while (n)
-- {
-- page = rb_entry(n, struct page, rb_page_cache);
--
-- if (offset < page->offset)
-- n = n->rb_left;
-- else if (offset > page->offset)
-- n = n->rb_right;
-- else
-- return page;
-- }
-- return NULL;
--}
--
--static inline struct page * __rb_insert_page_cache(struct inode * inode,
-- unsigned long offset,
-- rb_node_t * node)
--{
-- rb_node_t ** p = &inode->i_rb_page_cache.rb_node;
-- rb_node_t * parent = NULL;
-- struct page * page;
--
-- while (*p)
-- {
-- parent = *p;
-- page = rb_entry(parent, struct page, rb_page_cache);
--
-- if (offset < page->offset)
-- p = &(*p)->rb_left;
-- else if (offset > page->offset)
-- p = &(*p)->rb_right;
-- else
-- return page;
-- }
--
-- rb_link_node(node, parent, p);
--
-- return NULL;
--}
--
--static inline struct page * rb_insert_page_cache(struct inode * inode,
-- unsigned long offset,
-- rb_node_t * node)
--{
-- struct page * ret;
-- if ((ret = __rb_insert_page_cache(inode, offset, node)))
-- goto out;
-- rb_insert_color(node, &inode->i_rb_page_cache);
-- out:
-- return ret;
--}
-------------------------------------------------------------------------
--*/
--
--#ifndef _LINUX_RBTREE_H
--#define _LINUX_RBTREE_H
--
--#include <linux/kernel.h>
--#include <linux/stddef.h>
--
--typedef struct rb_node_s
--{
-- struct rb_node_s * rb_parent;
-- int rb_color;
--#define RB_RED 0
--#define RB_BLACK 1
-- struct rb_node_s * rb_right;
-- struct rb_node_s * rb_left;
--}
--rb_node_t;
--
--typedef struct rb_root_s
--{
-- struct rb_node_s * rb_node;
--}
--rb_root_t;
--
--#define RB_ROOT (rb_root_t) { NULL, }
--#define rb_entry(ptr, type, member) \
-- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
--
--extern void rb_insert_color(rb_node_t *, rb_root_t *);
--extern void rb_erase(rb_node_t *, rb_root_t *);
--
--static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link)
--{
-- node->rb_parent = parent;
-- node->rb_color = RB_RED;
-- node->rb_left = node->rb_right = NULL;
--
-- *rb_link = node;
--}
--
--#endif /* _LINUX_RBTREE_H */
-+#endif /* __MTD_COMPAT_RBTREE_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/suspend.h linux/include/linux/suspend.h
---- linux-mips-2.4.27/include/linux/suspend.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/suspend.h 2004-11-19 10:25:12.150161640 +0100
-@@ -0,0 +1,10 @@
-+/* $Id$ */
-+
-+#ifndef __MTD_COMPAT_VERSION_H__
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-+#include_next <linux/suspend.h>
-+#endif
-+
-+#endif /* __MTD_COMPAT_VERSION_H__ */
-diff -Nurb linux-mips-2.4.27/include/linux/workqueue.h linux/include/linux/workqueue.h
---- linux-mips-2.4.27/include/linux/workqueue.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/workqueue.h 2004-11-19 10:25:12.152161336 +0100
-@@ -0,0 +1,21 @@
-+/*
-+ * 2.5 compatibility
-+ * $Id$
-+ */
-+
-+#ifndef __MTD_COMPAT_WORKQUEUE_H__
-+#define __MTD_COMPAT_WORKQUEUE_H__
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40)
-+#include_next <linux/workqueue.h>
-+#else
-+#include <linux/tqueue.h>
-+#define work_struct tq_struct
-+#define schedule_work(x) schedule_task(x)
-+#define flush_scheduled_work flush_scheduled_tasks
-+#define INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
-+#endif
-+
-+#endif /* __MTD_COMPAT_WORKQUEUE_H__ */